GroupDocs.Assembly for Python via .NET 26.11 Release Notes
This release upgrades the GroupDocs.Assembly engine from 24.12 to 26.7, and the embedded .NET runtime from .NET Core 3.1 to .NET 10.0.14. It is the first release with wheels for Linux and macOS, and one wheel per platform now serves Python 3.5 – 3.14. A Python dict or list is a data source as it is, assemble_document() takes one DataSourceInfo without a list, a document’s tables take a Python load handler, Python types stand where the API takes a .NET Type, and the license can come from the GROUPDOCS_LIC_PATH environment variable. Every component the CVE scan of 25.5.1 flagged is updated.
Breaking change: BarcodeSettings.x_resolution and y_resolution are xresolution and yresolution, and DocumentAssembler.set_use_reflection_optimization(False) is the class attribute DocumentAssembler.use_reflection_optimization = False. Engine errors that 25.5 raised as RuntimeError("Proxy error(...)") now raise FileNotFoundError for a missing file, RuntimeError for a template error, LicenseError for a license that cannot be applied and GroupDocsAssemblyException for the others; the last two do not derive from RuntimeError, so except RuntimeError no longer catches them. The 32-bit Windows wheel is dropped. See API Changes for the full list.
Full List of Changes in This Release
| Key | Category | Summary |
|---|---|---|
| ASSEMBLYPYTHON‑26 | Feature | Add wheels for Linux x64 and macOS (Intel and Apple Silicon) |
| ASSEMBLYPYTHON‑27 | Feature | Add support for a Python dict or list as a data source |
| ASSEMBLYPYTHON‑28 | Feature | Add support for a Python handler of document table loading (IDocumentTableLoadHandler) |
| ASSEMBLYPYTHON‑29 | Feature | Add support for Python types where the API takes a .NET Type (DocumentTableColumn.type, known_types) |
| ASSEMBLYPYTHON‑30 | Feature | Add support for applying the license from the GROUPDOCS_LIC_PATH environment variable |
| ASSEMBLYPYTHON‑31 | Enhancement | Update GroupDocs.Assembly to 26.7 and the embedded runtime to .NET 10.0.14 |
| ASSEMBLYPYTHON‑32 | Enhancement | Ship a pure-Python package for Python 3.5 – 3.14 in place of the compiled extension |
| ASSEMBLYPYTHON‑33 | Enhancement | Accept one DataSourceInfo in assemble_document() as well as a list |
| ASSEMBLYPYTHON‑34 | Enhancement | Raise FileNotFoundError for a missing file, LicenseError for a license that cannot be applied, and GroupDocsAssemblyException for other engine errors |
| ASSEMBLYPYTHON‑35 | Enhancement | Rename BarcodeSettings.x_resolution/y_resolution to xresolution/yresolution, and make use_reflection_optimization a class attribute |
| ASSEMBLYPYTHON‑36 | Enhancement | Remove the 32-bit Windows wheel |
| ASSEMBLYPYTHON‑11 | Fix | Fix CVE findings in 25.5.1: zlib 1.2.11 → 1.2.12 (+4 more) |
Major Features
Linux and macOS
26.11 has wheels for Linux x64 (manylinux_2_27_x86_64, glibc 2.27 or newer) and for macOS 12 or newer on Intel (macosx_12_0_x86_64) and Apple Silicon (macosx_12_0_arm64), beside Windows x64. 25.5 had Windows wheels only. pip 20.3 or newer picks the wheel for the platform. On Linux the .NET runtime needs ICU, and presentation templates need libgdiplus (see Requirements).
pip install groupdocs-assembly-net==26.11.0
Python data as a data source
DataSourceInfo takes a dict, a list of dicts or a list of values as it is; 25.5 raised TypeError for a dict. The wrapper turns the data into .NET objects typed from its shape, so numbers, strings, bool, datetime, date and Decimal values reach the template typed: <<[o.OrderDate.Month]>> and <<if [c.Vip]>> work as they do on .NET objects. Dicts in one list share one type with the union of their keys.
from groupdocs.assembly import DataSourceInfo, DocumentAssembler
orders = [
{"Number": 10001, "Product": "Harbor Blend whole bean coffee", "Quantity": 30, "Price": 552.0},
{"Number": 10004, "Product": "Aged harbour cheddar", "Quantity": 8, "Price": 132.0},
]
# order-table.docx: a table whose row <<foreach [o in orders]>><<[o.Number]>> ... <</foreach>> repeats per order
DocumentAssembler().assemble_document("order-table.docx", "order-table-report.docx", [
DataSourceInfo("Quayside Bistro", "customer"),
DataSourceInfo(orders, "orders"),
])
One data source without a list
assemble_document() takes one DataSourceInfo or a list of them, as .NET’s params DataSourceInfo[] does. 25.5 required a list and raised TypeError: can't build Array value from 'groupdocs.assembly.DataSourceInfo' for one.
from groupdocs.assembly import DataSourceInfo, DocumentAssembler
customer = {"Name": "Quayside Bistro", "Product": "Harbor Blend whole bean coffee"}
DocumentAssembler().assemble_document("hello-world.docx", "hello-world-report.docx", DataSourceInfo(customer, "customer"))
Table-load handlers
DocumentTableSet(path, load_handler) takes a Python function (args), or an object with a handle(args) method, and calls it for each table of the document before it loads. The handler sets that table’s args.options, or skips the table with args.is_loaded = False; args.table_index says which table it is. 25.5 raised TypeError for a Python function.
from groupdocs.assembly.data import DocumentTableOptions, DocumentTableSet
def on_table(args):
options = DocumentTableOptions()
options.first_row_contains_column_names = True
args.options = options
tables = DocumentTableSet("contracts.xlsx", on_table)
for table in tables.tables:
print(table.name, [column.name for column in table.columns])
Python types where the API takes a .NET type
A Python type stands for the .NET type a member takes: float for System.Double, int, str, bool, datetime. A column of a document table can be made numeric so a chart sums it, and known_types lets a template call a type’s static members; it also takes a .NET type name. 25.5 raised TypeError: can't build Type value from 'type'.
from groupdocs.assembly import DataSourceInfo, DocumentAssembler
from groupdocs.assembly.data import DocumentTable, DocumentTableOptions
options = DocumentTableOptions()
options.first_row_contains_column_names = True
contracts = DocumentTable("contracts.xlsx", 0, options)
contracts.columns["Price"].type = float
assembler = DocumentAssembler()
assembler.known_types.add("System.Math") # templates can call <<[Math.Round(x, 1)]>>
assembler.assemble_document("table-row.docx", "table-row-report.docx", DataSourceInfo(contracts, "contracts"))
License from the environment
Set GROUPDOCS_LIC_PATH to the path of a license file, or to a URL that serves one, and the license is applied at the first engine call, with no license code; 25.5 did not read the variable. If that license cannot be applied (a missing file, an expired subscription, a license for another product), every engine call raises LicenseError, naming the variable and the engine’s reason, until License().set_license() applies a license. Set GROUPDOCS_LIC_STRICT=0 to get one LicenseWarning and evaluation mode instead.
from groupdocs.assembly import DataSourceInfo, DocumentAssembler, LicenseError
customer = {"Name": "Quayside Bistro", "Product": "Harbor Blend whole bean coffee"}
try:
DocumentAssembler().assemble_document("hello-world.docx", "hello-world-report.docx", DataSourceInfo(customer, "customer"))
except LicenseError as e:
print(e) # GROUPDOCS_LIC_PATH=... could not be applied: <reason>
Errors by kind
25.5 raised a bare RuntimeError("Proxy error(<.NET exception>): ...") for every engine error. 26.11 raises FileNotFoundError for a missing template or data file, which still derives from RuntimeError; RuntimeError with the engine’s message alone for a template error or a member the data lacks; LicenseError for a license that cannot be applied; and GroupDocsAssemblyException for the other engine errors. LicenseError and GroupDocsAssemblyException are importable from groupdocs.assembly and do not derive from RuntimeError.
from groupdocs.assembly import DataSourceInfo, DocumentAssembler, GroupDocsAssemblyException
try:
DocumentAssembler().assemble_document("no-such-template.docx", "report.docx", DataSourceInfo({"Name": "A"}, "customer"))
except FileNotFoundError as e:
print("missing:", e)
except (RuntimeError, GroupDocsAssemblyException) as e:
print("engine:", e)
One wheel for Python 3.5 – 3.14
25.5 was a compiled extension, with one binary module per Python version (cp35 to cp313) and a .NET Core 3.1 runtime, and it declared python_requires=">=3.5,<3.14". 26.11 is one py3-none-<platform> wheel per platform, plain Python over an embedded .NET 10 runtime, for Python 3.5 – 3.14. It ships .pyi stubs and an AGENTS.md that IDEs and AI coding assistants read. Code written for 25.5 runs unchanged apart from the two renames below: the 11 examples of the 25.5 examples repository that run without metered keys write the same reports with 26.11.
Engine 26.7
25.5.1 shipped engine 24.12. The engine releases since then add, among others:
- Custom font folders (25.6):
FontSettings.set_font_sources([FolderFontSource(folder, SearchOption.ALL_FOLDERS)])makes the engine render with the fonts of a folder, such as fonts the machine does not have installed;FontSettings.reset_font_sources()undoes it. The folder must exist, orFolderFontSourceraisesFileNotFoundError. - OOXML compliance (25.12):
LoadSaveOptions.ooxml_compliancesaves a Word report asOoxmlCompliance.ECMA,TRANSITIONALorSTRICT. Left atNone, the report keeps its template’s compliance level (measured with Ecma, Transitional and Strict templates). - Stricter barcode size (26.6): a barcode below the engine’s minimum raises
Size of barcode is too small. Please, increase the xDimension or resolution.; enlarge the barcode’sxDimensionor resolution in the template. - UTC dates from JSON (26.6): a JSON date-time ending in
Zis no longer shifted by the host’s time zone.
The engine’s own notes have the full list: GroupDocs.Assembly for .NET release notes.
from groupdocs.assembly import DataSourceInfo, DocumentAssembler, FileFormat, LoadSaveOptions, OoxmlCompliance
options = LoadSaveOptions(FileFormat.DOCX)
options.ooxml_compliance = OoxmlCompliance.STRICT
customer = {"Name": "Quayside Bistro", "Product": "Harbor Blend whole bean coffee"}
DocumentAssembler().assemble_document("hello-world.docx", "hello-world-strict.docx", options, DataSourceInfo(customer, "customer"))
API Changes
Upgraders need to rename x_resolution/y_resolution and set_use_reflection_optimization(), and catch GroupDocsAssemblyException and LicenseError where they caught RuntimeError. Everything else is additive.
New classes and members
groupdocs.assembly:FontSettings,FolderFontSource,IFontSource,SearchOption,OoxmlCompliance,GroupDocsAssemblyException,LicenseError,LicenseWarning.LoadSaveOptions:ooxml_compliance.KnownTypeSet:append().DocumentTableCollection,DocumentTableColumnCollection:get().DocumentTableRelationCollection:append(),get().
Renamed
BarcodeSettings.x_resolution→BarcodeSettings.xresolutionBarcodeSettings.y_resolution→BarcodeSettings.yresolution
The old names raise AttributeError with a “Did you mean” hint, on reading and on assignment.
Removed
DocumentAssembler.set_use_reflection_optimization(): assign the class attribute instead,DocumentAssembler.use_reflection_optimization = False.
Changed
DataSourceInfotakes a dict or a list (see Python data as a data source).assemble_document()takes oneDataSourceInfoas well as a list.DocumentTableSet(path, load_handler)takes a Python function or an object withhandle(args).DocumentTableColumn.typeandKnownTypeSet.add()take a Python type.- Engine errors raise
FileNotFoundError,RuntimeError,LicenseErrororGroupDocsAssemblyException(see Errors by kind).except Exceptioncatches the errors of both releases.
Fixed
- Fix CVE findings in 25.5.1: zlib 1.2.11 → 1.2.12 (+4 more) (ASSEMBLYPYTHON‑11). The 25.5.1 wheels bundled zlib 1.2.11 (in
libSkiaSharp), SkiaSharp 2.88.3,System.Formats.Asn18.0.0,System.Security.Cryptography.Pkcs8.0.0 and the .NET Core 3.1.32 runtime, which has had no fixes since 2022. 26.11 ships SkiaSharp 3.119.4, whose native libraries link zlib 1.3.0.1 and libpng 1.6.58, the runtime’s ownSystem.Formats.Asn1,System.Security.Cryptography.Pkcs10.0.14 and the .NET 10.0.14 runtime.
Known Issues
- On Linux, without ICU the process aborts on the first engine call with
Couldn't find a valid ICU package, and no Python exception is raised. Install ICU (apt-get install libicu-dev, any version) and do not setDOTNET_SYSTEM_GLOBALIZATION_INVARIANT. - On Linux and macOS, presentation templates (PPTX, PPT, ODP and the others) need
libgdiplus. Without it they neither load nor save:The type initializer for 'Gdip' threw an exception. Install it withapt-get install libgdiplusorbrew install mono-libgdiplus. Word processing, spreadsheet and email templates do not need it. - A QR code is drawn with a font the engine looks up by name and does not substitute: a Word document’s default font, and in a workbook the font of the text box that holds the tag. Without that font installed the call raises
Value cannot be null. (Parameter 'trueTypeFont'), on any OS. On Linux, install the font, such as the Microsoft core fonts (ttf-mscorefonts-installer) for Times New Roman and Arial, or set the template’s font to one the machine has. Code 128, EAN-13 and Codabar barcodes need no particular font. - On Linux, a presentation template saved as TIFF raises
Not implemented.; save it as PDF instead. - A process forked after its first engine call cannot use GroupDocs.Assembly in the child: every call there raises
RuntimeError(The .NET runtime cannot be used in a process forked after it started), and the parent keeps working. This coversmultiprocessingwith theforkstart method (the default on Linux before Python 3.14),gunicorn --preloadand Celery’s prefork pool. Usemultiprocessing.get_context("spawn"), start the workers before the first call, or make the first call in each worker. - The first engine call in a process takes about 20 – 25 seconds while the engine loads and applies the license; later calls take a fraction of a second.
- On Linux and macOS, pip older than 20.3 does not know the wheels’ platform tags and finds no matching distribution, and neither does any pip on Linux older than glibc 2.27 or macOS older than 12. Upgrade pip with
python -m pip install --upgrade pip. On a 32-bit Python for Windows, pip installs 25.5.1, the last release with a 32-bit wheel.
Requirements
- Python 3.5 – 3.14 (
python_requires = ">=3.5,<3.15") and pip 20.3 or newer, 64-bit - Windows x64, Linux x64 with glibc 2.27 or newer, macOS 12 or newer on Intel or Apple Silicon. On an Intel Mac, a Python built against a pre-11 macOS SDK reports the system as macOS 10.16 — use pip 24.1 or newer there, or set
SYSTEM_VERSION_COMPAT=0when running pip - Windows: no additional packages
- Linux: ICU, libgdiplus and the fonts your templates use —
apt-get install libicu-dev libgdiplus fontconfig ttf-mscorefonts-installer. ICU is required for any template; libgdiplus serves presentations; a QR code needs its font installed by name (see Known Issues). Every other report, PDF included, fills and renders with the DejaVu fonts alone - macOS:
brew install mono-libgdiplus, for presentations as on Linux - The .NET 10.0.14 runtime is embedded in the wheel; no separate install is needed
Wheel Distribution
The wheels are on PyPI, where pip 20.3 or newer picks the one for your platform, and on releases.groupdocs.com for a machine without PyPI access. Install a downloaded wheel by its file name, from which pip reads the platform:
| Platform | Download | Wheel |
|---|---|---|
| Windows x64 | Windows | groupdocs_assembly_net-26.11.0-py3-none-win_amd64.whl |
| Linux x64 | Linux | groupdocs_assembly_net-26.11.0-py3-none-manylinux_2_27_x86_64.whl |
| macOS Intel | macOS Intel | groupdocs_assembly_net-26.11.0-py3-none-macosx_12_0_x86_64.whl |
| macOS Apple Silicon | macOS Apple Silicon | groupdocs_assembly_net-26.11.0-py3-none-macosx_12_0_arm64.whl |
pip install groupdocs-assembly-net==26.11.0
Additional Resources
Feedback
Questions and issues are welcome on the GroupDocs.Assembly forum.