Skip to main content

Xcodefy

PyPI version Xcodefy - Test Coverage License: MIT Python versions

Modern Python library and command-line tool for the new Xcode project.xcproj project format.


🚀 Project

Xcodefy reads, writes, validates, formats, and manipulates the new JSON5-based Xcode project format introduced with Xcode 27.

The project follows the model published in Apple's open-source xcode-project-format repository while providing a Python-native API and packaging. It intentionally supports only the new project.xcproj format. The legacy project.pbxproj format is outside the scope of the library.

The internal package layout mirrors the main areas of Apple's implementation:

apple/xcode-project-format                 xcodefy
Sources/Library/Schema          ->         src/xcodefy/library/schema
Sources/Library/Serialization   ->         src/xcodefy/library/serialization
Sources/Library/Utilities       ->         src/xcodefy/library/utilities
Sources/Tool                    ->         src/xcodefy/tool

Every model class and enum lives in its own Python file. Every class has a mirrored unit test file, and the complete suite is required to maintain 100% statement and branch coverage.

✨ Features

  • Read and write project.xcproj
  • Accept an outer .xcodeproj package or an inner project.xcproj file
  • JSON5 parser with comments, trailing commas, unquoted keys, single-quoted strings, hexadecimal numbers, and JSON5 escapes
  • Canonical pretty printer with ordered output, omitted defaults, and the reference's compact and multi-line layout rules
  • Complete Python model for projects, targets, references, build phases, build files, build rules, configurations, Swift packages, folder exception sets, imported products, and schema value types
  • High-level project manipulation API
  • Add and remove files and target membership
  • Add and remove targets
  • Add Swift package references
  • Edit project-level and target-level build settings
  • Validate project invariants and required capabilities
  • xcodefy command-line formatter equivalent to Apple's xcprojformatter workflow
  • Zero runtime dependencies
  • uv development workflow
  • Wheel and source distribution ready for PyPI
  • PyPI Trusted Publishing release workflow
  • 100% statement and branch coverage gate
  • Single-source version, managed through the Makefile

📦 Install

With pip:

pip install xcodefy

With uv:

uv add xcodefy

Xcodefy requires Python 3.11 or newer.

💡 Library usage

Load an Xcode project package:

from xcodefy.xcode_project import XcodeProject

project = XcodeProject.load("MyApp.xcodeproj")
project.set_build_setting("SWIFT_VERSION", "6.0")
project.set_build_setting("PRODUCT_BUNDLE_IDENTIFIER", "com.example.myapp", target="MyApp")
project.save()

Add a Swift source file to a target. The path is relative to the group it is added to, so this one lands at Sources/Feature.swift:

from xcodefy.xcode_project import XcodeProject

project = XcodeProject.load("MyApp.xcodeproj")
project.add_group("Sources")
project.add_file("Feature.swift", target="MyApp", group="Sources")
project.save()

Add a local Swift package:

from xcodefy.library.schema.packages.local_swift_package import LocalSwiftPackage
from xcodefy.library.schema.packages.swift_package import SwiftPackage
from xcodefy.library.schema.packages.swift_package_location import SwiftPackageLocation
from xcodefy.xcode_project import XcodeProject

project = XcodeProject.load("MyApp.xcodeproj")
project.add_package(SwiftPackage(SwiftPackageLocation.of_local(LocalSwiftPackage("../Shared"))))
project.save()

Add a target and a file to it:

from xcodefy.library.schema.build_phases.build_phase import BuildPhase
from xcodefy.library.schema.build_phases.build_phase_kind import BuildPhaseKind
from xcodefy.library.schema.target.common_target_properties import CommonTargetProperties
from xcodefy.library.schema.target.target import Target
from xcodefy.library.schema.values.object_id import ObjectID
from xcodefy.xcode_project import XcodeProject

project = XcodeProject.load("MyApp.xcodeproj")
phases = [BuildPhase.of_kind(BuildPhaseKind.SOURCES)]
project.add_target(Target.native(CommonTargetProperties("Widget", ObjectID("W1"), build_phases=phases)))
project.add_group("Widget")
project.add_file("WidgetBundle.swift", target="Widget", group="Widget")
project.save()

The lower-level schema types are available directly from their modules. Package __init__.py files are deliberately empty, so imports always identify the concrete source module.

Reading a project and writing it back is idempotent: the output is the canonical rendering, so running Xcodefy over an already-canonical document changes nothing.

🛠️ Command-line tool

Xcodefy includes a formatter with the same input/output workflow as the tool in Apple's reference package:

xcodefy [[--input] input-project] [--output output-project]
xcodefy --update project
xcodefy --help
xcodefy --version

Update a project in place:

xcodefy --update MyApp.xcodeproj

Read from standard input and write canonical output to standard output:

cat project.xcproj | xcodefy

Format one project into another:

xcodefy --input Input.xcodeproj --output Output.xcodeproj

Both Input.xcodeproj and Input.xcodeproj/project.xcproj are valid paths.

🧪 Development

Install the locked development environment:

make install

Run the complete suite:

make test

Run the strict coverage gate:

make coverage

Run lint and formatting checks:

make lint

Build the wheel and source distribution:

make build
make check

📚 Documentation

🏷️ Releasing a new version

A release is driven by a matching Git tag. The version lives only in pyproject.toml, and the Makefile is the only thing that writes it:

make version                    # show the current version
make set-version VERSION=x.y.z  # set it
make bump PART=patch            # or raise major, minor or patch

Commit the change, then push the matching tag:

git tag vX.Y.Z
git push origin vX.Y.Z

The release workflow runs lint and the full 100% coverage suite, verifies that the tag matches the declared package version, builds the wheel and source distribution with uv, validates both distributions with Twine, publishes to PyPI through Trusted Publishing, and creates the GitHub release.

Configure the PyPI Trusted Publisher for repository paulocoutinhox/xcodefy, workflow release.yml, and environment pypi before the first release.

☕ Buy me a coffee

Support the continuous development of this project.

Buy Me a Coffee at ko-fi.com

📄 License

MIT

Copyright (c) 2026, Paulo Coutinho

Xcodefy is an independent project and is not affiliated with Apple Inc. Xcode, Swift, and Apple are trademarks of Apple Inc. See THIRD_PARTY_NOTICES.md.

Release files for xcodefy 0.0.2

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

Source distribution (sdist)

Source distribution for xcodefy 0.0.2
File Size Uploaded
xcodefy-0.0.2.tar.gz 544.0 kB Details

Built distribution (wheel)

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

Total release size: 651.9 kB

Release files / xcodefy-0.0.2.tar.gz

Download URL xcodefy-0.0.2.tar.gz
Size 544.0 kB
Tags Source
SHA-256 checksum
How to use checksums
f601815fe69ca4194d3db741bd29ef1ff5de08e1f1b649d1698d3d9defefe4a1
BLAKE2b-256 checksum
How to use checksums
638ad7c0c0cd0ff226bff47cc13d43bac6d0cf1745ad6ddc80db3b9e9f0a813e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.

Transparency log

Release files / xcodefy-0.0.2-py3-none-any.whl

Download URL xcodefy-0.0.2-py3-none-any.whl
Size 107.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ef5eb509951ae80190ae96f697b2516c73c1d41c7de0616acc6d6829aa8aa295
BLAKE2b-256 checksum
How to use checksums
84994f594b4a35d88c49665b75e5e5dd4d14d1aec8706e30b8fd26db7c5e49a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.0.2 This release

2 release files

0.0.1

2 release files

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