fix: resolve all deprecation warnings and remove dead test scripts
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
dce41a01ac
commit
30db7a310c
6 changed files with 76 additions and 671 deletions
|
|
@ -57,37 +57,17 @@ class GeoTag(str, Enum):
|
|||
class GeoPunkt(BaseModel):
|
||||
"""Represents a 3D point with reference."""
|
||||
koordinatensystem: str = Field(
|
||||
description="Coordinate system (e.g. 'LV95', 'EPSG:2056')",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=True,
|
||||
)
|
||||
description="Coordinate system (e.g. 'LV95', 'EPSG:2056')", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": True})
|
||||
x: float = Field(
|
||||
description="East value (E) [m], typically 2'480'000 - 2'840'000",
|
||||
frontend_type="number",
|
||||
frontend_readonly=False,
|
||||
frontend_required=True,
|
||||
)
|
||||
description="East value (E) [m], typically 2'480'000 - 2'840'000", json_schema_extra={"frontend_type": "number", "frontend_readonly": False, "frontend_required": True})
|
||||
y: float = Field(
|
||||
description="North value (N) [m], typically 1'070'000 - 1'300'000",
|
||||
frontend_type="number",
|
||||
frontend_readonly=False,
|
||||
frontend_required=True,
|
||||
)
|
||||
description="North value (N) [m], typically 1'070'000 - 1'300'000", json_schema_extra={"frontend_type": "number", "frontend_readonly": False, "frontend_required": True})
|
||||
z: Optional[float] = Field(
|
||||
None,
|
||||
description="Height above sea level [m]",
|
||||
frontend_type="number",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Height above sea level [m]", json_schema_extra={"frontend_type": "number", "frontend_readonly": False, "frontend_required": False})
|
||||
referenz: Optional[GeoTag] = Field(
|
||||
None,
|
||||
description="Point categorization",
|
||||
frontend_type="select",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Point categorization", json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": False})
|
||||
|
||||
|
||||
class GeoPolylinie(BaseModel):
|
||||
|
|
@ -97,18 +77,10 @@ class GeoPolylinie(BaseModel):
|
|||
description="Primary key",
|
||||
)
|
||||
closed: bool = Field(
|
||||
description="Is the GeoPolylinie closed (polygon)?",
|
||||
frontend_type="boolean",
|
||||
frontend_readonly=False,
|
||||
frontend_required=True,
|
||||
)
|
||||
description="Is the GeoPolylinie closed (polygon)?", json_schema_extra={"frontend_type": "boolean", "frontend_readonly": False, "frontend_required": True})
|
||||
punkte: List[GeoPunkt] = Field(
|
||||
default_factory=list,
|
||||
description="List of GeoPunkte forming the GeoPolylinie",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=True,
|
||||
)
|
||||
description="List of GeoPunkte forming the GeoPolylinie", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": True})
|
||||
|
||||
|
||||
@i18nModel("Dokument")
|
||||
|
|
@ -117,73 +89,33 @@ class Dokument(PowerOnModel):
|
|||
id: str = Field(
|
||||
default_factory=lambda: str(uuid.uuid4()),
|
||||
description="Primary key",
|
||||
frontend_type="text",
|
||||
frontend_readonly=True,
|
||||
frontend_required=False,
|
||||
label="ID",
|
||||
)
|
||||
json_schema_extra={"label": "ID", "frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
mandateId: str = Field(
|
||||
description="ID of the mandate this document belongs to",
|
||||
frontend_type="text",
|
||||
frontend_readonly=True,
|
||||
frontend_required=False,
|
||||
label="Mandats-ID",
|
||||
)
|
||||
json_schema_extra={"label": "Mandats-ID", "frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
featureInstanceId: str = Field(
|
||||
description="ID of the feature instance this document belongs to",
|
||||
frontend_type="text",
|
||||
frontend_readonly=True,
|
||||
frontend_required=False,
|
||||
label="Feature-Instanz-ID",
|
||||
)
|
||||
json_schema_extra={"label": "Feature-Instanz-ID", "frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
label: str = Field(
|
||||
description="Document label",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=True,
|
||||
label="Bezeichnung",
|
||||
)
|
||||
json_schema_extra={"label": "Bezeichnung", "frontend_type": "text", "frontend_readonly": False, "frontend_required": True})
|
||||
versionsbezeichnung: Optional[str] = Field(
|
||||
None,
|
||||
description="Version number or designation (e.g. 'v1.0', 'Rev. A')",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Version number or designation (e.g. 'v1.0', 'Rev. A')", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False})
|
||||
dokumentTyp: Optional[DokumentTyp] = Field(
|
||||
None,
|
||||
description="Document type",
|
||||
frontend_type="select",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Document type", json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": False})
|
||||
dokumentReferenz: str = Field(
|
||||
description="File path or URL",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=True,
|
||||
)
|
||||
description="File path or URL", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": True})
|
||||
quelle: Optional[str] = Field(
|
||||
None,
|
||||
description="Source of the document",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Source of the document", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False})
|
||||
mimeType: Optional[str] = Field(
|
||||
None,
|
||||
description="MIME type of the document (e.g. 'application/pdf', 'image/png')",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="MIME type of the document (e.g. 'application/pdf', 'image/png')", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False})
|
||||
kategorienTags: List[str] = Field(
|
||||
default_factory=list,
|
||||
description="Document categorization tags",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Document categorization tags", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
|
||||
|
||||
class Kontext(PowerOnModel):
|
||||
|
|
@ -193,78 +125,38 @@ class Kontext(PowerOnModel):
|
|||
description="Primary key",
|
||||
)
|
||||
thema: str = Field(
|
||||
description="Theme designation",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=True,
|
||||
)
|
||||
description="Theme designation", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": True})
|
||||
inhalt: str = Field(
|
||||
description="Detailed information (text)",
|
||||
frontend_type="textarea",
|
||||
frontend_readonly=False,
|
||||
frontend_required=True,
|
||||
)
|
||||
description="Detailed information (text)", json_schema_extra={"frontend_type": "textarea", "frontend_readonly": False, "frontend_required": True})
|
||||
|
||||
|
||||
class Land(PowerOnModel):
|
||||
"""National level administrative entity."""
|
||||
id: str = Field(
|
||||
default_factory=lambda: str(uuid.uuid4()),
|
||||
description="Primary key",
|
||||
frontend_type="text",
|
||||
frontend_readonly=True,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Primary key", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
mandateId: str = Field(
|
||||
description="ID of the mandate",
|
||||
frontend_type="text",
|
||||
frontend_readonly=True,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="ID of the mandate", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
featureInstanceId: str = Field(
|
||||
description="ID of the feature instance",
|
||||
frontend_type="text",
|
||||
frontend_readonly=True,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="ID of the feature instance", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
label: str = Field(
|
||||
description="Country name (e.g. 'Schweiz')",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=True,
|
||||
)
|
||||
description="Country name (e.g. 'Schweiz')", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": True})
|
||||
abk: Optional[str] = Field(
|
||||
None,
|
||||
description="Abbreviation (e.g. 'CH')",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Abbreviation (e.g. 'CH')", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False})
|
||||
dokumente: List[Dokument] = Field(
|
||||
default_factory=list,
|
||||
description="National laws/documents",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="National laws/documents", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
kontextInformationen: List[Kontext] = Field(
|
||||
default_factory=list,
|
||||
description="National context information",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="National context information", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
|
||||
|
||||
class Kanton(PowerOnModel):
|
||||
"""Cantonal level administrative entity."""
|
||||
id: str = Field(
|
||||
default_factory=lambda: str(uuid.uuid4()),
|
||||
description="Primary key",
|
||||
frontend_type="text",
|
||||
frontend_readonly=True,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Primary key", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
mandateId: str = Field(
|
||||
description="ID of the mandate",
|
||||
json_schema_extra={
|
||||
|
|
@ -282,11 +174,7 @@ class Kanton(PowerOnModel):
|
|||
},
|
||||
)
|
||||
label: str = Field(
|
||||
description="Canton name (e.g. 'Zürich')",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=True,
|
||||
)
|
||||
description="Canton name (e.g. 'Zürich')", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": True})
|
||||
id_land: Optional[str] = Field(
|
||||
None,
|
||||
description="Land ID (Foreign Key) - eindeutiger Link zum Land, in welchem Land der Kanton liegt",
|
||||
|
|
@ -299,54 +187,26 @@ class Kanton(PowerOnModel):
|
|||
)
|
||||
abk: Optional[str] = Field(
|
||||
None,
|
||||
description="Abbreviation (e.g. 'ZH')",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Abbreviation (e.g. 'ZH')", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False})
|
||||
dokumente: List[Dokument] = Field(
|
||||
default_factory=list,
|
||||
description="Cantonal documents",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Cantonal documents", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
kontextInformationen: List[Kontext] = Field(
|
||||
default_factory=list,
|
||||
description="Canton-specific context information",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Canton-specific context information", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
|
||||
|
||||
class Gemeinde(PowerOnModel):
|
||||
"""Municipal level administrative entity."""
|
||||
id: str = Field(
|
||||
default_factory=lambda: str(uuid.uuid4()),
|
||||
description="Primary key",
|
||||
frontend_type="text",
|
||||
frontend_readonly=True,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Primary key", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
mandateId: str = Field(
|
||||
description="ID of the mandate",
|
||||
frontend_type="text",
|
||||
frontend_readonly=True,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="ID of the mandate", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
featureInstanceId: str = Field(
|
||||
description="ID of the feature instance",
|
||||
frontend_type="text",
|
||||
frontend_readonly=True,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="ID of the feature instance", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
label: str = Field(
|
||||
description="Municipality name (e.g. 'Zürich')",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=True,
|
||||
)
|
||||
description="Municipality name (e.g. 'Zürich')", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": True})
|
||||
id_kanton: Optional[str] = Field(
|
||||
None,
|
||||
description="Kanton ID (Foreign Key) - eindeutiger Link zum Kanton, in welchem Kanton die Gemeinde liegt",
|
||||
|
|
@ -359,25 +219,13 @@ class Gemeinde(PowerOnModel):
|
|||
)
|
||||
plz: Optional[str] = Field(
|
||||
None,
|
||||
description="Postal code (for municipalities with multiple PLZ, this can be a main PLZ). Bei Gemeinden mit mehreren Postleitzahlen wird die konkrete PLZ der Parzelle im Attribut `plz` der Parzelle erfasst.",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Postal code (for municipalities with multiple PLZ, this can be a main PLZ). Bei Gemeinden mit mehreren Postleitzahlen wird die konkrete PLZ der Parzelle im Attribut `plz` der Parzelle erfasst.", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False})
|
||||
dokumente: List[Dokument] = Field(
|
||||
default_factory=list,
|
||||
description="Municipal documents",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Municipal documents", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
kontextInformationen: List[Kontext] = Field(
|
||||
default_factory=list,
|
||||
description="Municipality-specific context information",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Municipality-specific context information", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
|
||||
|
||||
# ===== Main Models (use ForwardRef for circular references) =====
|
||||
|
|
@ -392,11 +240,7 @@ class Parzelle(PowerOnModel):
|
|||
id: str = Field(
|
||||
default_factory=lambda: str(uuid.uuid4()),
|
||||
description="Primary key",
|
||||
frontend_type="text",
|
||||
frontend_readonly=True,
|
||||
frontend_required=False,
|
||||
label="ID",
|
||||
)
|
||||
json_schema_extra={"label": "ID", "frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
mandateId: str = Field(
|
||||
description="ID of the mandate",
|
||||
json_schema_extra={
|
||||
|
|
@ -421,55 +265,27 @@ class Parzelle(PowerOnModel):
|
|||
# Grunddaten
|
||||
label: str = Field(
|
||||
description="Plot designation",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=True,
|
||||
label="Bezeichnung",
|
||||
)
|
||||
json_schema_extra={"label": "Bezeichnung", "frontend_type": "text", "frontend_readonly": False, "frontend_required": True})
|
||||
parzellenAliasTags: List[str] = Field(
|
||||
default_factory=list,
|
||||
description="Additional plot names or field names",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Additional plot names or field names", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
eigentuemerschaft: Optional[str] = Field(
|
||||
None,
|
||||
description="Owner of the plot",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Owner of the plot", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False})
|
||||
strasseNr: Optional[str] = Field(
|
||||
None,
|
||||
description="Street and house number",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Street and house number", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False})
|
||||
plz: Optional[str] = Field(
|
||||
None,
|
||||
description="Postal code of the plot",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Postal code of the plot", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False})
|
||||
|
||||
# Geografischer Kontext
|
||||
perimeter: Optional[GeoPolylinie] = Field(
|
||||
None,
|
||||
description="Plot boundary as closed GeoPolylinie",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Plot boundary as closed GeoPolylinie", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
baulinie: Optional[GeoPolylinie] = Field(
|
||||
None,
|
||||
description="Building line of the plot",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Building line of the plot", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
|
||||
kontextGemeinde: Optional[str] = Field(
|
||||
None,
|
||||
|
|
@ -485,145 +301,69 @@ class Parzelle(PowerOnModel):
|
|||
# Bebauungsparameter
|
||||
bauzone: Optional[str] = Field(
|
||||
None,
|
||||
description="Building zone designation (e.g. W3, WG2, etc.)",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Building zone designation (e.g. W3, WG2, etc.)", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False})
|
||||
az: Optional[float] = Field(
|
||||
None,
|
||||
description="Ausnützungsziffer",
|
||||
frontend_type="number",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Ausnützungsziffer", json_schema_extra={"frontend_type": "number", "frontend_readonly": False, "frontend_required": False})
|
||||
bz: Optional[float] = Field(
|
||||
None,
|
||||
description="Bebauungsziffer",
|
||||
frontend_type="number",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Bebauungsziffer", json_schema_extra={"frontend_type": "number", "frontend_readonly": False, "frontend_required": False})
|
||||
vollgeschossZahl: Optional[int] = Field(
|
||||
None,
|
||||
description="Number of allowed full floors",
|
||||
frontend_type="number",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Number of allowed full floors", json_schema_extra={"frontend_type": "number", "frontend_readonly": False, "frontend_required": False})
|
||||
anrechenbarDachgeschoss: Optional[float] = Field(
|
||||
None,
|
||||
description="Accountable portion of attic (0.0 - 1.0)",
|
||||
frontend_type="number",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Accountable portion of attic (0.0 - 1.0)", json_schema_extra={"frontend_type": "number", "frontend_readonly": False, "frontend_required": False})
|
||||
anrechenbarUntergeschoss: Optional[float] = Field(
|
||||
None,
|
||||
description="Accountable portion of basement (0.0 - 1.0)",
|
||||
frontend_type="number",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Accountable portion of basement (0.0 - 1.0)", json_schema_extra={"frontend_type": "number", "frontend_readonly": False, "frontend_required": False})
|
||||
gebaeudehoeheMax: Optional[float] = Field(
|
||||
None,
|
||||
description="Maximum building height in meters",
|
||||
frontend_type="number",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Maximum building height in meters", json_schema_extra={"frontend_type": "number", "frontend_readonly": False, "frontend_required": False})
|
||||
|
||||
# Abstandsregelungen
|
||||
regelnGrenzabstand: List[str] = Field(
|
||||
default_factory=list,
|
||||
description="Regulations for boundary distance",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Regulations for boundary distance", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
regelnMehrlaengenzuschlag: List[str] = Field(
|
||||
default_factory=list,
|
||||
description="Regulations for additional length surcharge",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Regulations for additional length surcharge", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
regelnMehrhoehenzuschlag: List[str] = Field(
|
||||
default_factory=list,
|
||||
description="Regulations for additional height surcharge",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Regulations for additional height surcharge", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
|
||||
# Eigenschaften (Ja/Nein)
|
||||
parzelleBebaut: Optional[JaNein] = Field(
|
||||
None,
|
||||
description="Is the plot built?",
|
||||
frontend_type="select",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Is the plot built?", json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": False})
|
||||
parzelleErschlossen: Optional[JaNein] = Field(
|
||||
None,
|
||||
description="Is the plot developed?",
|
||||
frontend_type="select",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Is the plot developed?", json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": False})
|
||||
parzelleHanglage: Optional[JaNein] = Field(
|
||||
None,
|
||||
description="Is the plot on a slope?",
|
||||
frontend_type="select",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Is the plot on a slope?", json_schema_extra={"frontend_type": "select", "frontend_readonly": False, "frontend_required": False})
|
||||
|
||||
# Schutzzonen
|
||||
laermschutzzone: Optional[str] = Field(
|
||||
None,
|
||||
description="Noise protection zone (e.g. 'II')",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Noise protection zone (e.g. 'II')", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False})
|
||||
hochwasserschutzzone: Optional[str] = Field(
|
||||
None,
|
||||
description="Flood protection zone (e.g. 'tief')",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Flood protection zone (e.g. 'tief')", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False})
|
||||
grundwasserschutzzone: Optional[str] = Field(
|
||||
None,
|
||||
description="Groundwater protection zone",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Groundwater protection zone", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False})
|
||||
|
||||
# Beziehungen (stored as JSONB in database)
|
||||
parzellenNachbarschaft: List[Dict[str, Any]] = Field(
|
||||
default_factory=list,
|
||||
description="Neighboring plots (stored as list of Parzelle IDs or full objects)",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Neighboring plots (stored as list of Parzelle IDs or full objects)", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
dokumente: List[Dokument] = Field(
|
||||
default_factory=list,
|
||||
description="Plot-specific documents",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Plot-specific documents", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
kontextInformationen: List[Kontext] = Field(
|
||||
default_factory=list,
|
||||
description="Plot-specific context information",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Plot-specific context information", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
|
||||
|
||||
@i18nModel("Projekt")
|
||||
|
|
@ -632,11 +372,7 @@ class Projekt(PowerOnModel):
|
|||
id: str = Field(
|
||||
default_factory=lambda: str(uuid.uuid4()),
|
||||
description="Primary key",
|
||||
frontend_type="text",
|
||||
frontend_readonly=True,
|
||||
frontend_required=False,
|
||||
label="ID",
|
||||
)
|
||||
json_schema_extra={"label": "ID", "frontend_type": "text", "frontend_readonly": True, "frontend_required": False})
|
||||
mandateId: str = Field(
|
||||
description="ID of the mandate",
|
||||
json_schema_extra={
|
||||
|
|
@ -659,54 +395,26 @@ class Projekt(PowerOnModel):
|
|||
)
|
||||
label: str = Field(
|
||||
description="Project designation",
|
||||
frontend_type="text",
|
||||
frontend_readonly=False,
|
||||
frontend_required=True,
|
||||
label="Bezeichnung",
|
||||
)
|
||||
json_schema_extra={"label": "Bezeichnung", "frontend_type": "text", "frontend_readonly": False, "frontend_required": True})
|
||||
statusProzess: Optional[StatusProzess] = Field(
|
||||
None,
|
||||
description="Project status",
|
||||
frontend_type="select",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
label="Prozessstatus",
|
||||
)
|
||||
json_schema_extra={"label": "Prozessstatus", "frontend_type": "select", "frontend_readonly": False, "frontend_required": False})
|
||||
perimeter: Optional[GeoPolylinie] = Field(
|
||||
None,
|
||||
description="Envelope of all plots in the project",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Envelope of all plots in the project", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
baulinie: Optional[GeoPolylinie] = Field(
|
||||
None,
|
||||
description="Building line of the project",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Building line of the project", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
parzellen: List[Parzelle] = Field(
|
||||
default_factory=list,
|
||||
description="All plots of the project",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="All plots of the project", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
dokumente: List[Dokument] = Field(
|
||||
default_factory=list,
|
||||
description="Project-specific documents",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Project-specific documents", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
kontextInformationen: List[Kontext] = Field(
|
||||
default_factory=list,
|
||||
description="Project-specific context information",
|
||||
frontend_type="json",
|
||||
frontend_readonly=False,
|
||||
frontend_required=False,
|
||||
)
|
||||
description="Project-specific context information", json_schema_extra={"frontend_type": "json", "frontend_readonly": False, "frontend_required": False})
|
||||
|
||||
|
||||
# Resolve forward references
|
||||
|
|
|
|||
|
|
@ -457,10 +457,10 @@ async def getStats(
|
|||
instanceId: str,
|
||||
dateFrom: Optional[str] = Query(default=None, description="ISO date YYYY-MM-DD"),
|
||||
dateTo: Optional[str] = Query(default=None, description="ISO date YYYY-MM-DD"),
|
||||
bucket: str = Query(default="week", regex="^(day|week|month)$"),
|
||||
bucket: str = Query(default="week", pattern="^(day|week|month)$"),
|
||||
trackerIds: Optional[List[int]] = Query(default=None),
|
||||
categoryIds: Optional[List[int]] = Query(default=None, description="Filter by Redmine issue categories"),
|
||||
statusFilter: str = Query(default="*", regex="^(\\*|open|closed)$", description="Restrict to open/closed/all tickets"),
|
||||
statusFilter: str = Query(default="*", pattern="^(\\*|open|closed)$", description="Restrict to open/closed/all tickets"),
|
||||
context: RequestContext = Depends(getRequestContext),
|
||||
) -> RedmineStatsDto:
|
||||
mandateId = _validateInstanceAccess(instanceId, context)
|
||||
|
|
|
|||
|
|
@ -1,97 +0,0 @@
|
|||
# Copyright (c) 2026 PowerOn AG
|
||||
# All rights reserved.
|
||||
"""Test full KPI extraction and validation flow"""
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import pytest
|
||||
|
||||
# Add gateway directory to path
|
||||
_gateway_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
if _gateway_path not in sys.path:
|
||||
sys.path.insert(0, _gateway_path)
|
||||
|
||||
from modules.serviceCenter.services.serviceAi.subJsonResponseHandling import JsonResponseHandler
|
||||
from modules.datamodels.datamodelAi import JsonAccumulationState
|
||||
|
||||
# Load actual JSON response
|
||||
json_file = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"..", "..", "..", "local", "debug", "prompts",
|
||||
"20251130-211706-078-document_generation_response.txt"
|
||||
)
|
||||
|
||||
if not os.path.exists(json_file):
|
||||
pytest.skip(f"Test data file not found: {json_file}", allow_module_level=True)
|
||||
|
||||
with open(json_file, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Extract JSON
|
||||
from modules.shared.jsonUtils import extractJsonString
|
||||
extracted = extractJsonString(content)
|
||||
parsedJson = json.loads(extracted)
|
||||
|
||||
# KPI definition from the response
|
||||
kpiDefinitions = [{
|
||||
"id": "prime_numbers_count",
|
||||
"description": "Number of prime numbers generated and organized in the table",
|
||||
"jsonPath": "documents[0].sections[0].elements[0].rows",
|
||||
"targetValue": 4000
|
||||
}]
|
||||
|
||||
print("="*60)
|
||||
print("KPI EXTRACTION AND VALIDATION TEST")
|
||||
print("="*60)
|
||||
|
||||
# Step 1: Initialize accumulation state with KPIs
|
||||
accumulationState = JsonAccumulationState(
|
||||
accumulatedJsonString="",
|
||||
isAccumulationMode=True,
|
||||
lastParsedResult=None,
|
||||
allSections=[],
|
||||
kpis=[{**kpi, "currentValue": 0} for kpi in kpiDefinitions]
|
||||
)
|
||||
|
||||
print(f"\nStep 1: Initialized KPIs")
|
||||
for kpi in accumulationState.kpis:
|
||||
print(f" KPI {kpi['id']}: currentValue={kpi.get('currentValue', 'N/A')}, targetValue={kpi.get('targetValue', 'N/A')}")
|
||||
|
||||
# Step 2: Extract KPI values from parsed JSON
|
||||
print(f"\nStep 2: Extracting KPI values from JSON...")
|
||||
updatedKpis = JsonResponseHandler.extractKpiValuesFromJson(
|
||||
parsedJson,
|
||||
accumulationState.kpis
|
||||
)
|
||||
|
||||
print(f" Extracted {len(updatedKpis)} KPIs")
|
||||
for kpi in updatedKpis:
|
||||
print(f" KPI {kpi['id']}: currentValue={kpi.get('currentValue', 'N/A')}, targetValue={kpi.get('targetValue', 'N/A')}")
|
||||
|
||||
# Step 3: Validate progression
|
||||
print(f"\nStep 3: Validating KPI progression...")
|
||||
shouldProceed, reason = JsonResponseHandler.validateKpiProgression(
|
||||
accumulationState,
|
||||
updatedKpis
|
||||
)
|
||||
|
||||
print(f" Result: shouldProceed={shouldProceed}, reason={reason}")
|
||||
|
||||
# Step 4: Check what's in accumulationState.kpis vs updatedKpis
|
||||
print(f"\nStep 4: Comparing state...")
|
||||
print(f" accumulationState.kpis[0].currentValue = {accumulationState.kpis[0].get('currentValue', 'N/A')}")
|
||||
print(f" updatedKpis[0].currentValue = {updatedKpis[0].get('currentValue', 'N/A')}")
|
||||
|
||||
# Step 5: Check if we need to update accumulationState.kpis
|
||||
print(f"\nStep 5: Updating accumulationState.kpis...")
|
||||
accumulationState.kpis = updatedKpis
|
||||
print(f" Updated accumulationState.kpis[0].currentValue = {accumulationState.kpis[0].get('currentValue', 'N/A')}")
|
||||
|
||||
# Step 6: Validate again (should show progress)
|
||||
print(f"\nStep 6: Validating again after update...")
|
||||
shouldProceed2, reason2 = JsonResponseHandler.validateKpiProgression(
|
||||
accumulationState,
|
||||
updatedKpis
|
||||
)
|
||||
print(f" Result: shouldProceed={shouldProceed2}, reason={reason2}")
|
||||
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
# Copyright (c) 2026 PowerOn AG
|
||||
# All rights reserved.
|
||||
"""Test KPI extraction with incomplete JSON"""
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import pytest
|
||||
|
||||
# Add gateway directory to path
|
||||
_gateway_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
if _gateway_path not in sys.path:
|
||||
sys.path.insert(0, _gateway_path)
|
||||
|
||||
from modules.serviceCenter.services.serviceAi.subJsonResponseHandling import JsonResponseHandler
|
||||
from modules.datamodels.datamodelAi import JsonAccumulationState
|
||||
from modules.shared.jsonUtils import extractJsonString, repairBrokenJson
|
||||
|
||||
# Load actual incomplete JSON response
|
||||
json_file = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"..", "..", "..", "local", "debug", "prompts",
|
||||
"20251130-211706-078-document_generation_response.txt"
|
||||
)
|
||||
|
||||
if not os.path.exists(json_file):
|
||||
pytest.skip(f"Test data file not found: {json_file}", allow_module_level=True)
|
||||
|
||||
with open(json_file, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
print("="*60)
|
||||
print("KPI EXTRACTION WITH INCOMPLETE JSON TEST")
|
||||
print("="*60)
|
||||
|
||||
# Step 1: Try to extract and parse JSON
|
||||
print(f"\nStep 1: Extracting JSON string...")
|
||||
extracted = extractJsonString(content)
|
||||
print(f" Extracted length: {len(extracted)} chars")
|
||||
|
||||
# Step 2: Try to parse
|
||||
print(f"\nStep 2: Attempting to parse...")
|
||||
parsedJson = None
|
||||
try:
|
||||
parsedJson = json.loads(extracted)
|
||||
print(f" ✅ JSON parsed successfully")
|
||||
except json.JSONDecodeError as e:
|
||||
print(f" ❌ JSON parsing failed: {e}")
|
||||
print(f" Attempting repair...")
|
||||
try:
|
||||
parsedJson = repairBrokenJson(extracted)
|
||||
if parsedJson:
|
||||
print(f" ✅ JSON repaired successfully")
|
||||
else:
|
||||
print(f" ❌ JSON repair failed")
|
||||
except Exception as e2:
|
||||
print(f" ❌ Repair error: {e2}")
|
||||
|
||||
if not parsedJson:
|
||||
pytest.skip("Cannot proceed - JSON cannot be parsed or repaired", allow_module_level=True)
|
||||
|
||||
# Step 3: Check if path exists
|
||||
print(f"\nStep 3: Checking if KPI path exists...")
|
||||
path = "documents[0].sections[0].elements[0].rows"
|
||||
try:
|
||||
value = JsonResponseHandler._extractValueByPath(parsedJson, path)
|
||||
print(f" ✅ Path exists: {type(value)}")
|
||||
if isinstance(value, list):
|
||||
print(f" ✅ Value is list with {len(value)} items")
|
||||
if len(value) > 0:
|
||||
print(f" ✅ First item: {value[0]}")
|
||||
else:
|
||||
print(f" ⚠️ Value is not a list: {value}")
|
||||
except Exception as e:
|
||||
print(f" ❌ Path extraction failed: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
pytest.skip(f"Path extraction failed: {e}", allow_module_level=True)
|
||||
|
||||
# Step 4: Test KPI extraction
|
||||
print(f"\nStep 4: Testing KPI extraction...")
|
||||
kpiDefinitions = [{
|
||||
"id": "prime_numbers_count",
|
||||
"description": "Number of prime numbers generated and organized in the table",
|
||||
"jsonPath": "documents[0].sections[0].elements[0].rows",
|
||||
"targetValue": 4000
|
||||
}]
|
||||
|
||||
accumulationState = JsonAccumulationState(
|
||||
accumulatedJsonString="",
|
||||
isAccumulationMode=True,
|
||||
lastParsedResult=parsedJson,
|
||||
allSections=[],
|
||||
kpis=[{**kpi, "currentValue": 0} for kpi in kpiDefinitions]
|
||||
)
|
||||
|
||||
print(f" Initial KPI currentValue: {accumulationState.kpis[0].get('currentValue', 'N/A')}")
|
||||
|
||||
updatedKpis = JsonResponseHandler.extractKpiValuesFromJson(
|
||||
parsedJson,
|
||||
accumulationState.kpis
|
||||
)
|
||||
|
||||
print(f" Updated KPI currentValue: {updatedKpis[0].get('currentValue', 'N/A')}")
|
||||
|
||||
# Step 5: Test validation
|
||||
print(f"\nStep 5: Testing KPI validation...")
|
||||
shouldProceed, reason = JsonResponseHandler.validateKpiProgression(
|
||||
accumulationState,
|
||||
updatedKpis
|
||||
)
|
||||
|
||||
print(f" Result: shouldProceed={shouldProceed}, reason={reason}")
|
||||
|
||||
if not shouldProceed:
|
||||
print(f"\n❌ VALIDATION FAILED - This is the problem!")
|
||||
print(f" Let's debug why...")
|
||||
|
||||
# Check what's being compared
|
||||
lastValues = {kpi.get("id"): kpi.get("currentValue", 0) for kpi in accumulationState.kpis}
|
||||
print(f" Last values from accumulationState: {lastValues}")
|
||||
|
||||
for updatedKpi in updatedKpis:
|
||||
kpiId = updatedKpi.get("id")
|
||||
currentValue = updatedKpi.get("currentValue", 0)
|
||||
print(f" Updated KPI {kpiId}: currentValue={currentValue}")
|
||||
|
||||
if kpiId in lastValues:
|
||||
lastValue = lastValues[kpiId]
|
||||
print(f" Comparing: {lastValue} vs {currentValue}")
|
||||
if currentValue > lastValue:
|
||||
print(f" ✅ Should detect progress!")
|
||||
else:
|
||||
print(f" ❌ No progress detected (currentValue <= lastValue)")
|
||||
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
# Copyright (c) 2026 PowerOn AG
|
||||
# All rights reserved.
|
||||
"""Test KPI path extraction"""
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add gateway directory to path
|
||||
_gateway_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
if _gateway_path not in sys.path:
|
||||
sys.path.insert(0, _gateway_path)
|
||||
|
||||
from modules.serviceCenter.services.serviceAi.subJsonResponseHandling import JsonResponseHandler
|
||||
|
||||
# Test JSON matching the actual response
|
||||
test_json = {
|
||||
"metadata": {
|
||||
"split_strategy": "single_document",
|
||||
"source_documents": [],
|
||||
"extraction_method": "ai_generation"
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"id": "doc_1",
|
||||
"title": "Prime Numbers Table",
|
||||
"filename": "prime_numbers.json",
|
||||
"sections": [
|
||||
{
|
||||
"id": "section_prime_numbers_table",
|
||||
"content_type": "table",
|
||||
"elements": [
|
||||
{
|
||||
"headers": ["Column 1", "Column 2"],
|
||||
"rows": [
|
||||
[2, 3, 5, 7, 11],
|
||||
[13, 17, 19, 23, 29]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# Test path from KPI definition
|
||||
path = "documents[0].sections[0].elements[0].rows"
|
||||
|
||||
print(f"Testing path: {path}")
|
||||
print(f"JSON structure: documents[0].sections[0].elements[0].rows")
|
||||
print()
|
||||
|
||||
try:
|
||||
value = JsonResponseHandler._extractValueByPath(test_json, path)
|
||||
print(f"✅ Extracted value: {type(value)}")
|
||||
print(f" Value: {value}")
|
||||
|
||||
if isinstance(value, list):
|
||||
count = len(value)
|
||||
print(f" Count: {count}")
|
||||
else:
|
||||
print(f" Not a list!")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
|
@ -30,11 +30,7 @@ _FEATURES_DIR = Path(__file__).resolve().parents[2] / "modules" / "features"
|
|||
|
||||
_BARE_LABEL_PATTERN = re.compile(r'^\s*"label"\s*:\s*"[^"]+"', re.MULTILINE)
|
||||
|
||||
# mainRealEstate.py contains "label": "AA1704" inside a multi-line f-string
|
||||
# that is used as a JSON example in an AI prompt -- not a real catalog entry.
|
||||
_ALLOWED_FILES_WITH_BARE_LABELS: set[str] = {
|
||||
"mainRealEstate.py",
|
||||
}
|
||||
_ALLOWED_FILES_WITH_BARE_LABELS: set[str] = set()
|
||||
|
||||
|
||||
def _findFeatureMainFiles() -> list[Path]:
|
||||
|
|
|
|||
Loading…
Reference in a new issue