|
27 | 27 | Field, |
28 | 28 | FieldSerializationInfo, |
29 | 29 | StringConstraints, |
30 | | - TypeAdapter, |
31 | | - ValidationError, |
32 | 30 | computed_field, |
33 | 31 | field_serializer, |
34 | 32 | field_validator, |
@@ -1595,88 +1593,68 @@ class PictureItem(FloatingItem): |
1595 | 1593 | deprecated("Field `annotations` is deprecated; use `meta` instead."), |
1596 | 1594 | ] = [] |
1597 | 1595 |
|
1598 | | - @model_validator(mode="before") |
1599 | | - @classmethod |
1600 | | - def _migrate_annotations_to_meta(cls, data: Any) -> Any: |
| 1596 | + @model_validator(mode="after") |
| 1597 | + def _migrate_annotations_to_meta(self) -> Self: |
1601 | 1598 | """Migrate the `annotations` field to `meta`.""" |
1602 | | - if isinstance(data, dict) and (annotations := data.get("annotations")): |
| 1599 | + if self.annotations: |
1603 | 1600 | _logger.warning( |
1604 | 1601 | "Migrating deprecated `annotations` to `meta`; this will be removed in the future. " |
1605 | 1602 | "Note that only the first available instance of each annotation type will be migrated." |
1606 | 1603 | ) |
1607 | | - for raw_ann in annotations: |
| 1604 | + for ann in self.annotations: |
1608 | 1605 | # migrate annotations to meta |
1609 | 1606 |
|
1610 | | - try: |
1611 | | - ann: PictureDataType = TypeAdapter(PictureDataType).validate_python( |
1612 | | - raw_ann |
1613 | | - ) |
1614 | | - except ValidationError as e: |
1615 | | - raise e |
1616 | | - |
1617 | 1607 | # ensure meta field is present |
1618 | | - data.setdefault("meta", {}) |
| 1608 | + if self.meta is None: |
| 1609 | + self.meta = PictureMeta() |
1619 | 1610 |
|
1620 | 1611 | if isinstance(ann, PictureClassificationData): |
1621 | | - data["meta"].setdefault( |
1622 | | - MetaFieldName.CLASSIFICATION.value, |
1623 | | - PictureClassificationMetaField( |
1624 | | - predictions=[ |
1625 | | - PictureClassificationPrediction( |
1626 | | - class_name=pred.class_name, |
1627 | | - confidence=pred.confidence, |
1628 | | - created_by=ann.provenance, |
1629 | | - ) |
1630 | | - for pred in ann.predicted_classes |
1631 | | - ], |
1632 | | - ).model_dump(mode="json"), |
| 1612 | + self.meta.classification = PictureClassificationMetaField( |
| 1613 | + predictions=[ |
| 1614 | + PictureClassificationPrediction( |
| 1615 | + class_name=pred.class_name, |
| 1616 | + confidence=pred.confidence, |
| 1617 | + created_by=ann.provenance, |
| 1618 | + ) |
| 1619 | + for pred in ann.predicted_classes |
| 1620 | + ], |
1633 | 1621 | ) |
1634 | 1622 | elif isinstance(ann, DescriptionAnnotation): |
1635 | | - data["meta"].setdefault( |
1636 | | - MetaFieldName.DESCRIPTION.value, |
1637 | | - DescriptionMetaField( |
1638 | | - text=ann.text, |
1639 | | - created_by=ann.provenance, |
1640 | | - ).model_dump(mode="json"), |
| 1623 | + self.meta.description = DescriptionMetaField( |
| 1624 | + text=ann.text, |
| 1625 | + created_by=ann.provenance, |
1641 | 1626 | ) |
1642 | 1627 | elif isinstance(ann, PictureMoleculeData): |
1643 | | - data["meta"].setdefault( |
1644 | | - MetaFieldName.MOLECULE.value, |
1645 | | - MoleculeMetaField( |
1646 | | - smi=ann.smi, |
1647 | | - confidence=ann.confidence, |
1648 | | - created_by=ann.provenance, |
1649 | | - **{ |
1650 | | - MetaUtils._create_migrated_meta_field_name( |
1651 | | - name="segmentation" |
1652 | | - ): ann.segmentation, |
1653 | | - MetaUtils._create_migrated_meta_field_name( |
1654 | | - name="class_name" |
1655 | | - ): ann.class_name, |
1656 | | - }, |
1657 | | - ).model_dump(mode="json"), |
| 1628 | + self.meta.molecule = MoleculeMetaField( |
| 1629 | + smi=ann.smi, |
| 1630 | + confidence=ann.confidence, |
| 1631 | + created_by=ann.provenance, |
| 1632 | + **{ |
| 1633 | + MetaUtils._create_migrated_meta_field_name( |
| 1634 | + name="segmentation" |
| 1635 | + ): ann.segmentation, |
| 1636 | + MetaUtils._create_migrated_meta_field_name( |
| 1637 | + name="class_name" |
| 1638 | + ): ann.class_name, |
| 1639 | + }, |
1658 | 1640 | ) |
1659 | 1641 | elif isinstance(ann, PictureTabularChartData): |
1660 | | - data["meta"].setdefault( |
1661 | | - MetaFieldName.TABULAR_CHART.value, |
1662 | | - TabularChartMetaField( |
1663 | | - title=ann.title, |
1664 | | - chart_data=ann.chart_data, |
1665 | | - ).model_dump(mode="json"), |
1666 | | - ) |
1667 | | - elif isinstance(ann, MiscAnnotation): |
1668 | | - data["meta"].setdefault( |
1669 | | - MetaUtils._create_migrated_meta_field_name(name=ann.kind), |
1670 | | - ann.content, |
| 1642 | + self.meta.tabular_chart = TabularChartMetaField( |
| 1643 | + title=ann.title, |
| 1644 | + chart_data=ann.chart_data, |
1671 | 1645 | ) |
1672 | 1646 | else: |
1673 | | - # fall back to reusing original annotation type name (in namespaced format) |
1674 | | - data["meta"].setdefault( |
1675 | | - MetaUtils._create_migrated_meta_field_name(name=ann.kind), |
1676 | | - ann.model_dump(mode="json"), |
| 1647 | + self.meta.set_custom_field( |
| 1648 | + namespace=MetaUtils._META_FIELD_LEGACY_NAMESPACE, |
| 1649 | + name=ann.kind, |
| 1650 | + value=( |
| 1651 | + ann.content |
| 1652 | + if isinstance(ann, MiscAnnotation) |
| 1653 | + else ann.model_dump(mode="json") |
| 1654 | + ), |
1677 | 1655 | ) |
1678 | 1656 |
|
1679 | | - return data |
| 1657 | + return self |
1680 | 1658 |
|
1681 | 1659 | # Convert the image to Base64 |
1682 | 1660 | def _image_to_base64(self, pil_image, format="PNG"): |
@@ -1829,49 +1807,37 @@ class TableItem(FloatingItem): |
1829 | 1807 | deprecated("Field `annotations` is deprecated; use `meta` instead."), |
1830 | 1808 | ] = [] |
1831 | 1809 |
|
1832 | | - @model_validator(mode="before") |
1833 | | - @classmethod |
1834 | | - def migrate_annotations_to_meta(cls, data: Any) -> Any: |
| 1810 | + @model_validator(mode="after") |
| 1811 | + def _migrate_annotations_to_meta(self) -> Self: |
1835 | 1812 | """Migrate the `annotations` field to `meta`.""" |
1836 | | - if isinstance(data, dict) and (annotations := data.get("annotations")): |
| 1813 | + if self.annotations: |
1837 | 1814 | _logger.warning( |
1838 | 1815 | "Migrating deprecated `annotations` to `meta`; this will be removed in the future. " |
1839 | 1816 | "Note that only the first available instance of each annotation type will be migrated." |
1840 | 1817 | ) |
1841 | | - for raw_ann in annotations: |
1842 | | - # migrate annotations to meta |
1843 | | - |
1844 | | - try: |
1845 | | - ann: TableAnnotationType = TypeAdapter( |
1846 | | - TableAnnotationType |
1847 | | - ).validate_python(raw_ann) |
1848 | | - except ValidationError as e: |
1849 | | - raise e |
| 1818 | + for ann in self.annotations: |
1850 | 1819 |
|
1851 | 1820 | # ensure meta field is present |
1852 | | - data.setdefault("meta", {}) |
| 1821 | + if self.meta is None: |
| 1822 | + self.meta = FloatingMeta() |
1853 | 1823 |
|
1854 | 1824 | if isinstance(ann, DescriptionAnnotation): |
1855 | | - data["meta"].setdefault( |
1856 | | - MetaFieldName.DESCRIPTION.value, |
1857 | | - DescriptionMetaField( |
1858 | | - text=ann.text, |
1859 | | - created_by=ann.provenance, |
1860 | | - ).model_dump(mode="json"), |
1861 | | - ) |
1862 | | - elif isinstance(ann, MiscAnnotation): |
1863 | | - data["meta"].setdefault( |
1864 | | - MetaUtils._create_migrated_meta_field_name(name=ann.kind), |
1865 | | - ann.content, |
| 1825 | + self.meta.description = DescriptionMetaField( |
| 1826 | + text=ann.text, |
| 1827 | + created_by=ann.provenance, |
1866 | 1828 | ) |
1867 | 1829 | else: |
1868 | | - # fall back to reusing original annotation type name (in namespaced format) |
1869 | | - data["meta"].setdefault( |
1870 | | - MetaUtils._create_migrated_meta_field_name(name=ann.kind), |
1871 | | - ann.model_dump(mode="json"), |
| 1830 | + self.meta.set_custom_field( |
| 1831 | + namespace=MetaUtils._META_FIELD_LEGACY_NAMESPACE, |
| 1832 | + name=ann.kind, |
| 1833 | + value=( |
| 1834 | + ann.content |
| 1835 | + if isinstance(ann, MiscAnnotation) |
| 1836 | + else ann.model_dump(mode="json") |
| 1837 | + ), |
1872 | 1838 | ) |
1873 | 1839 |
|
1874 | | - return data |
| 1840 | + return self |
1875 | 1841 |
|
1876 | 1842 | def export_to_dataframe( |
1877 | 1843 | self, doc: Optional["DoclingDocument"] = None |
|
0 commit comments