You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iTi-Flask/iti/exchange/base.py

248 lines
7.2 KiB
Python

from __future__ import annotations
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Protocol, Sequence
class ExchangeTemplateKind(str, Enum):
IMPORT = "import"
EXPORT = "export"
class ExchangeTaskKind(str, Enum):
IMPORT = "import"
EXPORT = "export"
@dataclass(frozen=True)
class ExchangePlaceholder:
key: str
label: str
description: str | None = None
required: bool = False
example: str | None = None
@dataclass(frozen=True)
class ExchangeField:
key: str
label: str
placeholder: str | None = None
required: bool = False
example: str | None = None
width: int | None = None
format: str | None = None
source: str | None = None
target: str | None = None
options: tuple[tuple[str, str], ...] = ()
meta: dict[str, Any] = field(default_factory=dict)
def workbook_header(self) -> str:
return self.placeholder or self.label or self.key
def export_source_key(self) -> str:
return self.source or self.key
def import_target_key(self) -> str:
return self.target or self.key
@dataclass(frozen=True)
class ExchangeTemplateBinding:
entity: str
template_kind: ExchangeTemplateKind
handler: str | None = None
description: str | None = None
default_sheet_name: str | None = None
default_file_name: str | None = None
title: str | None = None
meta: dict[str, Any] = field(default_factory=dict)
class ExchangeTemplateSourceKind(str, Enum):
LOCAL = "local"
REMOTE = "remote"
MAPPING = "mapping"
CUSTOM = "custom"
@dataclass(frozen=True)
class ExchangeTemplateSnapshot:
id: str
version: str
template_id: str
template_kind: ExchangeTemplateKind
bindings: tuple[ExchangeTemplateBinding, ...] = ()
published_at: str | None = None
file_key: str | None = None
checksum: str | None = None
fields: tuple[ExchangeField, ...] = ()
placeholders: tuple[ExchangePlaceholder, ...] = ()
meta: dict[str, Any] = field(default_factory=dict)
def to_plan(self) -> "ExchangePlan":
meta = dict(self.meta)
return ExchangePlan(
template_kind=self.template_kind,
template_id=self.template_id,
version_id=self.id,
version=self.version,
bindings=self.bindings,
fields=self.fields,
placeholders=self.placeholders,
title=meta.get("title"),
description=meta.get("description"),
sheet_name=meta.get("sheet_name"),
meta=meta,
)
@dataclass(frozen=True)
class ExchangePlan:
template_kind: ExchangeTemplateKind
template_id: str | None = None
version_id: str | None = None
version: str | None = None
bindings: tuple[ExchangeTemplateBinding, ...] = ()
fields: tuple[ExchangeField, ...] = ()
placeholders: tuple[ExchangePlaceholder, ...] = ()
title: str | None = None
description: str | None = None
sheet_name: str | None = None
meta: dict[str, Any] = field(default_factory=dict)
@classmethod
def from_mapping(
cls,
*,
template_kind: ExchangeTemplateKind | str,
template_id: str | None = None,
version_id: str | None = None,
version: str | None = None,
bindings: Sequence[ExchangeTemplateBinding] | None = None,
fields: Sequence[ExchangeField] | None = None,
placeholders: Sequence[ExchangePlaceholder] | None = None,
title: str | None = None,
description: str | None = None,
sheet_name: str | None = None,
meta: dict[str, Any] | None = None,
) -> "ExchangePlan":
return cls(
template_kind=ExchangeTemplateKind(template_kind),
template_id=template_id,
version_id=version_id,
version=version,
bindings=tuple(bindings or ()),
fields=tuple(fields or ()),
placeholders=tuple(placeholders or ()),
title=title,
description=description,
sheet_name=sheet_name,
meta=meta or {},
)
def resolved_meta(self) -> dict[str, Any]:
meta = dict(self.meta)
if self.template_id is not None:
meta.setdefault("template_id", self.template_id)
if self.version_id is not None:
meta.setdefault("version_id", self.version_id)
if self.version is not None:
meta.setdefault("version", self.version)
if self.title is not None:
meta.setdefault("title", self.title)
if self.description is not None:
meta.setdefault("description", self.description)
if self.sheet_name is not None:
meta.setdefault("sheet_name", self.sheet_name)
return meta
@dataclass(frozen=True)
class ExchangeTemplateSource:
kind: ExchangeTemplateSourceKind
template_kind: ExchangeTemplateKind
template_id: str | None = None
version_id: str | None = None
version: str | None = None
service: str | None = None
bindings: tuple[ExchangeTemplateBinding, ...] = ()
fields: tuple[ExchangeField, ...] = ()
placeholders: tuple[ExchangePlaceholder, ...] = ()
title: str | None = None
description: str | None = None
sheet_name: str | None = None
meta: dict[str, Any] = field(default_factory=dict)
def to_plan(self) -> ExchangePlan:
meta = dict(self.meta)
return ExchangePlan(
template_kind=self.template_kind,
template_id=self.template_id,
version_id=self.version_id,
version=self.version,
bindings=self.bindings,
fields=self.fields,
placeholders=self.placeholders,
title=self.title,
description=self.description,
sheet_name=self.sheet_name,
meta=meta,
)
@dataclass(frozen=True)
class ExchangeTemplate:
id: str
code: str
name: str
template_kind: ExchangeTemplateKind
entity: str
status: str = "draft"
description: str | None = None
current_version: str | None = None
bindings: tuple[ExchangeTemplateBinding, ...] = ()
fields: tuple[ExchangeField, ...] = ()
placeholders: tuple[ExchangePlaceholder, ...] = ()
meta: dict[str, Any] = field(default_factory=dict)
def to_plan(self) -> ExchangePlan:
meta = dict(self.meta)
return ExchangePlan(
template_kind=self.template_kind,
template_id=self.id,
version_id=self.current_version,
bindings=self.bindings,
fields=self.fields,
placeholders=self.placeholders,
title=self.name,
description=self.description,
sheet_name=meta.get("sheet_name"),
meta={
"code": self.code,
"status": self.status,
"current_version": self.current_version,
**meta,
},
)
class DataExchangeModule(Protocol):
name: str
def init_app(self, app) -> None:
...
def register_routes(self, app) -> None:
...
def register_permissions(self, app) -> None:
...
def register_menu_seed(self, app) -> None:
...
def register_tasks(self, app) -> None:
...