GroupDocs.Parser for Python via .NET 26.10 Release Notes

This release upgrades the GroupDocs.Parser engine from 25.10 to 26.8. The embedded .NET runtime moves from .NET Core 3.1 to .NET 10.0.14, and System.Security.Cryptography.Pkcs to 10.0.14, which fixes two denial-of-service vulnerabilities. New features include annotation extraction, tables from HTML documents, OCR for Arabic and Korean, a Python logger and external-resource handler, preview callbacks as plain functions, a groupdocs-parser command line, the license applied from the GROUPDOCS_LIC_PATH environment variable and support for Python 3.14. Some Word and RTF documents that 25.12 could not read now open, and a document opened from a BytesIO no longer leaks memory. One wheel per platform now serves Python 3.5 – 3.14, the platform wheels target manylinux_2_27_x86_64 and macosx_13_0_*, and the 32-bit Windows wheel is removed.

Breaking change: The ICreatePageStream, IReleasePageStream and IPreviewPageRender classes are removed: pass plain Python functions to PreviewOptions and PreviewOptions.preview_page_render instead. Engine errors that 25.12 raised as RuntimeError now raise GroupDocsParserException or one of its subclasses (InvalidPasswordException, CorruptedDocumentException, UnsupportedDocumentFormatException), which do not derive from RuntimeError, so except RuntimeError no longer catches them. Assigning an attribute that a class does not have now raises AttributeError instead of creating a Python-only attribute the engine never sees. The wheel platform tags changed to manylinux_2_27_x86_64, macosx_13_0_x86_64 and macosx_13_0_arm64, and the 32-bit Windows wheel was dropped, so installing requires pip 20.3 or newer. See API Changes for the full list.

Full List of Changes in This Release

KeyCategorySummary
PARSERPYTHONNET‑23FeatureAdd support for extracting annotations with get_annotations() and TextOptions.include_annotations
PARSERPYTHONNET‑24FeatureAdd the groupdocs-parser command-line tool
PARSERPYTHONNET‑25FeatureAdd support for a Python logger object implementing ILogger
PARSERPYTHONNET‑26FeatureAdd support for handling the loading of external resources from Python
PARSERPYTHONNET‑27FeatureAdd OCR for Arabic and Korean text
PARSERPYTHONNET‑28FeatureAdd support for extracting tables from HTML documents
PARSERPYTHONNET‑36FeatureAdd support for applying the license from the GROUPDOCS_LIC_PATH environment variable
PARSERPYTHONNET‑29EnhancementUpdate GroupDocs.Parser to 26.8 and the embedded runtime to .NET 10.0.14
PARSERPYTHONNET‑30EnhancementShip a pure-Python package for Python 3.5 – 3.14 in place of the compiled extension
PARSERPYTHONNET‑31EnhancementPass preview callbacks to PreviewOptions as plain Python functions
PARSERPYTHONNET‑32EnhancementReject assignments to unknown attributes of API objects
PARSERPYTHONNET‑33EnhancementUpdate the platform tags to glibc 2.27 and macOS 13, and remove the 32-bit Windows wheel
PARSERPYTHONNET‑34EnhancementRaise GroupDocsParserException and its subclasses instead of RuntimeError
PARSERPYTHONNET‑37EnhancementUpdate System.Security.Cryptography.Pkcs to 10.0.14, which fixes two denial-of-service vulnerabilities
PARSERPYTHONNET‑35FixSome Word and RTF documents fail with The document appears to be corrupted or a missing SkiaSharp 3.119 assembly
PARSERPYTHONNET‑38FixMemory grows with each document opened from a BytesIO

Major Features

Extract annotations

Parser.get_annotations() returns the comments and notes of a PDF, Word or PowerPoint document as AnnotationItem objects with the value, type, page index, timestamp, author name and initials; get_annotations(page_index) reads one page. TextOptions.include_annotations adds the annotation text to the extracted text, and parser.features.annotations tells whether a format supports annotations.

from groupdocs.parser import Parser
from groupdocs.parser.options import TextOptions

with Parser("reviewed.docx") as parser:
    for note in parser.get_annotations() or []:
        print(note.page_index + 1, note.annotation_type, note.author_name, note.value.strip())

    options = TextOptions()
    options.include_annotations = True
    print(parser.get_text(options))

Command line

The wheel installs the groupdocs-parser console script (also python -m groupdocs.parser) with the commands text, info, metadata, images, annotations and list-formats. text takes --page N (counted from 1), --format plain|markdown|html, --ocr, --include-annotations and -o FILE; info, metadata and annotations take --json; images takes --out DIR; every command takes --password. --license and --version come before the command. The exit code is 0 on success, 2 for a user error such as a missing file, and 1 for an engine error or a format that does not support the operation.

groupdocs-parser text report.pdf --page 2 -o page2.txt
groupdocs-parser text report.docx --format markdown
groupdocs-parser info report.pdf --json
groupdocs-parser annotations reviewed.docx --json
groupdocs-parser --license license.lic text protected.pdf --password secret

Python logger

A plain Python object with trace(message), warning(message) and error(message, exception) methods can be passed to ParserSettings as the logger, and the engine calls it with what it meets while it extracts, such as a damaged file. A healthy document may log nothing. A function log(level, message, exception) works too.

from groupdocs.parser import Parser
from groupdocs.parser.options import ParserSettings


class PrintLogger:
    def trace(self, message):
        print("TRACE:", message)

    def warning(self, message):
        print("WARNING:", message)

    def error(self, message, exception):
        print("ERROR:", message, exception)


with Parser("document.pdf", ParserSettings(PrintLogger())) as parser:
    print(parser.get_document_info().page_count)

Control the loading of external resources

The engine asks an external-resource handler before it loads each picture an HTML or MHTML document references. The handler is a function, an object with an on_loading(args) method, or a subclass of ExternalResourceHandler; setting args.skipped = True skips the resource. ParserSettings takes it as external_resource_handler.

from groupdocs.parser import Parser
from groupdocs.parser.options import ParserSettings


def skip_remote(args):
    args.skipped = args.uri.startswith("http")


with Parser("page.html", ParserSettings(external_resource_handler=skip_remote)) as parser:
    print(len(parser.get_images() or []))

OCR for Arabic and Korean

OcrOptions.language selects the alphabet OCR recognizes, English by default. Language.ARA and Language.KOR are new in this engine. The recognition models are part of the engine: the first OCR call unpacks them, about 80 MB, into an aspose_data folder in the working directory, with no download. To choose the folder, set Resources.storage_path (from groupdocs.parser import Resources) before the first OCR call.

from groupdocs.parser import Parser
from groupdocs.parser.options import Language, OcrOptions, TextOptions

ocr_options = OcrOptions()
ocr_options.language = Language.KOR
with Parser("scan.jpg") as parser:
    print(parser.get_text(TextOptions(False, True, ocr_options)))

Tables from HTML documents

get_tables() now finds the tables of HTML documents, as it does for PDF, Word and spreadsheet documents; 25.12 found none. A cell is table[row, column], or table.get(row, column).

from groupdocs.parser import Parser

with Parser("report.html") as parser:
    for table in parser.get_tables() or []:
        for row in range(table.row_count):
            print([table[row, column].text.rstrip("\x07") for column in range(table.column_count)])

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 Parser call, with no license code; 25.12 did not read the variable. If that license cannot be applied (a missing file, an expired subscription, a license for another product), every Parser 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.parser import LicenseError, Parser

try:
    with Parser("report.pdf") as parser:
        print(parser.get_text())
except LicenseError as e:
    print(e)  # GROUPDOCS_LIC_PATH=... could not be applied: <reason>

Preview callbacks as plain functions

PreviewOptions(create_page_stream, release_page_stream) takes ordinary functions, and so does PreviewOptions.preview_page_render. create_page_stream(page_number) returns a writable stream, such as a file opened with "wb" or an io.BytesIO; pages are numbered from 1. The engine closes a file it was given, and calls release_page_stream(page_number) once the page is written. In 25.12 these were the ICreatePageStream, IReleasePageStream and IPreviewPageRender classes.

from groupdocs.parser import Parser
from groupdocs.parser.options import PreviewOptions


def create_page_stream(page_number):
    return open("page-%d.png" % page_number, "wb")


def release_page_stream(page_number):
    print("page", page_number, "written")


options = PreviewOptions(create_page_stream, release_page_stream)
options.preview_page_render = lambda info: print("rendering page", info.page_number)
with Parser("document.pdf") as parser:
    parser.generate_preview(options)

Misspelled attributes raise AttributeError

Assigning a property that an API object does not have raises AttributeError with a “Did you mean” hint. 25.12 accepted the assignment, stored a Python-only attribute and left the engine setting unchanged.

from groupdocs.parser.options import TextOptions

options = TextOptions()
try:
    options.include_annotation = True
except AttributeError as error:
    print(error)

One wheel for Python 3.5 – 3.14

25.12 was a compiled extension, with one binary module per Python version and a .NET Core 3.1 runtime. 26.10 is one py3-none-<platform> wheel per platform, plain Python over an embedded .NET 10 runtime, and it declares python_requires=">=3.5,<3.15". Python 3.14 is new: 25.12 declared <3.14. Most 25.12 code runs unchanged, and all 129 Docs examples that ran on 25.12 run on 26.10. get_text() and get_formatted_text() still return a str, which now also answers read_to_end().

Updated platform tags and 64-bit Windows wheel

The Linux wheel is tagged manylinux_2_27_x86_64, the oldest glibc the embedded .NET 10 runtime starts on, and the macOS wheels macosx_13_0_x86_64 and macosx_13_0_arm64. 25.12’s manylinux1 and macosx_10_14 / macosx_11_0 tags let pip install wheels on systems where they could not start. OCR on macOS needs 13.3 or newer, which the ONNX Runtime library it uses declares. There is no 32-bit Windows wheel any more. Installing requires pip 20.3 or newer.

API Changes

Upgraders need to replace the preview callback classes with functions, catch GroupDocsParserException where they caught RuntimeError, and fix any misspelled attribute assignment, which now raises AttributeError. Everything else is additive.

New classes and members

  • groupdocs.parser: Resources.
  • groupdocs.parser.data: AnnotationItem.
  • groupdocs.parser.options: CreatePageStream, ReleasePageStream, PreviewPageRender, Language, PreviewFormats.
  • Parser: get_annotations(), get_structure(), dispose().
  • Features: annotations.
  • TextOptions: include_annotations.
  • OcrOptions: language.
  • ILogger: error().
  • TocItem: extract_text().
  • PageTableArea: get() and table[row, column].
  • DocumentData, Template: get().
  • TemplateCollection: append().
  • Resources: storage_path, writable.

Removed

  • groupdocs.parser.options.ICreatePageStream
  • groupdocs.parser.options.IReleasePageStream
  • groupdocs.parser.options.IPreviewPageRender

Pass functions to PreviewOptions and PreviewOptions.preview_page_render instead (see Preview callbacks as plain functions).

Changed

  • Engine errors raise GroupDocsParserException, InvalidPasswordException, CorruptedDocumentException or UnsupportedDocumentFormatException from groupdocs.parser.exceptions, where 25.12 raised RuntimeError for all of them. The classes existed in 25.12, but they did not derive from Exception and were never raised. except Exception catches the errors of both releases.
  • Assigning an unknown attribute raises AttributeError.
  • Lists the engine returns support len() and indexing, and an empty one is false.

Fixed

  • Some Word and RTF documents fail with The document appears to be corrupted or a missing SkiaSharp 3.119 assembly (PARSERPYTHONNET‑35). On 25.12, get_text() rejected some valid Word and RTF documents as corrupted, and get_tables() and get_images() on them raised Could not load file or assembly 'SkiaSharp, Version=3.119.0.0', because the 25.12 wheel shipped SkiaSharp 2.88 while its engine references 3.119. 26.10 ships the SkiaSharp its engine is built against, and those documents return their text, tables and images.
  • Memory grows with each document opened from a BytesIO (PARSERPYTHONNET‑38). On 25.12, each Parser(io.BytesIO(data)) kept memory after the parser closed: opening a 40 MB document 60 times grew the process from 162 MB to 627 MB, while the same loop with a file path stayed flat. In 26.10 the BytesIO loop stays at about 175 MB.

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 set DOTNET_SYSTEM_GLOBALIZATION_INVARIANT.
  • On Linux and macOS, presentations need libgdiplus. Without it, the page preview of every PowerPoint and OpenDocument presentation fails with The type initializer for 'Gdip' threw an exception, and so does every operation but get_metadata() on ODP and OTP files and on PPT, PPS and POT files that contain a table, and get_hyperlinks() on a PowerPoint file with a table or a hyperlink. Install it with apt-get install libgdiplus or brew install mono-libgdiplus.
  • On Linux, without the Liberation fonts get_structure() reports the merged cells of a Word table as separate rows. Install them with apt-get install fonts-liberation; the Microsoft core fonts are not needed.
  • OCR on macOS 13.0 – 13.2 raises GroupDocsParserException naming Microsoft.ML.OnnxRuntime.NativeMethods, because the ONNX Runtime library OCR uses needs macOS 13.3. Every other feature works on 13.0.
  • The text of a table cell from a DOCX or HTML document ends with the control character \x07. Remove it with cell.text.rstrip("\x07").
  • A process forked after its first Parser call cannot use Parser 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 covers multiprocessing with the fork start method (the default on Linux before Python 3.14), gunicorn --preload and Celery’s prefork pool. Use multiprocessing.get_context("spawn"), start the workers before the first call, or make the first call in each worker.
  • The first Parser(...) in a process takes 20 – 30 seconds while the engine loads; documents opened after that take a fraction of a second.
  • ParserSettings() raises TypeError: __init__() - no overload matched: there is no empty ParserSettings. Pass a logger, an OCR connector or an external-resource handler.
  • With pip older than 20.3, or on Linux older than glibc 2.27 or macOS older than 13, pip cannot use the 26.10 wheels: an unpinned pip install groupdocs-parser-net falls back to 25.12, and a pinned one finds no matching distribution. Upgrade pip with python -m pip install --upgrade pip.

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 13 or newer on Intel or Apple Silicon. OCR on macOS needs 13.3 or newer. 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=0 when running pip
  • Windows: no additional packages
  • Linux: ICU, fontconfig, the Liberation fonts and libgdiplus — apt-get install libicu-dev libfontconfig1 fonts-liberation libgdiplus. ICU is required for any document. The Liberation fonts keep merged table cells right in get_structure(). libgdiplus serves presentations: page previews, ODP and OTP files, and PowerPoint files with tables or hyperlinks. The Microsoft core fonts are not needed
  • 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:

PlatformDownloadWheel
Windows x64Windowsgroupdocs_parser_net-26.10.0-py3-none-win_amd64.whl
Linux x64Linuxgroupdocs_parser_net-26.10.0-py3-none-manylinux_2_27_x86_64.whl
macOS IntelmacOS Intelgroupdocs_parser_net-26.10.0-py3-none-macosx_13_0_x86_64.whl
macOS Apple SiliconmacOS Apple Silicongroupdocs_parser_net-26.10.0-py3-none-macosx_13_0_arm64.whl
pip install groupdocs-parser-net==26.10.0

Additional Resources

Feedback

Questions and issues are welcome on the GroupDocs.Parser forum.