Skip to main content

Archivar für Videoschnitt-Projekte: packt FCPXML-Bundles und iMovieMobile-Container ins Langzeit-Archiv, mit aggregierten Projekt-Metadaten und Video-Originalmedien-Inventar.

Project description

🎬 schnittprojekt-archivar

Archivar für Videoschnitt-Projekte. Verpackt FCPXML-Bundles und iMovieMobile-Container ins Langzeit-Archiv und schreibt zwei aggregierte Metadaten-Sidecars dazu: Projekt-Übersicht (.project.toml) und Clip-Inventar (.project.clips.jsonl) mit voller MediaFileMetadata pro referenziertem Quellclip.

Status: 2.2.0 (Beta) — Greenfield-Neuanfang nach Bounded-Context-Wechsel; die Versionsnummer setzt den Git-Tag-Stream des Repos fort (v1.x war fcplib-manager, siehe CHANGELOG). API-Vertrag startet mit 2.0.0; v2.1.0 ergänzt Konsumenten-Helpers (verify_archive, skip_if_target_exists, delete_source_after_archive) für die familienfilm-manager-Integration; v2.2.0 macht Final-Cut-Pro-Bundles mit externen Library-Medien self-contained (FCP-Materializer). Breaking Changes erst bei 3.0.0.

Hinweis: Bis Januar 2026 hiess dieses Repo fcplib-manager und archivierte Final-Cut-Pro-Libraries (FCPBundles) via tar+split+SSH. Mit der Umbenennung zu schnittprojekt-archivar ändert sich der Bounded Context komplett: Schnittprojekte im FCPXML-/iMovieMobile-Format statt FCP-Library-Bundles.

✨ Was es kann

  • Drei Schnittprojekt-Formate:
    • .fcpxmld (FCP-Bundle, Verzeichnis) → ZIP-Container mit ZIP_STORED+allowZip64 (kein erneutes Komprimieren, weil Bundle-Medien bereits HEVC/ProRes sind)
    • .fcpxml (Single-File) → 1:1-Kopie ohne Container
    • .iMovieMobile (ist schon ZIP) → 1:1-Kopie ohne erneutes Zippen
  • FCP-Materializer (v2.2.0+): Final-Cut-Pro-Bundles, deren Info.fcpxml per <media-rep src="file:///.../Library.fcpbundle/..."> auf externe Library-Medien zeigt, werden beim Archivieren self-contained gemacht. Der Archivar kopiert die Originale in eine Staging-Kopie nach Original Media/ und schreibt das XML auf relative ./Original Media/{name}-Pfade um — das resultierende ZIP ist ohne die ursprüngliche FCP-Library in FCP/LumaFusion/anderer Software wieder importierbar. LumaFusion-Bundles mit relativen <asset src="./..."> bleiben unbeeinflusst (No-Op).
  • Atomares Schreiben überall (write-to-tempfile + os.replace). Crashes hinterlassen keine Halb-Dateien.
  • Aggregiertes Projekt-Manifest (<stem>.project.toml): Format, Sequenz, Aufnahmedatum mit Provenance, Clip-Anzahl, Bundle-Größe.
  • Clip-Inventar (<stem>.project.clips.jsonl): pro referenziertem Quellclip eine JSONL-Zeile mit voller MediaFileMetadata aus kurmann-medien-leser (Codec, Auflösung, GPS, Kamera-Modell, Production-Felder, etc.) — kompatibel zum kamera-einleser-Manifest-Format für Cross-References zwischen Schnittprojekt-Sicht und Originalmedien-Volumes.
  • rclone-Ziele unterstützt: lokal in work_dir aufbauen, dann via rclone copyto ins Archiv-Remote.
  • Flexibles Konsumenten-API: Suffixe sind Konstanten (keine hardcoded Implementierungs-Details). Drei Schichten — Daten, Bundle-Packaging, Persistierung — können separat oder als Convenience zusammen genutzt werden.

📋 Voraussetzungen

  • Python 3.11 oder höher
  • exiftool (Pflicht, für Clip-Inventar) — brew install exiftool auf macOS
  • rclone (optional, für rclone-Ziele) — brew install rclone auf macOS

Quelle = lokaler Pfad. Der Archivar liest das Schnittprojekt heute ausschliesslich vom lokalen Filesystem (echte lokale Pfade oder gemountete Netzpfade wie /Volumes/<share>/...). rclone-URIs (remote:path/...) sind nur als Ziel (--target-dir) erlaubt, nicht als Quelle. Wer ein Projekt vom NAS archivieren will, ohne den Share gemountet zu haben, holt es vorher via rclone copy ins lokale Work-Dir.

Archivieren = kopieren, nicht verschieben. Die Originalquelle wird nie gelöscht oder verändert. Der Archivar arbeitet ausschliesslich Copy-and-Verify; Aufräumen der Quelle ist Aufgabe des Konsumenten (z. B. familienfilm-manager).

.fcpxml vs. .fcpxmld — was archiviert wird: FCP exportiert oft beides nebeneinander: eine Flat-.fcpxml (paar KB XML) und ein .fcpxmld/-Bundle (Verzeichnis mit Info.fcpxml + Resources). Wenn beide mit gleichem Stem nebeneinander liegen, bricht der Archivar mit Fehler ab, statt zu raten — du gibst gezielt das .fcpxmld/-Verzeichnis an, wenn du das Bundle willst. Override: --allow-flat-fcpxml.

Self-contained, immer. Bei .fcpxmld-Bundles im LumaFusion-Stil liegen die Originalmedien bereits direkt im Bundle neben der Projekt-XML, mit relativen src="./..."-Pfaden — der Archivar packt den gesamten Bundle-Inhalt mit ins ZIP. Bei .fcpxmld-Bundles im Final-Cut-Pro-Stil (nur Info.fcpxml im Bundle, Medien per <media-rep src="file://..."> extern in einer Library.fcpbundle) materialisiert der Archivar die externen Medien vor dem ZIP-Build in eine Staging-Kopie (siehe FCP-Materializer-Punkt oben). .iMovieMobile-Container sind formatbedingt self-contained. In allen drei Fällen gilt: Archiv entpacken → in FCP/LumaFusion/iMovie öffnen, alle Medien gefunden. Bei der Flat-.fcpxml-Variante (nur die XML, keine Bundle-Hülle) wird nur die XML kopiert; das ist als Live-Workflow-Sicht gedacht, nicht als Langzeit-Archiv. Das .project.clips.jsonl-Inventar dokumentiert zusätzlich, aus welchen ISO-Manifests / Volumes die Clips ursprünglich stammen — Cross-Reference zur Originalmedien-Sicht, nicht Ersatz für Mitarchivierung.

🚀 Installation

uv add kurmann-schnittprojekt-archivar
# oder
pipx install kurmann-schnittprojekt-archivar
# oder
pip install kurmann-schnittprojekt-archivar

🎯 Quick Start

CLI

schnittprojekt-archivar archive \
    "/Volumes/Videoschnitt/Familienfilme/Projekte/Mädchen spazieren.fcpxmld" \
    --target-dir "lyssach-nas:/Archiv/2026/Projekte" \
    --target-stem "2026-05-10-Maedchen-spazieren" \
    --timezone Europe/Zurich

Erzeugt im Ziel:

2026-05-10-Maedchen-spazieren.fcpxmld.zip   ← Bundle als ZIP
2026-05-10-Maedchen-spazieren.project.toml  ← Projekt-Metadaten
2026-05-10-Maedchen-spazieren.project.clips.jsonl   ← Clip-Inventar

Als Bibliothek

from pathlib import Path
from schnittprojekt_archivar import archive_project
from schnittprojekt_archivar.models import ArchiveProjectRequest, RuntimeOptions

result = archive_project(
    ArchiveProjectRequest(
        project_path=Path("Mädchen spazieren.fcpxmld"),
        target_dir="lyssach-nas:/Archiv/2026/Projekte",
        target_stem="2026-05-10-Maedchen-spazieren",
        timezone_assumption="Europe/Zurich",
    ),
    RuntimeOptions(),
)
if result.success:
    print(result.bundle.target_uri, result.bundle.bundle_size_bytes)
else:
    print("Fehler:", result.error_message)

🧾 Was kommt zurück? Beispiel-Output

<stem>.project.toml (aggregiert)

[meta]
schema_version = 1
generator = "Kurmann Schnittprojekt-Archivar 2.2.0"
created_at = "2026-05-21T10:00:00+02:00"

[project]
name = "Fünffacher Büsi-Nachwuchs bei Tagesmutter Karin"
format = "fcpxml_bundle"
schema_version = "1.8"
original_filename = "Fünffacher Büsi-Nachwuchs bei Tagesmutter Karin poster-13s080.fcpxmld"
mtime = "2026-05-10T20:02:57+02:00"

[recording]
first_clip_date = "2026-05-05"
first_clip_datetime = "2026-05-05T17:43:51+02:00"
first_clip_source_label = "exif:Keys:CreationDate"
first_clip_confidence = "high"

[sequence]
width = 3840
height = 2160
color_space = "9-16-9 (Rec. 2020 PQ)"
audio_layout = "stereo"

[counts]
clips_primary = 6
clips_total = 7

[bundle]
archive_filename = "2026-05-05-Buesi-Nachwuchs.fcpxmld.zip"
archive_size_bytes = 421857393

<stem>.project.clips.jsonl (Inventar)

{"_type":"header","manifest_version":1,"project_name":"Fünffacher Büsi-Nachwuchs bei Tagesmutter Karin","project_format":"fcpxml_bundle","clip_count":6,"generator":"Kurmann Schnittprojekt-Archivar 2.2.0","created_at":"2026-05-21T10:00:00+02:00"}
{"spine_index":0,"relative_path":"./A001_05051743_C491.mov","asset_id":"p1997","clip_name":"A001_05051743_C491","is_video":true,"resolution_status":"resolved","resolved_uri":"/.../A001_05051743_C491.mov","media_metadata":{"recorded_at":"2026-05-05T17:43:51+02:00","recorded_at_source":"exif:Keys:CreationDate","source_app":"Blackmagic Camera","video":{"codec":"HEVC","resolution":"3840x2160","fps":60.007},"camera":{"model":"Apple iPhone 15 Pro Max 120mm","software":"Blackmagic Cam 3.3.100001"},"gps":{"lat":47.06675,"lon":7.58025}}}
{"spine_index":1,"relative_path":"./A001_05051744_C492.mov",...}

🏛 Architektur — drei Schichten + ein Wrapper

┌─────────────────────────────────────────────────────────────────┐
│ Convenience / CLI                                               │
│ ─────────────────                                               │
│ archive_project(request, runtime)                               │
│   opinion-getriebener Happy-Path: liest, packt, persistiert.    │
└─────────────────────────────────────────────────────────────────┘
              │
        ┌─────┼─────┐
        ▼     ▼     ▼
 ┌──────────┐ ┌──────────────┐ ┌────────────────────┐
 │ Daten    │ │ Bundle       │ │ Persistierung      │
 │ ─────    │ │ ──────       │ │ ──────────────     │
 │ read_    │ │ package_     │ │ write_manifest_    │
 │ project_ │ │ project_     │ │ toml(m, path)      │
 │ manifest │ │ bundle       │ │ write_clips_jsonl( │
 │  → in-   │ │  → ZIP /     │ │   m, path)         │
 │   memory │ │   1:1-Kopie  │ │ Suffix-Konstanten  │
 │ Mani-    │ │   nach Ziel  │ │ als Empfehlung,    │
 │ fest     │ │              │ │ nicht Pflicht      │
 └──────────┘ └──────────────┘ └────────────────────┘

Konsumenten können nach Bedarf entweder den Convenience-Wrapper nutzen oder die einzelnen Schichten kombinieren — siehe „Konsumenten-Szenarien" weiter unten.

📚 Public API

Symbol Beschreibung
archive_project(request, runtime) → ArchiveProjectResult Convenience-Orchestrator: Manifest lesen + Bundle packen + Sidecars schreiben
verify_archive(target_dir, target_stem, runtime) → VerifyArchiveResult v2.1.0 Read-only-Idempotenz-Check: liegen alle erwarteten Artefakte am Ziel?
read_project_manifest(path, runtime) → ProjectManifest Liest Schnittprojekt + Clips, liefert in-memory Objekt (keine Side-Effects)
package_project_bundle(path, target_dir, filename, runtime) → PackageResult Verpackt Bundle ins Ziel (Caller wählt Filename)
write_manifest_toml(manifest, path) Aggregiertes Manifest als TOML (atomar)
write_clips_jsonl(manifest, path) Clip-Inventar als JSONL (atomar)
to_archive_stem(text) → str, is_archive_safe_stem(text) → bool ASCII-Slug-Helper (v2.0.0+, idempotent)
PROJECT_TOML_SUFFIX, CLIPS_JSONL_SUFFIX, FCPXML_BUNDLE_ZIP_SUFFIX, IMOVIE_MOBILE_SUFFIX, FCPXML_SINGLE_SUFFIX Empfohlene Suffixe als Konstanten
ArchiveProjectRequest, ArchiveProjectResult, PackageResult, RuntimeOptions, ProjectManifest, ClipEntry, ProjectHeader, SequenceInfo, ArchivarEvent Dataclasses (Type-Hints + Serialisierungs-Helpers)
SchnittprojektArchivarError, BundleError, ManifestReadError, ArchiveTargetError, ArchiveTargetExistsError Exception-Hierarchie

🏷 Begriffe und Suffix-Konventionen

Die Suffixe sind so gewählt, dass sie auch ohne diese README verständlich sind und nicht mit anderen kurmann-Sidecars kollidieren.

Quellformate: .fcpxml, .fcpxmld, .iMovieMobile

Suffix Was es ist Wie's der Archivar verpackt
.fcpxml Flat-XML, Single-File. Reine Edit-Decision-XML, paar KB bis paar MB. 1:1-Kopie.
.fcpxmld FCPXML-Document = macOS-Package (Verzeichnis). Enthält Info.fcpxml + bei LumaFusion-Export die Medien direkt daneben (./*.mov), bei Final-Cut-Pro-Export externe <media-rep src="file:///.../Library.fcpbundle/...">-Referenzen in eine FCP-Library. Das d-Suffix ist Apples Konvention für „Bundle-Variante eines flachen Formats" (analog .rtf.rtfd). ZIP-Container .fcpxmld.zip mit ZIP_STORED+allowZip64, alphabetisch sortierte Member (deterministisch). FCP-Materializer (v2.2.0+) erkennt externe file://-Referenzen und kopiert die Medien vor dem ZIP-Build in eine Staging-Kopie nach Original Media/, schreibt das XML auf relative Pfade um.
.iMovieMobile iMovie-iOS-Export — bereits ein ZIP-Container. 1:1-Kopie (kein Re-Zip).

Wenn FCP beides exportiert (.fcpxml und .fcpxmld mit gleichem Stem): immer das .fcpxmld archivieren — das ist die vollständige Variante. Der Archivar erkennt diese Mehrdeutigkeit und bricht ab, wenn man die Flat-Variante als Quelle angibt, während ein Bundle daneben liegt. Override falls bewusst nur die Flat-XML gewünscht: --allow-flat-fcpxml.

Namespace .project.* (Archivar) vs. .video.* (familienfilm-manager)

Wenn ein Familienfilm gleichzeitig als Schnitt-Export und als Schnittprojekt archiviert wird, leben beide Sätze problemlos im selben Verzeichnis nebeneinander — gleicher <stem>, unterschiedliche Domäne-Präfixe:

2026-05-10-Maedchen-spazieren.mov                       ← FFM-Video-Export
2026-05-10-Maedchen-spazieren.video.toml                ← FFM-Sidecar (Recording, Publishing)
2026-05-10-Maedchen-spazieren.fcpxmld.zip               ← Archivar-Bundle
2026-05-10-Maedchen-spazieren.project.toml              ← Archivar-Projekt-Manifest
2026-05-10-Maedchen-spazieren.project.clips.jsonl       ← Archivar-Clip-Inventar
Namespace Domäne Verantwortlich
.video.* exportierter Schnitt-Stream (was publiziert wird) familienfilm-manager
.project.* Schnittprojekt-Quelldatei (woraus exportiert wurde) dieser Archivar

<domäne>.toml ohne weiteren Zusatz = Haupt-Manifest dieser Domäne (= „Metadaten"). Zusatz-Suffixe wie .clips qualifizieren spezialisierte Inventare.

Warum „Clips" und nicht „Originalmedien"?

Zwei legitime Vokabulare treffen aufeinander:

  • Schnittprojekt-Sicht (im FCPXML als <asset-clip>, im iMovieMobile als editList[i] mit clipType): hier sind die referenzierten Asset-Einheiten Clips. Das ist die Sprache, in der das Projekt selbst über sein Material spricht. Auch Audio-Subspuren wären „Audio-Clips" im Schnitt-Sinne.
  • NAS-Sicht (/Volumes/Originalmedien/, kamera-einleser-ISO-Manifests): hier heisst dasselbe Material Originalmedien — die unbeschnittenen Aufnahmen von der Kamera, bevor sie ein Projekt sehen.

Beide Begriffe widersprechen sich nicht, sie zeigen dasselbe Material aus zwei Schichten. In diesem Archivar gilt die Schnittprojekt-Sicht — daher .project.clips.jsonl. Cross-References zwischen kamera-einleser-ISO-Manifest (Originalmedien-Sicht) und <stem>.project.clips.jsonl (Schnittprojekt-Sicht) bleiben über die gemeinsame MediaFileMetadata-Struktur möglich (gleiche Felder, gleiche Schemas, beide aus kurmann-medien-leser).

🎯 Scope von include_clips (v2.0.0)

Standardmässig (include_clips=True) wird das vollständige Inventar aller referenzierten Video-Clips in <stem>.project.clips.jsonl geschrieben.

Enthalten: Top-Level-Spine-Video-Clips mit Asset-Backing — bei FCPXML alles, was asset-clip mit echter Quelldatei referenziert; bei iMovieMobile editList-Einträge mit clipType=1.

Bewusst NICHT enthalten (Stand v2.0.0):

  • Audio-Subspuren / separate Audio-Synchronspuren
  • Foto-Clips (clipType=5 iMovieMobile)
  • Transitions (clipType=3)
  • Sekundäre Tracks / Picture-in-Picture
  • Generators, Titles, Effekte ohne Asset-Backing

Hintergrund: Die Detail-Metadaten pro Clip werden vom kurmann-medien-leser gelesen, der heute auf Video-Metadaten ausgerichtet ist. Sobald Audio-Schemas dort verfügbar sind, wird include_audio_tracks=True als additives Flag ergänzt — kein Schema-Bruch nötig, weil „Clip" konzeptuell auch Audio-Clips abdecken kann.

Use-Case: Cross-References zwischen Schnittprojekten und Originalmedien-Volumes (z.B. ISO-Manifests aus kamera-einleser). Fragen wie „welche Clips aus ISO XYZ wurden in welchem Schnittprojekt verwendet?" sind mit beiden JSONL-Manifesten gemeinsam beantwortbar — gleiches MediaFileMetadata-Schema.

🤝 Konsumenten-Szenarien

Szenario α: Standalone-Aufruf via CLI

schnittprojekt-archivar archive <projekt> \
    --target-dir <archiv-uri> --target-stem <slug>

Alles ins Ziel, drei Sidecars nebeneinander.

Szenario β: Bundle packen, Manifest in eigene Struktur einbetten

Für Konsumenten wie den familienfilm-manager, die ihr eigenes Sidecar-Schema haben:

from schnittprojekt_archivar import (
    read_project_manifest,
    package_project_bundle,
)

# 1. Manifest als in-memory-Objekt lesen
manifest = read_project_manifest(project_path, runtime)

# 2. Bundle separat verpacken (Konsument wählt Filename)
package_project_bundle(
    project_path,
    target_dir="nas:/Archiv/2026/Videoschnitt",
    target_filename="2026-05-10-Maedchen.fcpxmld.zip",
    runtime=runtime,
)

# 3. Konsument bettet Manifest in eigene .video.toml-Sektion ein —
#    schreibt KEIN .project.toml oder .project.clips.jsonl daneben.
ffm_sidecar.schnittprojekt = {
    "bundle_filename": "2026-05-10-Maedchen.fcpxmld.zip",
    "first_clip_date": manifest.header.first_clip_date,
    "clip_count": len(manifest.clips),
    # ... etc
}

Szenario γ: Convenience, aber kein project.clips.jsonl

from schnittprojekt_archivar import archive_project
from schnittprojekt_archivar.models import ArchiveProjectRequest

archive_project(
    ArchiveProjectRequest(
        project_path=project_path,
        target_dir=target_dir,
        target_stem="2026-05-10-Maedchen",
        write_clips_jsonl_file=False,  # nur .project.toml + Bundle
    ),
    runtime,
)

🐚 CLI-Disziplin (Unix-Style)

Der schnittprojekt-archivar-CLI folgt klassischer Unix-Philosophie: Stille ist Erfolg.

Kanal Default --verbose --json
stdout (leer) (leer) Result-JSON
stderr (leer); Fehler bei Misserfolg Event-Trace + Slug-Hinweis + Sub-Prozess-Output wie ohne --json
Exit-Code 0 (Erfolg) / 1 (Fehler) wie Default wie Default

Beispiele:

# Stiller Aufruf — Erfolg erkennt man am Exit-Code
schnittprojekt-archivar archive <projekt> --target-dir <ziel>
echo $?    # 0

# Pipeline-Konsument
schnittprojekt-archivar archive <projekt> --target-dir <ziel> --json \
  | jq -r .target_uri

# Diagnose
schnittprojekt-archivar archive <projekt> --target-dir <ziel> -v
# stderr zeigt: [stem_slugified] target_stem »...« → »...«
#               [bundle_build_started] ...
#               [bundle_upload_completed] ...

Fehler landen immer auf stderr, unabhängig von --verbose. --verbose und --json sind orthogonal kombinierbar.

🏷 ASCII-Slug-Disziplin

Der Archivar wendet per Default eine Archivierungs-Disziplin auf den Ziel-Dateinamen an: target_stem wird durch to_archive_stem() geschickt und damit ASCII-safe gemacht. So bleiben die Archiv-Dateinamen filesystem-, cloud- und Tooling-neutral lesbar.

Algorithmus (in schnittprojekt_archivar.models.slug):

  1. Unicode-Normalisierung NFC.
  2. Deutsche Transliteration: ä→ae, ö→oe, ü→ue, ß→ss (Gross-Schreibung analog).
  3. NFKD + ASCII-Encode errors="ignore" (entfernt restliche Diakritika und Nicht-ASCII).
  4. Regex [^a-zA-Z0-9]+ → '-', dann führende/abschliessende - strippen.

Beispiele:

Eingabe Ergebnis
Mädchen spazieren Maedchen-spazieren
2026-05-10 – Höhenflug 2026-05-10-Hoehenflug
Café crème Cafe-creme
2026-05-10-Maedchen 2026-05-10-Maedchen (unverändert)

Die Funktion ist idempotent — doppelte Anwendung ändert nichts.

Public-API:

from schnittprojekt_archivar import to_archive_stem, is_archive_safe_stem

to_archive_stem("Mädchen spazieren")        # "Maedchen-spazieren"
is_archive_safe_stem("Mädchen spazieren")   # False
is_archive_safe_stem("Maedchen-spazieren")  # True

Default-Verhalten in archive_project: Umlaute werden still umgeformt, das Ergebnis steht in ArchiveProjectResult.effective_stem, das Original in original_stem, das Flag stem_was_slugified=True. Zusätzlich emittiert der Archivar eine Warnung und ein stem_slugified-Event.

Strict-Modus mit strict_stem=True (CLI: --strict-stem): der Archivar slugifiziert nicht, sondern verlangt, dass der gelieferte Stem bereits archivtauglich ist. Andernfalls bricht er mit klarer Fehlermeldung ab, bevor irgendetwas geschrieben wird — sinnvoll für Konsumenten, die selbst über die finale Namensgebung bestimmen wollen (z. B. familienfilm-manager, der seine eigene Slug-Logik hat).

Diese Slug-Logik existiert 1:1 auch im familienfilm-manager (Code-Spiegelung). Sobald ein dritter Konsument auftaucht oder Archiv-Helpers gebündelt werden sollen (PAR2, ZIP64, Indexierung), lohnt sich ein kurmann-archiv-utils-Helper-Repo. Heute YAGNI.

🛣️ Roadmap

  • 0.x: API-Stabilisierung mit dem ersten Konsumenten (familienfilm-manager v1.5+).
  • 0.2.x: extract-Subcommand für Retrieval aus dem Archiv (Architektur ist eingeplant, Schemas tragen die nötigen Felder bereits).
  • 0.3.x: Indexierung über mehrere Projekte (optional — Discovery via externe jq-Queries reicht heute).
  • 1.0.0: API-Lock nach SemVer.
  • Später: include_audio_tracks=True, sobald kurmann-medien-leser Audio-Schemas unterstützt.

📝 Lizenz

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kurmann_schnittprojekt_archivar-2.2.0.tar.gz (67.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kurmann_schnittprojekt_archivar-2.2.0-py3-none-any.whl (62.0 kB view details)

Uploaded Python 3

File details

Details for the file kurmann_schnittprojekt_archivar-2.2.0.tar.gz.

File metadata

File hashes

Hashes for kurmann_schnittprojekt_archivar-2.2.0.tar.gz
Algorithm Hash digest
SHA256 5b81ec13043f573bbcd00e5d03bd659f421e8240ff0e042ab5cc762ba7ebd1a7
MD5 c36dee1e63efdabfacbcc056bc385391
BLAKE2b-256 1d28eb745015e5e5b9d303168d4566297e297d6525ad1c93862ebc43dd93075f

See more details on using hashes here.

Provenance

The following attestation bundles were made for kurmann_schnittprojekt_archivar-2.2.0.tar.gz:

Publisher: publish.yml on kurmann/schnittprojekt-archivar

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kurmann_schnittprojekt_archivar-2.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for kurmann_schnittprojekt_archivar-2.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 50b9af9ff712dfb0527419b33e0e18faca3c44a5052a1e06e04641af0135958f
MD5 ee7d8bfd019615b584f4488331e58565
BLAKE2b-256 cec16ec494fb5f1d2a48549e1bd5e89265840508bc9c3ff50f4affbab03daa21

See more details on using hashes here.

Provenance

The following attestation bundles were made for kurmann_schnittprojekt_archivar-2.2.0-py3-none-any.whl:

Publisher: publish.yml on kurmann/schnittprojekt-archivar

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page