Skip to main content

xcresult

A Python library and CLI tool for reading Xcode's .xcresult bundles. It uses xcresulttool's modern JSON reports and generated Python dataclasses to inspect build issues, extract test results, export attachments, and generate JUnit XML. Neither generation nor runtime access uses the deprecated legacy object API.

Installation

pip install xcresult

Requires Python 3.10+ and Xcode 27's xcresulttool (schema version 0.4.0). Select the Xcode installation using xcode-select or DEVELOPER_DIR. Older Xcode schema versions are not currently a supported compatibility target.

Library Usage

import xcresult

bundle = xcresult.Xcresults("/path/to/MyApp.xcresult")

# Check build issues
for error in bundle.build_results.errors:
    print(error.message, error.sourceURL)

# Check availability before requesting test reports from build-only bundles
if bundle.content_availability.hasTestResults:
    print(bundle.test_summary.failedTests)
    for node in bundle.tests.testNodes:
        print(node.name, node.result)

# Read a specific test's individual runs or activity trees
details = bundle.test_details("MyTests/testExample()")
activities = bundle.test_activities("MyTests/testExample()")

# Export test attachments (screenshots, etc.)
manifest = bundle.export_test_attachments("/path/to/output/")

# Write JUnit XML
bundle.write_junit("/path/to/results.junit")

build_results, content_availability, test_summary, and tests are loaded lazily and cached for the lifetime of the Xcresults instance. Test identifiers can be identifier strings or identifier URLs; prefer URLs when targets contain identically named tests. Apple field names retain their camelCase spelling.

Attachments use xcresulttool's export layout: files and manifest.json in the output directory. The returned manifest identifies each test's files through attachment.exportedFileName. To export only one test or suite, pass test_id="MyTests/testExample()".

Use a fresh output directory for each export: xcresulttool refuses to overwrite an existing manifest.json. The JUnit export_attachments_path option performs its own export, so it also needs a directory without an existing manifest.

JUnit options

bundle.write_junit(
    "/path/to/results.junit",
    export_attachments_path="/path/to/attachments",
    test_class_prefix="MyApp",
    test_class_suffix="UI",
    collapse_retries=True,
    test_filter=lambda test: not test.name.startswith("disabled"),
)

By default, each individual run becomes a testcase, rather than reporting only the aggregate result. Retry collapsing prefers a passing attempt and keeps different devices, configurations, and arguments separate. Expected failures are treated as successful outcomes; skipped tests become <skipped> elements. Unknown outcomes are not treated as passes. The filter receives a modern TestNode; excluded tests do not contribute to XML counts or leave empty suites. Suite names follow the modern bundle/suite hierarchy, with configuration and device recorded as properties. Attachment links come from the export manifest. Build-only bundles produce an empty JUnit report.

CLI Usage

The package installs an xcresult command with three subcommands:

Export test attachments

xcresult -b /path/to/MyApp.xcresult export -o /path/to/output/

Generate JUnit XML

xcresult -b /path/to/MyApp.xcresult junit -o /path/to/results.junit

Optionally export attachments alongside the JUnit file:

xcresult -b /path/to/MyApp.xcresult junit -o /path/to/results.junit --export-attachments-path /path/to/attachments/

Collapse retry attempts:

xcresult -b /path/to/MyApp.xcresult junit -o /path/to/results.junit --collapse-retries

Check for issues

xcresult -b /path/to/MyApp.xcresult check-issues

Filter by issue type with --issue-types:

xcresult -b /path/to/MyApp.xcresult check-issues --issue-types error warning

Available issue types: error, warning, analyzer-warning, test-failure, test-warning.

Returns exit code 1 if any matching issues are found.

Migrating from the legacy API

This is a breaking library API change. The command-line subcommands remain available, but the underlying models, attachment layout, and JUnit suite hierarchy now follow the modern reports.

Legacy API Modern API
actions_invocation_record.issues build_results.errors, .warnings, .analyzerWarnings, plus test_summary.testFailures and .runtimeWarnings
actions_invocation_record.actions and testsRef traversal tests.testNodes and test_details(test_id).testRuns
get(object_id) and summary references test_details(test_id) or test_activities(test_id)
export_attachment(payload_id, type, path) export_test_attachments(directory, test_id=...) and its returned manifest
ActionTestMetadata in test filters TestNode (name, nodeIdentifier, nodeIdentifierURL, result)
deserialize(legacy_typed_json) Tests.from_dict(json_data) or deserialize(json_data, Tests)

Legacy Action*, Reference, and other internal object-graph models are no longer exported. Modern models are dataclasses with required constructor arguments and optional fields defaulting to None. Missing required data and invalid field types raise errors; unrecognized properties are logged and ignored to accommodate additive tool changes. Decoding does not mutate input. Test results use modern values such as Passed, Failed, Skipped, and Expected Failure, rather than legacy testStatus values. Timestamp fields are UNIX seconds, not datetime objects. Models use normal mutable dataclass equality and are not hashable.

Development

Dependencies are managed with Poetry. Regenerate the models from the selected Xcode installation's endpoint schemas, then format them:

python -m generator
python -m black --line-length 100 xcresult/model.py

The generator reads the schemas for test summaries, test trees, test details, activities, build results, content availability, and attachment manifests. It reconciles shared types and keeps distinct activity/export attachment models. Two known schema cardinality errors are corrected to match report output: Summary.devicesAndConfigurations and Activities.testRuns are arrays. Generated models are checked in; using the package does not run the generator.

python -m pytest tests
XCRESULT_RUN_INTEGRATION=1 python -m pytest tests/test_modern_integration.py

Tests cover ordinary JSON decoding, command routing, issue reporting, retries, filtering, report counts, and manifest-based attachment links. Xcode integration checks use disposable fixture copies because xcresulttool may update a bundle's database while reading it. The live test-report, activity, and export checks are opt-in and require a working local Xcode test-report cache; command failures are surfaced rather than silently falling back to the legacy API.

License

MIT

Metadata

Release files for xcresult 27.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for xcresult 27.0.0
File Size Uploaded
xcresult-27.0.0.tar.gz 18.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for xcresult 27.0.0
File Interpreter ABI Platform
xcresult-27.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 39.4 kB

Release files / xcresult-27.0.0.tar.gz

Download URL xcresult-27.0.0.tar.gz
Size 18.9 kB
Tags Source
SHA-256 checksum
How to use checksums
8cfc429cc5b8bc97cbca4647ac9096610053e856d0810801ae32242adfc4bbff
BLAKE2b-256 checksum
How to use checksums
2d2e59c1b3b22560bd5f18be8ba0db0651bd80089ff877ae88ca70eb081b7408
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.3.3 CPython/3.12.14 Darwin/25.6.0

Release files / xcresult-27.0.0-py3-none-any.whl

Download URL xcresult-27.0.0-py3-none-any.whl
Size 20.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ececaa4372dedfe3a71f90d88475341e8f28e42ec8cd039ed2053002825a6f03
BLAKE2b-256 checksum
How to use checksums
767821a5a6e0ef94bf385403b2b1d15c30e20934134930a55fb57f03ae65ed6f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.3.3 CPython/3.12.14 Darwin/25.6.0
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page