parse-bench 1.0.6__tar.gz → 1.0.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {parse_bench-1.0.6 → parse_bench-1.0.7}/CHANGELOG.md +7 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/PKG-INFO +1 -1
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/__init__.py +1 -1
- parse_bench-1.0.7/src/parse_bench/evaluation/_registration.py +37 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/layout_adapters/registry.py +11 -13
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/layout_label_mappers/registry.py +12 -13
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_base.py +24 -8
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_formatting.py +41 -11
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/table_record_match_metric.py +48 -76
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/table_splitting.py +65 -41
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/utils.py +12 -12
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/extensions.py +12 -4
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/__init__.py +6 -7
- parse_bench-1.0.7/src/parse_bench/inference/providers/extract/__init__.py +29 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/extract/citations.py +3 -1
- parse_bench-1.0.7/src/parse_bench/inference/providers/layoutdet/__init__.py +33 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/__init__.py +12 -5
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/registry.py +26 -2
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/schemas/extract_output.py +2 -2
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/test_cases/parse_rule_schemas.py +10 -4
- parse_bench-1.0.7/tests/parse_bench/evaluation/metrics/parse/test_attributed_inline_tags.py +95 -0
- parse_bench-1.0.7/tests/parse_bench/evaluation/metrics/parse/test_mark_color_rule.py +87 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_table_splitting.py +158 -0
- parse_bench-1.0.7/tests/parse_bench/test_extensions.py +369 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/test_extract_integration.py +35 -0
- parse_bench-1.0.6/src/parse_bench/inference/providers/extract/__init__.py +0 -22
- parse_bench-1.0.6/src/parse_bench/inference/providers/layoutdet/__init__.py +0 -25
- parse_bench-1.0.6/tests/parse_bench/test_extensions.py +0 -149
- {parse_bench-1.0.6 → parse_bench-1.0.7}/.gitignore +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/LICENSE +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/README.md +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/pyproject.toml +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/analysis/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/analysis/aggregation_report.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/analysis/cli.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/analysis/comparison.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/analysis/comparison_core.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/analysis/comparison_report.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/analysis/detailed_report.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/analysis/leaderboard_report.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/analysis/metric_definitions.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/cli.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/data/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/data/cli.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/data/download.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/data/repetition.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/cli.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/evaluators/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/evaluators/base.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/evaluators/extract.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/evaluators/layoutdet.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/evaluators/parse.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/evaluators/qa.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/layout_adapters/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/layout_adapters/adapters.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/layout_adapters/base.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/layout_label_mappers/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/layout_label_mappers/base.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/layout_label_mappers/mappers.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/layout_label_mappers/projection.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metric_aggregation.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/attribution/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/attribution/constants.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/attribution/core.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/attribution/evaluate.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/attribution/geometry.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/attribution/text_utils.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/base.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/downstream/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/extract/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/extract/json_subset_match.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/extract/json_subset_match_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/extract/list_unwrap.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/extract/rule_based_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/extract/test_rules.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/extract/test_types.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/field_grounding/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/field_grounding/core.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/field_grounding/extract_adapter.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/field_grounding/parse_adapter.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/field_grounding/rule_filters.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/field_grounding/value_compare.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/layoutdet/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/layoutdet/classification_utils.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/layoutdet/furniture.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/layoutdet/iou.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/layoutdet/overlap.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/_vendor_grits_reference.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/chart_json_to_html.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/cross_page_table_consistency.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/emphasis_spans.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/fast_tree_edit.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/grits_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/grits_reference_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/header_accuracy_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/llm_normalization/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/llm_normalization/base.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/llm_normalization/config.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/llm_normalization/postprocess.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/llm_normalization/strategy_judge.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/mermaid_graph.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rule_based_judge_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rule_based_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_bag.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_chart.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_diagram.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_form.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_heading.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_list.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_page_decoration.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_repetition.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_table.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_text.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_watermark.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/structural_consistency_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/table_extraction.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/table_merging.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/table_pairing.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/table_parsing.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/table_title_stripping.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/teds_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/test_rules.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/test_types.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/text_content_projection.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/text_similarity_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/text_v21.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/qa/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/qa/answer_comparison.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/qa/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/qa/llm_service.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/reports/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/reports/csv.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/reports/html.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/reports/markdown.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/reports/rule_csv.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/runner.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/stats.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/geometry/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/geometry/rotated_bbox.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/chunkr_layout_extraction.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/cli.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/layout_extraction.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/pipelines/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/pipelines/extract.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/pipelines/layout.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/pipelines/parse.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/pipelines.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/base.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/cancellation.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/extract/extend.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/extract/llamaextract_v2_api.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/layoutdet/adapters.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/layoutdet/base.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/layoutdet/chandra.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/layoutdet/docling.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/layoutdet/dots_ocr.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/layoutdet/layout_v3.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/layoutdet/layout_v3_byoc.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/layoutdet/paddle.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/layoutdet/qwen3vl.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/layoutdet/surya.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/layoutdet/yolo.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/_docling_common.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/_layout_utils.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/_unlimitedocr2_convert.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/aeddix_alpine_ocr_kdl.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/amazon_nova.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/anthropic.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/anyformat.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/azure_document_intelligence.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/chandra2.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/chunkr.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/cohere_parse.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/databricks_ai_parse.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/datalab.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/deepseek.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/deepseekocr2.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/docai.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/docling.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/docling_serve.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/dots_ocr.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/extend_parse.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/falconocr.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/florin_parser_nano.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/gemma4.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/glm_zai.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/google.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/google_agentic_vision.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/google_docai.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/google_docai_layout_normalization.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/granite_vision.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/hpd_parsing.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/hunyuanocr.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/infinity_parser2.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/jinaocr.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/kdl_frontier_nano.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/landingai.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/lightonocr-3.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/liteparse.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/llamaparse.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/llamaparse_v2_normalization.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/markitdown.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/mineru25.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/mineru2605pro.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/mineru_diffusion.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/minicpm_ocr.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/mistral_ocr.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/nemotron_omni.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/nemotron_parse_3_5.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/nutrient_dws.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/oi_parser.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/openai.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/opendataloader.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/ovisocr2.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/ovisocr3.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/paddleocr.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/pdf_inspector.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/pulse.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/pymupdf.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/pymupdf4llm.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/pypdf.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/qwen.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/rakedoc_nano.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/reducto.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/surya2.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/teleocr.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/tesseract.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/textract.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/unlimitedocr.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/unlimitedocr2.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/unstructured.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/upstage.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/upstage_normalization.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/warp_ingest.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/providers/parse/wevisdoc.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/renormalize.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/inference/runner.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/layout_label_mapping.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/layout_projection.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/pipeline/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/pipeline/cli.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/py.typed +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/schemas/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/schemas/evaluation.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/schemas/layout_detection_output.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/schemas/layout_ontology.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/schemas/metrics.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/schemas/parse_output.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/schemas/pipeline.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/schemas/pipeline_io.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/schemas/product.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/test_cases/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/test_cases/bbox_value_strict_comparator.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/test_cases/extract_field_paths.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/test_cases/layout_attribution_generation.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/test_cases/loader.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/test_cases/rule_filters.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/test_cases/rule_ids.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/test_cases/schema.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/utils/__init__.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/utils/gemini_layout_utils.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/utils/text_aggregation.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/analysis/test_comparison_consistency.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/analysis/test_comparison_core.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/analysis/test_comparison_directory_suffix.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/analysis/test_detailed_report.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/evaluators/test_extract_empty_expected_output.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/evaluators/test_layoutdet_missing_ro_index.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/evaluators/test_parse_evaluator_layout_rule_filter.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/evaluators/test_parse_evaluator_styling_rollup.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/evaluators/test_parse_evaluator_table_pages.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/layout_adapters/test_anyformat_prediction_granularity.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/layout_adapters/test_docling_parse_layout_adapter.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/layout_adapters/test_llamaparse_attribution_scope.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/layout_adapters/test_llamaparse_canonical_layout_pages.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/layout_adapters/test_registry.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/layout_adapters/test_retained_typed_writers.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/layout_adapters/test_rotated_attribution_adapters.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/layout_label_mappers/test_llamaparse_label_mapper.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/layout_label_mappers/test_projection_attributes.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/layout_label_mappers/test_projection_dual_read.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/layout_label_mappers/test_pymupdf4llm_label_mapper.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/attribution/test_attribution_overclaim.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/attribution/test_rotated_attribution.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/extract/test_json_subset_match.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/field_grounding/test_extract_adapter.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/layoutdet/test_average_precision.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/layoutdet/test_classification_utils_paging.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/layoutdet/test_rotated_iou.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_chart_data_point_rule.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_chart_json_to_html.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_chart_label_punctuation.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_cross_page_table_consistency_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_degenerate_marker_rules.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_diagram_rules.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_fast_table_parity.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_form_field_rule.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_formatting_rule_adjacent_spans.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_grits_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_grits_perf_equivalence.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_grits_trm_composite.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_header_accuracy_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_heading_structure_rule.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_latex_arrow_length.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_latex_script_order.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_merge_preceding_titles.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_normalize_cell_text.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_normalize_text_inline_tag_separator.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_page_decoration_rule.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_parse_combining_mark_tokenization.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_parse_formatting_rule_paragraph_spans.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_parse_formatting_rule_quotes.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_parse_formatting_rule_span_scope.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_parse_list_level_rule.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_parse_table_cell_augmentation.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_parse_text_order_rule_html.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_parse_text_presence_rule.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_relaxed_normalize_cell_text.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_repetition_overshoot_rule.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_rule_alarm_thread_context.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_rule_metric_budget_and_bag_images.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_rule_metric_side_inputs.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_table_caption_title_band.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_table_cell_inline_marker_separator.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_table_dot_leaders.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_table_extraction.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_table_marker_cells_rule.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_table_merging_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_table_pairing.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_table_record_match_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_table_row_header_th.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_table_tbody_provenance.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_table_title_stripping.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_teds_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_text_color_rule.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_text_content_projection.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_text_similarity_metric.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_title_hierarchy_inapplicable.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/parse/test_watermark_removal_rule.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/metrics/qa/test_answer_comparison_exact_choice.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/test_cli_detailed_report_nonfatal.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/test_runner_aggregation.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/test_runner_result_files.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/test_runner_worker_timeout.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/evaluation/test_stats.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/geometry/test_rotated_bbox.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/extract/test_extend_cost_stats.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/extract/test_extend_schema_adapter.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_aeddix_alpine_ocr_kdl.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_amazon_nova.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_anthropic_pricing.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_anyformat.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_azure_document_intelligence_layout.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_chandra2_multipage.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_databricks_chart_descriptions.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_databricks_rest.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_datalab.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_deepseekocr2_multipage.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_docai.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_extend_parse_pages.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_falconocr_multipage.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_gemma4_multipage.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_glm_zai.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_google_parse_pricing.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_granite_vision_multipage.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_hpd_parsing.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_hunyuanocr.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_infinity_parser2.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_kdl_frontier_nano.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_layout_coordinate_frames.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_layout_utils.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_lightonocr_3.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_liteparse_layout.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_llamaparse_picture_type.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_llamaparse_polling.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_llamaparse_usage_metadata.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_llamaparse_v2_normalization.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_llamaparse_v2_null_page_fields.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_mineru25_multipage.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_mineru2605pro_multipage.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_mineru_diffusion_multipage.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_minicpm_ocr.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_nemotron_omni_multipage.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_nemotron_parse_3_5.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_nutrient_dws_errors.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_nutrient_dws_markdown.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_openai_parse_errors.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_ovisocr2.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_ovisocr3.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_paddleocr_multipage.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_pymupdf4llm.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_qwen.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_reducto_normalize.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_surya2_multipage.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_teleocr.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_textract_cost.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_unlimitedocr2.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_unlimitedocr_multipage.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_upstage.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_warp_ingest.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/providers/parse/test_wevisdoc.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/test_cli.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/test_layout_extraction.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/test_parse_pipelines.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/test_renormalize.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/inference/test_runner.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/test_cases/test_loader.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/test_cases/test_loader_stem_twins.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/test_cases/test_parse_rule_schemas.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/test_cases/test_rule_ids.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/test_evaluation_schema_extra_fields.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/parse_bench/test_layout_label_mapping_code_alias.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/test_data_dir_routing.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/test_llamaparse_base_url.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/test_pulse_public_api.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/test_repetition_cli.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/test_text_v21.py +0 -0
- {parse_bench-1.0.6 → parse_bench-1.0.7}/tests/test_text_v21_isolation.py +0 -0
|
@@ -66,6 +66,13 @@ All notable changes to `parse-bench` are recorded here. The format follows
|
|
|
66
66
|
now computed with a small numpy implementation that matches
|
|
67
67
|
`sklearn.metrics.average_precision_score` (including tied-score handling),
|
|
68
68
|
so evaluation numbers are unchanged. `scipy` remains a core dependency.
|
|
69
|
+
- Built-in providers now register on the first `create_provider` call instead
|
|
70
|
+
of when `parse_bench.inference.providers` (or any module under it) is
|
|
71
|
+
imported. Importing `parse_bench.extensions` or the layout adapter and label
|
|
72
|
+
mapper registries no longer loads every provider and its SDK: about 0.4 s
|
|
73
|
+
instead of about 4.8 s in a full install. The provider subpackages expose
|
|
74
|
+
`load_providers()` and the registry `load_builtin_providers()`; code that
|
|
75
|
+
read `_PROVIDER_REGISTRY` directly should call the latter first.
|
|
69
76
|
|
|
70
77
|
## [1.0.2] - 2026-09-04
|
|
71
78
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: parse-bench
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.7
|
|
4
4
|
Summary: ParseBench: a benchmark and evaluation harness for document parsing systems on real-world enterprise documents
|
|
5
5
|
Project-URL: Homepage, https://parsebench.ai
|
|
6
6
|
Project-URL: Repository, https://github.com/run-llama/ParseBench
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Shared replacement semantics for keyed layout registrations."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
from typing import Protocol
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class _KeyedRegistration(Protocol):
|
|
8
|
+
@property
|
|
9
|
+
def keys(self) -> tuple[str, ...]: ...
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def updated_registrations[RegistrationT: _KeyedRegistration](
|
|
13
|
+
registrations: Sequence[RegistrationT],
|
|
14
|
+
replacement: RegistrationT,
|
|
15
|
+
*,
|
|
16
|
+
dangerous_override: bool,
|
|
17
|
+
) -> Sequence[RegistrationT]:
|
|
18
|
+
"""Replace at the first matched position, retaining unrelated tie order."""
|
|
19
|
+
requested = set(replacement.keys)
|
|
20
|
+
updated: list[RegistrationT] = []
|
|
21
|
+
inserted = False
|
|
22
|
+
for entry in registrations:
|
|
23
|
+
overlap = requested.intersection(entry.keys)
|
|
24
|
+
if len(overlap) == 0:
|
|
25
|
+
updated.append(entry)
|
|
26
|
+
continue
|
|
27
|
+
if not dangerous_override:
|
|
28
|
+
raise ValueError(f"Layout implementation already registered for keys {sorted(overlap)}")
|
|
29
|
+
omitted = set(entry.keys) - requested
|
|
30
|
+
if len(omitted) > 0:
|
|
31
|
+
raise ValueError(f"Override must include all aliases of the replaced registration: {sorted(omitted)}")
|
|
32
|
+
if not inserted:
|
|
33
|
+
updated.append(replacement)
|
|
34
|
+
inserted = True
|
|
35
|
+
if not inserted:
|
|
36
|
+
updated.append(replacement)
|
|
37
|
+
return updated
|
{parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/layout_adapters/registry.py
RENAMED
|
@@ -4,7 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from collections.abc import Callable
|
|
6
6
|
from dataclasses import dataclass
|
|
7
|
+
from typing import TypeVar
|
|
7
8
|
|
|
9
|
+
from parse_bench.evaluation._registration import updated_registrations
|
|
8
10
|
from parse_bench.evaluation.layout_adapters.base import LayoutAdapter
|
|
9
11
|
from parse_bench.inference.pipelines import get_pipeline
|
|
10
12
|
from parse_bench.schemas.pipeline import PipelineSpec
|
|
@@ -22,27 +24,23 @@ class _LayoutAdapterRegistration:
|
|
|
22
24
|
|
|
23
25
|
_LAYOUT_ADAPTER_REGISTRY: list[_LayoutAdapterRegistration] = []
|
|
24
26
|
|
|
27
|
+
# Bound to the concrete class so the decorator hands back that class, not ``type[LayoutAdapter]``.
|
|
28
|
+
LayoutAdapterT = TypeVar("LayoutAdapterT", bound=type[LayoutAdapter])
|
|
29
|
+
|
|
25
30
|
|
|
26
31
|
def register_layout_adapter(
|
|
27
32
|
*provider_keys: str,
|
|
28
33
|
priority: int = 0,
|
|
29
|
-
|
|
34
|
+
_DANGEROUSLY_OVERRIDE: bool = False,
|
|
35
|
+
) -> Callable[[LayoutAdapterT], LayoutAdapterT]:
|
|
30
36
|
"""Register a layout adapter class for one or more provider keys."""
|
|
31
37
|
if not provider_keys:
|
|
32
38
|
raise ValueError("register_layout_adapter requires at least one provider key")
|
|
33
39
|
|
|
34
|
-
def decorator(cls:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
raise ValueError(f"Layout adapter already registered for provider key '{key}'")
|
|
39
|
-
|
|
40
|
-
_LAYOUT_ADAPTER_REGISTRY.append(
|
|
41
|
-
_LayoutAdapterRegistration(
|
|
42
|
-
keys=tuple(provider_keys),
|
|
43
|
-
priority=priority,
|
|
44
|
-
adapter_cls=cls,
|
|
45
|
-
)
|
|
40
|
+
def decorator(cls: LayoutAdapterT) -> LayoutAdapterT:
|
|
41
|
+
replacement = _LayoutAdapterRegistration(keys=tuple(provider_keys), priority=priority, adapter_cls=cls)
|
|
42
|
+
_LAYOUT_ADAPTER_REGISTRY[:] = updated_registrations(
|
|
43
|
+
_LAYOUT_ADAPTER_REGISTRY, replacement, dangerous_override=_DANGEROUSLY_OVERRIDE
|
|
46
44
|
)
|
|
47
45
|
return cls
|
|
48
46
|
|
{parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/layout_label_mappers/registry.py
RENAMED
|
@@ -4,7 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from collections.abc import Callable
|
|
6
6
|
from dataclasses import dataclass
|
|
7
|
+
from typing import TypeVar
|
|
7
8
|
|
|
9
|
+
from parse_bench.evaluation._registration import updated_registrations
|
|
8
10
|
from parse_bench.evaluation.layout_adapters.registry import resolve_layout_provider_name
|
|
9
11
|
from parse_bench.evaluation.layout_label_mappers.base import (
|
|
10
12
|
LayoutLabelMapper,
|
|
@@ -26,26 +28,23 @@ _LAYOUT_LABEL_MAPPER_REGISTRY: list[_LayoutLabelMapperRegistration] = []
|
|
|
26
28
|
_DEFAULT_LAYOUT_MAPPER_KEY = "__default__"
|
|
27
29
|
|
|
28
30
|
|
|
31
|
+
# Bound to the concrete class so the decorator hands back that class, not ``type[LayoutLabelMapper]``.
|
|
32
|
+
LayoutLabelMapperT = TypeVar("LayoutLabelMapperT", bound=type[LayoutLabelMapper])
|
|
33
|
+
|
|
34
|
+
|
|
29
35
|
def register_layout_label_mapper(
|
|
30
36
|
*mapper_keys: str,
|
|
31
37
|
priority: int = 0,
|
|
32
|
-
|
|
38
|
+
_DANGEROUSLY_OVERRIDE: bool = False,
|
|
39
|
+
) -> Callable[[LayoutLabelMapperT], LayoutLabelMapperT]:
|
|
33
40
|
"""Register a layout label mapper for one or more keys."""
|
|
34
41
|
if not mapper_keys:
|
|
35
42
|
raise ValueError("register_layout_label_mapper requires at least one key")
|
|
36
43
|
|
|
37
|
-
def decorator(cls:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
raise ValueError(f"Layout label mapper already registered for key '{key}'")
|
|
42
|
-
|
|
43
|
-
_LAYOUT_LABEL_MAPPER_REGISTRY.append(
|
|
44
|
-
_LayoutLabelMapperRegistration(
|
|
45
|
-
keys=tuple(mapper_keys),
|
|
46
|
-
priority=priority,
|
|
47
|
-
mapper_cls=cls,
|
|
48
|
-
)
|
|
44
|
+
def decorator(cls: LayoutLabelMapperT) -> LayoutLabelMapperT:
|
|
45
|
+
replacement = _LayoutLabelMapperRegistration(keys=tuple(mapper_keys), priority=priority, mapper_cls=cls)
|
|
46
|
+
_LAYOUT_LABEL_MAPPER_REGISTRY[:] = updated_registrations(
|
|
47
|
+
_LAYOUT_LABEL_MAPPER_REGISTRY, replacement, dangerous_override=_DANGEROUSLY_OVERRIDE
|
|
49
48
|
)
|
|
50
49
|
return cls
|
|
51
50
|
|
{parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_base.py
RENAMED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import logging
|
|
4
4
|
import re
|
|
5
5
|
from collections.abc import Callable
|
|
6
|
+
from dataclasses import dataclass
|
|
6
7
|
from html import unescape
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
from typing import Any
|
|
@@ -494,26 +495,38 @@ class ParseTestRule:
|
|
|
494
495
|
}
|
|
495
496
|
|
|
496
497
|
|
|
497
|
-
|
|
498
|
+
@dataclass(frozen=True)
|
|
499
|
+
class _RuleClassRegistration:
|
|
500
|
+
rule_class: type[ParseTestRule]
|
|
501
|
+
overrides_normalization: bool
|
|
498
502
|
|
|
499
503
|
|
|
500
|
-
|
|
504
|
+
_RULE_CLASS_REGISTRY: dict[str, _RuleClassRegistration] = {}
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
def register_rule_class(
|
|
508
|
+
rule_type: str, rule_class: type["ParseTestRule"], *, _DANGEROUSLY_OVERRIDE: bool = False
|
|
509
|
+
) -> None:
|
|
501
510
|
"""Register the scoring class for an additional rule ``type``.
|
|
502
511
|
|
|
503
512
|
Consulted by :func:`create_test_rule` before the built-in dispatch, so an
|
|
504
513
|
extension can add rule types without editing this module. Pair with
|
|
505
514
|
``parse_rule_schemas.register_parse_rule_model`` so the payload validates.
|
|
506
515
|
"""
|
|
507
|
-
|
|
516
|
+
_validate_rule_class(rule_type, rule_class)
|
|
517
|
+
_RULE_CLASS_REGISTRY[rule_type] = _RuleClassRegistration(rule_class, _DANGEROUSLY_OVERRIDE)
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
def _validate_rule_class(rule_type: str, rule_class: type["ParseTestRule"]) -> None:
|
|
521
|
+
if not isinstance(rule_type, str) or len(rule_type) == 0:
|
|
508
522
|
raise ValueError("rule_type must be a non-empty string")
|
|
509
|
-
if not (isinstance(
|
|
523
|
+
if not (isinstance(rule_class, type) and issubclass(rule_class, ParseTestRule)):
|
|
510
524
|
raise TypeError("rule_class must subclass ParseTestRule")
|
|
511
|
-
_RULE_CLASS_REGISTRY[rule_type] = rule_class
|
|
512
525
|
|
|
513
526
|
|
|
514
527
|
def registered_rule_classes() -> dict[str, type["ParseTestRule"]]:
|
|
515
528
|
"""Snapshot of extension rule classes keyed by rule ``type``."""
|
|
516
|
-
return
|
|
529
|
+
return {rule_type: entry.rule_class for rule_type, entry in _RULE_CLASS_REGISTRY.items()}
|
|
517
530
|
|
|
518
531
|
|
|
519
532
|
_REFERENCE_THUMBNAILER: Callable[[Path], str | None] | None = None
|
|
@@ -643,6 +656,10 @@ def create_test_rule(rule_data: ParseRuleInput) -> "ParseTestRule":
|
|
|
643
656
|
|
|
644
657
|
typed_rule: Any = coerce_parse_rule(rule_data)
|
|
645
658
|
rule_type = get_rule_type(typed_rule)
|
|
659
|
+
registered = _RULE_CLASS_REGISTRY.get(rule_type)
|
|
660
|
+
if registered is not None and registered.overrides_normalization:
|
|
661
|
+
return registered.rule_class(typed_rule)
|
|
662
|
+
|
|
646
663
|
if typed_rule.get("text_normalization") == "text-v2.1":
|
|
647
664
|
from parse_bench.evaluation.metrics.parse.text_v21 import RULE_TYPES, VisibleTextBagRule
|
|
648
665
|
|
|
@@ -652,9 +669,8 @@ def create_test_rule(rule_data: ParseRuleInput) -> "ParseTestRule":
|
|
|
652
669
|
if not rule_type:
|
|
653
670
|
raise ValueError("Rule must have a 'type' field")
|
|
654
671
|
|
|
655
|
-
registered = _RULE_CLASS_REGISTRY.get(rule_type)
|
|
656
672
|
if registered is not None:
|
|
657
|
-
return registered(typed_rule)
|
|
673
|
+
return registered.rule_class(typed_rule)
|
|
658
674
|
|
|
659
675
|
if rule_type in {TestType.PRESENT.value, TestType.ABSENT.value}:
|
|
660
676
|
return TextPresenceRule(typed_rule)
|
{parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/rules_formatting.py
RENAMED
|
@@ -12,7 +12,7 @@ from parse_bench.evaluation.metrics.parse.rules_base import (
|
|
|
12
12
|
is_degenerate_marker_text,
|
|
13
13
|
)
|
|
14
14
|
from parse_bench.evaluation.metrics.parse.test_types import TestType
|
|
15
|
-
from parse_bench.evaluation.metrics.parse.utils import _normalize_quotes, normalize_text
|
|
15
|
+
from parse_bench.evaluation.metrics.parse.utils import _TAG_REST, _normalize_quotes, normalize_text
|
|
16
16
|
from parse_bench.test_cases.parse_rule_schemas import (
|
|
17
17
|
ParseAbsentUnlessStrikeoutRule,
|
|
18
18
|
ParseCodeBlockRule,
|
|
@@ -121,28 +121,28 @@ _STRIP_PATTERNS: dict[str, list[tuple[re.Pattern, str]]] = {
|
|
|
121
121
|
"bold": [
|
|
122
122
|
(re.compile(r"\*\*\*(.+?)\*\*\*", re.DOTALL), r"\1"),
|
|
123
123
|
(re.compile(r"\*\*(.+?)\*\*", re.DOTALL), r"\1"),
|
|
124
|
-
(re.compile(
|
|
124
|
+
(re.compile(rf"</?(?:b|strong){_TAG_REST}", re.IGNORECASE), ""),
|
|
125
125
|
],
|
|
126
126
|
"italic": [
|
|
127
127
|
(re.compile(r"(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)"), r"\1"),
|
|
128
128
|
(re.compile(r"(?<!_)_(?!_)(.+?)(?<!_)_(?!_)"), r"\1"),
|
|
129
|
-
(re.compile(
|
|
129
|
+
(re.compile(rf"</?(?:i|em){_TAG_REST}", re.IGNORECASE), ""),
|
|
130
130
|
],
|
|
131
131
|
"underline": [
|
|
132
|
-
(re.compile(
|
|
132
|
+
(re.compile(rf"</?(?:u|ins){_TAG_REST}", re.IGNORECASE), ""),
|
|
133
133
|
],
|
|
134
134
|
"strikeout": [
|
|
135
135
|
(re.compile(r"~~"), ""),
|
|
136
|
-
(re.compile(
|
|
136
|
+
(re.compile(rf"</?(?:s|del|strike){_TAG_REST}", re.IGNORECASE), ""),
|
|
137
137
|
],
|
|
138
138
|
"mark": [
|
|
139
|
-
(re.compile(
|
|
139
|
+
(re.compile(rf"</?mark{_TAG_REST}", re.IGNORECASE), ""),
|
|
140
140
|
],
|
|
141
141
|
"sup": [
|
|
142
|
-
(re.compile(
|
|
142
|
+
(re.compile(rf"</?sup{_TAG_REST}", re.IGNORECASE), ""),
|
|
143
143
|
],
|
|
144
144
|
"sub": [
|
|
145
|
-
(re.compile(
|
|
145
|
+
(re.compile(rf"</?sub{_TAG_REST}", re.IGNORECASE), ""),
|
|
146
146
|
],
|
|
147
147
|
}
|
|
148
148
|
|
|
@@ -514,6 +514,9 @@ class MarkColorRule(ParseTestRule):
|
|
|
514
514
|
2. The ``<mark>`` tag contains the expected color string in any of its attributes
|
|
515
515
|
(e.g. ``style="background-color: yellow"``, ``background="yellow"``,
|
|
516
516
|
``backgroundColor="yellow"``).
|
|
517
|
+
When the expected color is a hue family name (``yellow``, ``green``, ...),
|
|
518
|
+
a hex, ``rgb()`` or named value in that family also passes
|
|
519
|
+
(``background-color:#ffff00``).
|
|
517
520
|
"""
|
|
518
521
|
|
|
519
522
|
def __init__(self, rule_data: ParseMarkColorRule | dict):
|
|
@@ -533,6 +536,14 @@ class MarkColorRule(ParseTestRule):
|
|
|
533
536
|
raise ValueError("Color field cannot be empty")
|
|
534
537
|
self.color = raw_color.strip().lower()
|
|
535
538
|
|
|
539
|
+
def _attrs_carry_color(self, attrs_str: str) -> bool:
|
|
540
|
+
"""True when the attributes name the expected color, or a highlight
|
|
541
|
+
(background) value is a hex, ``rgb()`` or named color in its hue family
|
|
542
|
+
(adjacent families accepted, as in ``TextColorRule``)."""
|
|
543
|
+
if self.color in attrs_str.lower():
|
|
544
|
+
return True
|
|
545
|
+
return any(_families_match(self.color, f) for f in _highlight_color_families(attrs_str))
|
|
546
|
+
|
|
536
547
|
def run(self, md_content: str, normalized_content: str | None = None) -> tuple[bool, str]:
|
|
537
548
|
"""Check if text is inside a <mark> tag that contains the expected color."""
|
|
538
549
|
escaped_query = re.escape(self.text)
|
|
@@ -549,8 +560,7 @@ class MarkColorRule(ParseTestRule):
|
|
|
549
560
|
if not text_pattern.search(inner_text):
|
|
550
561
|
continue
|
|
551
562
|
|
|
552
|
-
|
|
553
|
-
if self.color in attrs_str.lower():
|
|
563
|
+
if self._attrs_carry_color(attrs_str):
|
|
554
564
|
return True, ""
|
|
555
565
|
|
|
556
566
|
# Fallback: strip other formatting and retry
|
|
@@ -562,7 +572,7 @@ class MarkColorRule(ParseTestRule):
|
|
|
562
572
|
if not text_pattern.search(inner_text):
|
|
563
573
|
continue
|
|
564
574
|
|
|
565
|
-
if self.
|
|
575
|
+
if self._attrs_carry_color(attrs_str):
|
|
566
576
|
return True, ""
|
|
567
577
|
|
|
568
578
|
return (
|
|
@@ -787,6 +797,26 @@ def _extract_color_families(attrs_str: str) -> set[str]:
|
|
|
787
797
|
return families
|
|
788
798
|
|
|
789
799
|
|
|
800
|
+
# Highlight color declarations or attributes: CSS background / background-color,
|
|
801
|
+
# HTML background=, React-style backgroundColor=. Foreground color is excluded.
|
|
802
|
+
_HIGHLIGHT_VALUE_RE = re.compile(r"(?<![\w-])background(?:-?color)?\s*[:=]\s*[\"']?([^;\"'>]+)", re.IGNORECASE)
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
def _highlight_color_families(attrs_str: str) -> set[str]:
|
|
806
|
+
"""Hue families of a tag's highlight (background) colors only: hex, ``rgb()``
|
|
807
|
+
or a named color such as ``gold``. A foreground ``color`` never counts."""
|
|
808
|
+
families: set[str] = set()
|
|
809
|
+
for m in _HIGHLIGHT_VALUE_RE.finditer(attrs_str):
|
|
810
|
+
value = m.group(1)
|
|
811
|
+
families |= _extract_color_families(value)
|
|
812
|
+
for name in re.findall(r"[a-zA-Z]+", value):
|
|
813
|
+
rgb = _NAMED_COLOR_RGB.get(name.lower())
|
|
814
|
+
fam = _rgb_to_hue_family(*rgb) if rgb else None
|
|
815
|
+
if fam:
|
|
816
|
+
families.add(fam)
|
|
817
|
+
return families
|
|
818
|
+
|
|
819
|
+
|
|
790
820
|
class TextColorRule(ParseTestRule):
|
|
791
821
|
"""Test rule verifying that text carries a specific text color.
|
|
792
822
|
|
|
@@ -10,6 +10,8 @@ from __future__ import annotations
|
|
|
10
10
|
|
|
11
11
|
import logging
|
|
12
12
|
import re
|
|
13
|
+
from collections.abc import Sequence
|
|
14
|
+
from dataclasses import replace
|
|
13
15
|
from typing import Any
|
|
14
16
|
|
|
15
17
|
import numpy as np
|
|
@@ -132,87 +134,57 @@ def _normalize_trm_table_text(text: str) -> str:
|
|
|
132
134
|
return _normalize_trm_cell_text(text)
|
|
133
135
|
|
|
134
136
|
|
|
135
|
-
def
|
|
136
|
-
"""Normalize all cell text in a table for comparison.
|
|
137
|
-
|
|
138
|
-
Applies normalize_text() + _normalize_trm_cell_text() to every cell in
|
|
139
|
-
table.data and to col_headers text, producing a new TableData with
|
|
140
|
-
normalized values throughout. Columns whose data cells AND header
|
|
141
|
-
entries are all empty strings after normalization are dropped, and
|
|
142
|
-
remaining column indices are renumbered to stay contiguous.
|
|
143
|
-
"""
|
|
144
|
-
if table.data.size == 0:
|
|
145
|
-
return table
|
|
146
|
-
n_rows, n_cols = table.data.shape
|
|
137
|
+
def _normalize_table_text(table: TableData) -> TableData:
|
|
147
138
|
normalized = np.empty_like(table.data)
|
|
148
|
-
for
|
|
149
|
-
for
|
|
150
|
-
normalized[
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
for col_idx, entries in table.col_headers.items():
|
|
154
|
-
normalized_col_headers[col_idx] = [(row_idx, _normalize_trm_table_text(text)) for row_idx, text in entries]
|
|
155
|
-
normalized_row_headers: dict[int, list[tuple[int, str]]] = {}
|
|
156
|
-
for row_idx, entries in table.row_headers.items():
|
|
157
|
-
normalized_row_headers[row_idx] = [(col_idx, _normalize_trm_table_text(text)) for col_idx, text in entries]
|
|
158
|
-
|
|
159
|
-
# Drop columns whose data cells AND header entries are all literally
|
|
160
|
-
# empty strings after normalization. Such columns add noise to header
|
|
161
|
-
# alignment and inflate the union denominator used by _record_similarity
|
|
162
|
-
# without contributing any signal. Sentinel values like "-" or "n/a"
|
|
163
|
-
# count as real content and are NOT dropped.
|
|
164
|
-
#
|
|
165
|
-
# This runs independently on GT and pred, so the two normalized tables
|
|
166
|
-
# may end up with *different* column counts when (say) GT has an empty
|
|
167
|
-
# column 2 but pred has real content there. That's intentional: record
|
|
168
|
-
# matching is content-driven — ``_record_similarity`` compares columns
|
|
169
|
-
# via the ``column_mapping`` keyed by header text, not by positional
|
|
170
|
-
# index, so differing shapes are fine and the unmapped column on the
|
|
171
|
-
# longer side penalizes the score via ``max(n_gt_cols, n_pred_cols)``.
|
|
172
|
-
def _col_is_empty(c: int) -> bool:
|
|
173
|
-
for r in range(n_rows):
|
|
174
|
-
if str(normalized[r, c]) != "":
|
|
175
|
-
return False
|
|
176
|
-
for _row_idx, text in normalized_col_headers.get(c, []):
|
|
177
|
-
if text != "":
|
|
178
|
-
return False
|
|
179
|
-
return True
|
|
180
|
-
|
|
181
|
-
keep_cols = [c for c in range(n_cols) if not _col_is_empty(c)]
|
|
182
|
-
if len(keep_cols) != n_cols:
|
|
183
|
-
old_to_new = {old: new for new, old in enumerate(keep_cols)}
|
|
184
|
-
normalized = normalized[:, keep_cols]
|
|
185
|
-
normalized_col_headers = {
|
|
186
|
-
old_to_new[c]: normalized_col_headers[c] for c in keep_cols if c in normalized_col_headers
|
|
187
|
-
}
|
|
188
|
-
header_cols = {old_to_new[c] for c in table.header_cols if c in old_to_new}
|
|
189
|
-
header_cells = {(r, old_to_new[c]) for (r, c) in table.header_cells if c in old_to_new}
|
|
190
|
-
normalized_row_headers = {
|
|
191
|
-
row_idx: [(old_to_new[c], text) for c, text in entries if c in old_to_new]
|
|
192
|
-
for row_idx, entries in normalized_row_headers.items()
|
|
193
|
-
}
|
|
194
|
-
else:
|
|
195
|
-
header_cols = table.header_cols
|
|
196
|
-
header_cells = table.header_cells
|
|
197
|
-
|
|
198
|
-
return TableData(
|
|
139
|
+
for row in range(table.data.shape[0]):
|
|
140
|
+
for col in range(table.data.shape[1]):
|
|
141
|
+
normalized[row, col] = _normalize_trm_table_text(str(table.data[row, col]))
|
|
142
|
+
return replace(
|
|
143
|
+
table,
|
|
199
144
|
data=normalized,
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
column_scope_rows=table.column_scope_rows,
|
|
209
|
-
row_scope_rows=table.row_scope_rows,
|
|
210
|
-
caption=table.caption,
|
|
211
|
-
context_before=table.context_before,
|
|
212
|
-
context_after=table.context_after,
|
|
145
|
+
col_headers={
|
|
146
|
+
col: [(row, _normalize_trm_table_text(text)) for row, text in entries]
|
|
147
|
+
for col, entries in table.col_headers.items()
|
|
148
|
+
},
|
|
149
|
+
row_headers={
|
|
150
|
+
row: [(col, _normalize_trm_table_text(text)) for col, text in entries]
|
|
151
|
+
for row, entries in table.row_headers.items()
|
|
152
|
+
},
|
|
213
153
|
)
|
|
214
154
|
|
|
215
155
|
|
|
156
|
+
def _select_table_columns(table: TableData, columns: Sequence[int]) -> TableData:
|
|
157
|
+
old_to_new = {old: new for new, old in enumerate(columns)}
|
|
158
|
+
return replace(
|
|
159
|
+
table,
|
|
160
|
+
data=table.data[:, list(columns)],
|
|
161
|
+
header_cols={old_to_new[col] for col in table.header_cols if col in old_to_new},
|
|
162
|
+
col_headers={old_to_new[col]: entries for col, entries in table.col_headers.items() if col in old_to_new},
|
|
163
|
+
row_headers={
|
|
164
|
+
row: [(old_to_new[col], text) for col, text in entries if col in old_to_new]
|
|
165
|
+
for row, entries in table.row_headers.items()
|
|
166
|
+
},
|
|
167
|
+
header_cells={(row, old_to_new[col]) for row, col in table.header_cells if col in old_to_new},
|
|
168
|
+
spanned_cells={(row, old_to_new[col]) for row, col in table.spanned_cells if col in old_to_new},
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def normalize_table(table: TableData, *, preserve_text: bool = False) -> TableData:
|
|
173
|
+
"""Drop normalized-empty columns, returning normalized or original text."""
|
|
174
|
+
if table.data.size == 0:
|
|
175
|
+
return table
|
|
176
|
+
normalized = _normalize_table_text(table)
|
|
177
|
+
# Both representations use normalized emptiness, including header text.
|
|
178
|
+
# Sentinel values such as "-" and "n/a" remain real content.
|
|
179
|
+
columns = [
|
|
180
|
+
col
|
|
181
|
+
for col in range(normalized.data.shape[1])
|
|
182
|
+
if any(value != "" for value in normalized.data[:, col])
|
|
183
|
+
or any(text != "" for _, text in normalized.col_headers.get(col, []))
|
|
184
|
+
]
|
|
185
|
+
return _select_table_columns(table if preserve_text else normalized, columns)
|
|
186
|
+
|
|
187
|
+
|
|
216
188
|
def cell_score(expected: str, actual: str) -> float:
|
|
217
189
|
"""Score similarity between two cell values: 1.0 for match, 0.0 otherwise.
|
|
218
190
|
|
{parse_bench-1.0.6 → parse_bench-1.0.7}/src/parse_bench/evaluation/metrics/parse/table_splitting.py
RENAMED
|
@@ -22,7 +22,7 @@ circular import with ``table_record_match_metric``.
|
|
|
22
22
|
from __future__ import annotations
|
|
23
23
|
|
|
24
24
|
import itertools
|
|
25
|
-
from dataclasses import dataclass
|
|
25
|
+
from dataclasses import dataclass, replace
|
|
26
26
|
from typing import TYPE_CHECKING
|
|
27
27
|
|
|
28
28
|
from rapidfuzz import fuzz
|
|
@@ -99,50 +99,56 @@ def _detect_period_candidates(
|
|
|
99
99
|
return candidates
|
|
100
100
|
|
|
101
101
|
|
|
102
|
+
def _trim_trailing_padding(table: TableData) -> TableData:
|
|
103
|
+
"""Remove only empty tail rows, preserving metadata for retained rows."""
|
|
104
|
+
end = table.data.shape[0]
|
|
105
|
+
# Metadata can carry header text even when the grid cell is empty.
|
|
106
|
+
header_text_rows = {
|
|
107
|
+
r for entries in table.col_headers.values() for r, text in entries if len(str(text).strip()) > 0
|
|
108
|
+
}
|
|
109
|
+
header_text_rows.update(
|
|
110
|
+
r for r, entries in table.row_headers.items() if any(len(str(text).strip()) > 0 for _, text in entries)
|
|
111
|
+
)
|
|
112
|
+
while (
|
|
113
|
+
end > 0
|
|
114
|
+
and end - 1 not in header_text_rows
|
|
115
|
+
and not any(len(str(value).strip()) > 0 for value in table.data[end - 1])
|
|
116
|
+
):
|
|
117
|
+
end -= 1
|
|
118
|
+
if end == table.data.shape[0]:
|
|
119
|
+
return table
|
|
120
|
+
row_sets = ("header_rows", "thead_rows", "tbody_rows", "tfoot_rows", "column_scope_rows", "row_scope_rows")
|
|
121
|
+
return replace(
|
|
122
|
+
table,
|
|
123
|
+
data=table.data[:end],
|
|
124
|
+
**{name: {r for r in getattr(table, name) if r < end} for name in row_sets},
|
|
125
|
+
col_headers={c: [(r, text) for r, text in entries if r < end] for c, entries in table.col_headers.items()},
|
|
126
|
+
row_headers={r: entries for r, entries in table.row_headers.items() if r < end},
|
|
127
|
+
header_cells={(r, c) for r, c in table.header_cells if r < end},
|
|
128
|
+
spanned_cells={(r, c) for r, c in table.spanned_cells if r < end},
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
102
132
|
def build_sub_table(
|
|
103
133
|
pred_table: TableData,
|
|
104
134
|
start: int,
|
|
105
135
|
end: int,
|
|
106
136
|
) -> TableData:
|
|
107
|
-
"""
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
sub_header_cols: set[int] = set()
|
|
123
|
-
for new_c, old_c in enumerate(range(start, end)):
|
|
124
|
-
if old_c in pred_table.col_headers:
|
|
125
|
-
sub_col_headers[new_c] = pred_table.col_headers[old_c]
|
|
126
|
-
if old_c in pred_table.header_cols:
|
|
127
|
-
sub_header_cols.add(new_c)
|
|
128
|
-
|
|
129
|
-
sub_header_cells: set[tuple[int, int]] = set()
|
|
130
|
-
for r, c in pred_table.header_cells:
|
|
131
|
-
if start <= c < end and r < last_nonempty:
|
|
132
|
-
sub_header_cells.add((r, c - start))
|
|
133
|
-
|
|
134
|
-
return TableData(
|
|
135
|
-
data=sub_data,
|
|
136
|
-
header_rows=pred_table.header_rows.copy(),
|
|
137
|
-
header_cols=sub_header_cols,
|
|
138
|
-
col_headers=sub_col_headers,
|
|
139
|
-
row_headers={},
|
|
140
|
-
header_cells=sub_header_cells,
|
|
141
|
-
thead_rows=set(pred_table.thead_rows),
|
|
142
|
-
tbody_rows={r for r in pred_table.tbody_rows if r < last_nonempty},
|
|
143
|
-
tfoot_rows={r for r in pred_table.tfoot_rows if r < last_nonempty},
|
|
144
|
-
column_scope_rows={r for r in pred_table.column_scope_rows if r < last_nonempty},
|
|
145
|
-
row_scope_rows={r for r in pred_table.row_scope_rows if r < last_nonempty},
|
|
137
|
+
"""Slice columns and trim blank tail rows without losing header relationships."""
|
|
138
|
+
return _trim_trailing_padding(
|
|
139
|
+
replace(
|
|
140
|
+
pred_table,
|
|
141
|
+
data=pred_table.data[:, start:end],
|
|
142
|
+
header_cols={c - start for c in pred_table.header_cols if start <= c < end},
|
|
143
|
+
col_headers={c - start: entries for c, entries in pred_table.col_headers.items() if start <= c < end},
|
|
144
|
+
row_headers={
|
|
145
|
+
r: [(c - start, text) for c, text in entries if start <= c < end]
|
|
146
|
+
for r, entries in pred_table.row_headers.items()
|
|
147
|
+
if any(start <= c < end for c, _ in entries)
|
|
148
|
+
},
|
|
149
|
+
header_cells={(r, c - start) for r, c in pred_table.header_cells if start <= c < end},
|
|
150
|
+
spanned_cells={(r, c - start) for r, c in pred_table.spanned_cells if start <= c < end},
|
|
151
|
+
)
|
|
146
152
|
)
|
|
147
153
|
|
|
148
154
|
|
|
@@ -283,8 +289,15 @@ def split_ambiguous_merged_pred(
|
|
|
283
289
|
sub-tables emitted from a split have ``raw_html=""`` since they have no
|
|
284
290
|
meaningful HTML to attribute back to the source.
|
|
285
291
|
|
|
292
|
+
When a split is applied, normalize trailing blank padding on both sides.
|
|
293
|
+
The peer ``expected`` list is updated in place with replacement tables;
|
|
294
|
+
original TableData objects and source HTML remain unchanged. No-split
|
|
295
|
+
calls leave both inputs untouched.
|
|
296
|
+
|
|
286
297
|
Returns ``(possibly_rewritten_actual, did_split)``.
|
|
287
298
|
"""
|
|
299
|
+
from parse_bench.evaluation.metrics.parse.table_record_match_metric import normalize_table
|
|
300
|
+
|
|
288
301
|
if len(expected) <= len(actual):
|
|
289
302
|
return actual, False
|
|
290
303
|
|
|
@@ -297,5 +310,16 @@ def split_ambiguous_merged_pred(
|
|
|
297
310
|
if opt.sub_tables is None:
|
|
298
311
|
new_actual.append(original)
|
|
299
312
|
else:
|
|
300
|
-
|
|
313
|
+
# Keep the candidate geometry: normalization may remove spacer
|
|
314
|
+
# columns, so its offsets cannot slice the original grid directly.
|
|
315
|
+
source = normalize_table(original.table_data, preserve_text=True)
|
|
316
|
+
new_actual.extend(
|
|
317
|
+
ExtractedTable(
|
|
318
|
+
raw_html="",
|
|
319
|
+
table_data=build_sub_table(source, i * opt.period, (i + 1) * opt.period),
|
|
320
|
+
)
|
|
321
|
+
for i in range(opt.n_segments)
|
|
322
|
+
)
|
|
323
|
+
expected[:] = [replace(t, table_data=_trim_trailing_padding(t.table_data)) for t in expected]
|
|
324
|
+
new_actual = [replace(t, table_data=_trim_trailing_padding(t.table_data)) for t in new_actual]
|
|
301
325
|
return new_actual, True
|