ecm-generate-models

ecm-generate-models ist ein Kommandozeilen-Werkzeug, das typisierte Python-Modellklassen (ECMFolderModel, ECMRegisterModel, ECMDocumentModel) aus der enaio-Objektdefinition generiert.

Die generierten Klassen enthalten für jedes Feld eine typisierte ECMField-Deklaration sowie Enums für Listenfelder. Damit stehen in der IDE vollständige Code-Completion und Typprüfung zur Verfügung, ohne dass Feldnamen manuell nachgepflegt werden müssen.

1. Installation

Das Kommando ist in der Hauptinstallation enthalten — kein zusätzliches Extra erforderlich:

  • uv

  • pip

uv add ecmind-blue-client
pip install ecmind-blue-client

2. Argumente

2.1. Quelle (genau eine erforderlich)

Argument Standard Beschreibung

--host HOST

Hostname oder IP-Adresse des enaio-Servers. Gegenseitig ausschließend mit --file.

--file XML_FILE

Pfad zu einer lokalen asobjdef-XML-Datei (UTF-16- oder UTF-8-kodiert). Gegenseitig ausschließend mit --host.

2.2. Server-Optionen (nur mit --host)

Argument Standard Beschreibung

--port PORT

4000

TCP-Port des enaio-Servers.

--username USER

Benutzername für die Anmeldung am Server. Erforderlich bei --host.

--password PASS

Passwort für die Anmeldung am Server. Erforderlich bei --host.

--no-ssl

SSL aktiv

SSL/TLS deaktivieren. Standard: SSL ist aktiviert.

--name APPNAME

Anwendungsname, der im Enterprise Manager angezeigt wird (optional).

2.3. Ausgabe

Argument Standard Beschreibung

--output-dir DIR

stdout

Verzeichnis, in das die generierten .py-Dateien geschrieben werden. Pro Kabinett wird eine Datei <interner_name>.py erstellt. Wird die Option weggelassen, wird der generierte Code auf der Standardausgabe ausgegeben.

--cabinet NAME

alle

Nur Modelle für das Kabinett mit diesem internen Namen generieren. Wird die Option weggelassen, werden alle Kabinette generiert.

3. Beispiele

3.1. Vom Live-Server generieren

Der häufigste Anwendungsfall: Verbindung zum Server, alle Kabinette in ein Verzeichnis schreiben.

ecm-generate-models \
    --host enaio.example.com \
    --username admin \
    --password secret \
    --output-dir ./models

Ausgabe im Terminal:

Written: models/Invoices.py
Written: models/Contracts.py

3.2. Nur ein bestimmtes Kabinett generieren

ecm-generate-models \
    --host enaio.example.com \
    --username admin \
    --password secret \
    --cabinet Invoices \
    --output-dir ./models

3.3. Aus lokaler XML-Datei generieren

Die asobjdef-Datei kann einmalig vom Server exportiert werden und danach lokal verwendet werden — ohne aktive Serververbindung.

ecm-generate-models --file asobjdef.xml --output-dir ./models

3.4. Vorschau auf der Konsole

Ohne --output-dir wird der generierte Code direkt ausgegeben — nützlich zur schnellen Überprüfung:

ecm-generate-models \
    --host enaio.example.com \
    --username admin \
    --password secret \
    --cabinet Invoices

3.5. Ohne SSL (Entwicklungsumgebung)

ecm-generate-models \
    --host localhost \
    --port 4000 \
    --username admin \
    --password secret \
    --no-ssl \
    --output-dir ./models

4. Ausgabeformat

Pro Kabinett wird eine .py-Datei mit folgendem Aufbau generiert:

  • Imports (nur die tatsächlich benötigten)

  • Enums für Felder mit Listenkatalog

  • ECMTableRowModel-Subklassen für Tabellenfelder

  • Modellklassen (ECMFolderModel, ECMRegisterModel, ECMDocumentModel)

Beispiel einer generierten Datei:

"""Auto-generated ECM model classes for cabinet "Invoices".

DO NOT EDIT — regenerate with ecm-generate-models.
"""

from enum import Enum
from datetime import date

from ecmind_blue_client.ecm.model import (
    ECMDocumentModel,
    ECMField,
    ECMFolderModel,
    ECMRegisterModel,
    ECMTableField,
    ECMTableRowModel,
)


class InvoiceFolder_StatusEnum(str, Enum):
    OPEN = "Open"
    PAID = "Paid"
    CANCELLED = "Cancelled"


class InvoiceDocument_PositionsRow(ECMTableRowModel):
    Description: ECMField[str] = ECMField(str, default=None)
    Amount: ECMField[float] = ECMField(float, default=None)
    Date: ECMField[date] = ECMField(date, default=None)


class InvoiceFolder(ECMFolderModel):
    _internal_name_ = "InvoiceFolder"

    Title: ECMField[str] = ECMField(str, mandatory=True, default=None)
    Year: ECMField[int] = ECMField(int, default=None)
    Status: ECMField[InvoiceFolder_StatusEnum] = ECMField(InvoiceFolder_StatusEnum, default=None)


class InvoiceRegister(ECMRegisterModel):
    _internal_name_ = "InvoiceRegister"

    Name: ECMField[str] = ECMField(str, mandatory=True, default=None)


class InvoiceDocument(ECMDocumentModel):
    _internal_name_ = "InvoiceDocument"

    Title: ECMField[str] = ECMField(str, mandatory=True, default=None)
    InvoiceDate: ECMField[date] = ECMField(date, default=None)
    Positions: ECMTableField[InvoiceDocument_PositionsRow] = ECMTableField(default_factory=list)

5. Generierte Modelle verwenden

Die generierten Dateien werden einmalig nach der Erstellung importiert und dann in der Anwendung verwendet:

  • Sync

  • Async

from ecmind_blue_client.ecm import ECM
from ecmind_blue_client.pool import SyncPoolClient
from models.Invoices import InvoiceFolder, InvoiceRegister, InvoiceDocument

ecm = ECM(SyncPoolClient(servers="enaio.example.com:4000:1", username="admin", password="secret"))

# Abfragen mit vollem Typ-Support
for folder in (
    ecm.dms.select(InvoiceFolder)
    .where(InvoiceFolder.Year >= 2024)
    .order_by(InvoiceFolder.Year.DESC)
    .stream()
):
    print(folder.system.id, folder.Title, folder.Status)

# Neues Objekt anlegen
folder = ecm.dms.insert_and_get(
    InvoiceFolder(Title="Rechnung 2024", Year=2024)
)

# Feld aktualisieren
folder.Title = "Rechnung 2024 (aktualisiert)"
ecm.dms.update(folder)
from ecmind_blue_client.ecm import ECM
from ecmind_blue_client.pool import AsyncPoolClient
from models.Invoices import InvoiceFolder, InvoiceRegister, InvoiceDocument

ecm = ECM(AsyncPoolClient(servers="enaio.example.com:4000:1", username="admin", password="secret"))

# Abfragen mit vollem Typ-Support
async for folder in (
    ecm.dms.select(InvoiceFolder)
    .where(InvoiceFolder.Year >= 2024)
    .order_by(InvoiceFolder.Year.DESC)
    .stream()
):
    print(folder.system.id, folder.Title, folder.Status)

# Neues Objekt anlegen
folder = await ecm.dms.insert_and_get(
    InvoiceFolder(Title="Rechnung 2024", Year=2024)
)

# Feld aktualisieren
folder.Title = "Rechnung 2024 (aktualisiert)"
await ecm.dms.update(folder)

6. Wann neu generieren?

Die generierten Dateien sollten neu erstellt werden, wenn:

  • Neue Felder oder Objekttypen im enaio-Archivschema hinzugefügt wurden

  • Feldtypen oder Pflichtfeldmarkierungen geändert wurden

  • Einträge in Listkatalogen hinzugefügt oder entfernt wurden

Die Dateien tragen den Kommentar DO NOT EDIT — manuelle Änderungen gehen beim nächsten Generieren verloren. Eigene Erweiterungen können in separaten Dateien als Subklassen definiert werden.

7. Siehe auch

  • Schnellstart — Überblick über den Einstieg in die Bibliothek

  • select() — Objekte mit typisiertem Modell abfragen

  • insert() — Neue Objekte anlegen