We’re happy to announce the release of GroupDocs.Parser for Python v26.10, available as of November 2026. This release upgrades the underlying engine to version 26.8 and moves from .NET Core 3.1 to .NET 10.0.14, fixing two denial-of-service vulnerabilities in System.Security.Cryptography.Pkcs. It introduces major new features including annotation extraction, HTML table parsing, OCR for Arabic and Korean, a Python logger, external-resource handling, preview callbacks as plain functions, and a groupdocs-parser command-line tool. The wheel is now a pure-Python package targeting Python 3.5 – 3.14, with updated platform tags (manylinux_2_27_x86_64, macosx_13_0_*) and removal of the 32-bit Windows wheel.
What’s new in this release
- [Feature] Add support for extracting annotations with
get_annotations()andTextOptions.include_annotations(PARSERPYTHONNET-23) - [Feature] Add the
groupdocs-parsercommand-line tool (PARSERPYTHONNET-24) - [Feature] Add support for a Python logger object implementing
ILogger(PARSERPYTHONNET-25) - [Feature] Add support for handling the loading of external resources from Python (PARSERPYTHONNET-26)
- [Feature] Add OCR for Arabic and Korean text (PARSERPYTHONNET-27)
- [Feature] Add support for extracting tables from HTML documents (PARSERPYTHONNET-28)
- [Feature] Add support for applying the license from the
GROUPDOCS_LIC_PATHenvironment variable (PARSERPYTHONNET-36) - [Enhancement] Update GroupDocs.Parser to 26.8 and the embedded runtime to .NET 10.0.14 (PARSERPYTHONNET-29)
- [Enhancement] Ship a pure-Python package for Python 3.5 – 3.14 in place of the compiled extension (PARSERPYTHONNET-30)
- [Enhancement] Pass preview callbacks to
PreviewOptionsas plain Python functions (PARSERPYTHONNET-31) - [Enhancement] Reject assignments to unknown attributes of API objects (PARSERPYTHONNET-32)
- [Enhancement] Update the platform tags to glibc 2.27 and macOS 13, and remove the 32-bit Windows wheel (PARSERPYTHONNET-33)
- [Enhancement] Raise
GroupDocsParserExceptionand its subclasses instead ofRuntimeError(PARSERPYTHONNET-34) - [Enhancement] Update
System.Security.Cryptography.Pkcsto 10.0.14, which fixes two denial-of-service vulnerabilities (PARSERPYTHONNET-37) - [Fix] Some Word and RTF documents fail with
The document appears to be corruptedor a missingSkiaSharp3.119 assembly (PARSERPYTHONNET-35) - [Fix] Memory grows with each document opened from a
BytesIO(PARSERPYTHONNET-38)
Public API changes
- Engine errors raise
GroupDocsParserException,InvalidPasswordException,CorruptedDocumentExceptionorUnsupportedDocumentFormatExceptionfromgroupdocs.parser.exceptions, where 25.12 raisedRuntimeErrorfor all of them. The classes existed in 25.12, but they did not derive fromExceptionand were never raised.except Exceptioncatches 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.
Removed
groupdocs.parser.options.ICreatePageStreamgroupdocs.parser.options.IReleasePageStreamgroupdocs.parser.options.IPreviewPageRender
Pass functions to PreviewOptions and PreviewOptions.preview_page_render instead.
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()andtable[row, column].DocumentData,Template:get().TemplateCollection:append().Resources:storage_path, writable.
New 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 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. There is no 32-bit Windows wheel any more. Installing requires pip 20.3 or newer.
Code example
Extract annotations from a Word document and include them in the extracted text:
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))
How to get the update
PyPI
Install or upgrade using PyPI:
groupdocs-parser-net 26.10.0 on PyPI
pip install groupdocs-parser-net==26.10.0
Direct download
Download platform-specific wheels from the GroupDocs.Parser for Python via .NET 26.10 release page: