A Python port of the Eclipse Modeling Framework (EMF) Core metamodel and runtime.
It is derived from two references:
- TypeScript (
EMFTs/emfts) — structure and a tested behavior suite that serves as the conformance oracle. - Java (
learn/org.eclipse.emf) — the original, authoritative semantics.
Status: core complete — Phases 0–8 done; the ported conformance suite is green (284 tests,
ruff+mypy --strictclean). SeePLAN.mdfor per-phase detail.
- Dynamic EMF in pure Python: build metamodels programmatically, create instances, and use
the reflective API (
e_get/e_set/e_is_set/e_unset) — no code generation required. - Self-describing Ecore metamodel + global package registry (resolve classifiers by nsURI).
- Notification framework:
Adapter/Notifier/EContentAdapter, wired intoEObjectandEList. - Resources:
URI,Resource/ResourceSet, URI fragments (XPath / ID ///Name), cross-document proxies. - Serialization: emfjson-compatible JSON and XMI (loads/saves real
.ecoremodels) — both on the Python standard library (no required external deps). - Bidirectional references: instance-level opposite maintenance (EMF
eInverseAdd/eInverseRemovesemantics, including reparenting). - Utilities:
EcoreUtil(resolve/copy/containment), isinstance-based type guards, and an Eclipse-style plugin/extension registry with decorators.
Behavioral parity with the EMF references is verified by a 1:1 pytest port of the TypeScript suite (284 tests, all green).
pip install emfFrom source:
git clone https://github.com/eclipse-fennec/emf.py.git
cd emf.py
pip install .With optional lxml backend for faster XML parsing:
pip install emf[lxml]Runnable demos live in examples/:
python examples/runtime_example.py # build a metamodel, reflect, JSON round-trip
python examples/usage_example.py # registry lookup + XMI round-trip
python examples/plugin_system_example.py # extension points via decoratorsJava/TypeScript are camelCase; EMFPy maps idiomatically:
| EMF (TS/Java) | EMFPy |
|---|---|
eGet / eSet / eIsSet / eUnset |
e_get / e_set / e_is_set / e_unset |
eClass() / eContainer() / eContents() |
e_class() / e_container() / e_contents() |
getName() / setName() |
property .name |
isContainment() |
property .containment |
| Interfaces | ABCs (abc.ABC) |
EList |
collections.abc.MutableSequence subclass |
Class names stay EMF-canonical (EObject, EClass, BasicEObject, DynamicEObject, …).
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]" # add the optional lxml backend with: ".[dev,lxml]"
pytest # run the conformance suite
ruff check . && mypy # lint + type-checkEclipse Public License 2.0 (EPL-2.0) — same as Eclipse EMF.