docpull 6.0.1__tar.gz → 6.1.0__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.
- {docpull-6.0.1/src/docpull.egg-info → docpull-6.1.0}/PKG-INFO +31 -7
- {docpull-6.0.1 → docpull-6.1.0}/README.md +19 -1
- {docpull-6.0.1 → docpull-6.1.0}/pyproject.toml +13 -6
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/__init__.py +1 -1
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/benchmark.py +2 -2
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/cli.py +35 -1
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/conversion/special_cases.py +148 -8
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/conversion/trafilatura_extractor.py +1 -1
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/core/fetcher.py +12 -0
- docpull-6.1.0/src/docpull/document_parse.py +1204 -0
- docpull-6.1.0/src/docpull/document_worker.py +137 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/mcp/server.py +59 -4
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/mcp/tools.py +17 -3
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/models/config.py +22 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/steps/convert.py +76 -26
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/steps/fetch.py +6 -1
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/steps/metadata.py +4 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/security/download_policy.py +24 -3
- {docpull-6.0.1 → docpull-6.1.0/src/docpull.egg-info}/PKG-INFO +31 -7
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull.egg-info/SOURCES.txt +2 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull.egg-info/requires.txt +10 -3
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_ci_policy.py +46 -2
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_cli.py +12 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_convert_step_new.py +75 -0
- docpull-6.1.0/tests/test_document_parse.py +634 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_mcp_server.py +9 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_release_a_plus_check_script.py +18 -0
- docpull-6.1.0/tests/test_reproducible_release_build.py +179 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_security_hardening.py +40 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_special_cases.py +142 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_surface_contract.py +3 -0
- docpull-6.0.1/src/docpull/document_parse.py +0 -643
- docpull-6.0.1/tests/test_document_parse.py +0 -133
- {docpull-6.0.1 → docpull-6.1.0}/LICENSE +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/setup.cfg +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/__main__.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/accounting.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/agent_publish.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/auth_cli.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/basis.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/cache/__init__.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/cache/frontier.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/cache/manager.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/cache/streaming_dedup.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_aliases.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_ci.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/__init__.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/_legacy_cli.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/brand.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/cli.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/common.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/dataset.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/feed.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/openapi.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/package.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/paper.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/product.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/repo.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/schema_extract.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/search.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/standards.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/styleguide.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/transcript.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/typed.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/typed_models.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/visuals.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/context_packs/wiki.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/conversion/__init__.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/conversion/article_cleanup.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/conversion/chunking.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/conversion/ensemble.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/conversion/extractor.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/conversion/filings.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/conversion/markdown.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/conversion/protocols.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/core/__init__.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/discovery/__init__.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/discovery/_fetch.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/discovery/composite.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/discovery/contracts.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/discovery/crawler.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/discovery/filters.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/discovery/link_extractors/__init__.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/discovery/link_extractors/enhanced.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/discovery/link_extractors/protocols.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/discovery/link_extractors/static.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/discovery/protocols.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/discovery/sitemap.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/discovery_cli.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/doctor.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/eval_grade.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/evidence_pack.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/exports.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/fixtures/__init__.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/fixtures/parallel-search-extract.json +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/free_core.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/free_core_smoke.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/graph.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/hosted.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/http/__init__.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/http/client.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/http/protocols.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/http/rate_limiter.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/judge.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/local_workflows.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/mcp/__init__.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/mcp/sources.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/metadata_extractor.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/models/__init__.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/models/document.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/models/events.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/models/profiles.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/models/run.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/monitor.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/output_contract.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pack_reader.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pack_tools.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/parallel_workflows.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/parity.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/parity_cli.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/passk.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/__init__.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/base.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/manifest.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/steps/__init__.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/steps/chunk.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/steps/dedup.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/steps/render.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/steps/save.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/steps/save_json.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/steps/save_ndjson.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/steps/save_okf.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/steps/save_sqlite.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/pipeline/steps/validate.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/policy.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/policy_cli.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/project.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/provider_adapters.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/provider_capabilities.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/provider_cli.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/provider_keys.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/provider_probes.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/py.typed +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/redaction.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/rendering.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/scraper.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/security/__init__.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/security/robots.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/security/url_validator.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/server.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/share.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/skill_export.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/source_scoring.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/surface.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull/time_utils.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull.egg-info/dependency_links.txt +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull.egg-info/entry_points.txt +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/src/docpull.egg-info/top_level.txt +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_accounting.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_auth_cli.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_basis.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_benchmark.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_cache_conditional_get.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_chunking.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_claim_audit_script.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_context_ci.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_context_packs.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_conversion.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_discovery.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_discovery_contracts.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_doctor.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_document_record.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_evidence_pack.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_exports.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_extractor_ensemble.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_feed_pack.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_free_core.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_frontier_resume.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_graph.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_hosted.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_integration.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_judge.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_link_extractors.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_live_web_smoke.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_local_workflows.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_mcp_tools.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_metadata_extractor.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_monitor.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_naming.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_openapi_pack.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_optional_extras_installed.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_output_contract.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_outputs_e2e.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_pack_server.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_pack_tools.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_parallel_workflows.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_parity_workflows.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_passk.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_pipeline.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_policy.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_policy_cli.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_project.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_provider_adapters.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_provider_cli.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_provider_keys.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_provider_probes.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_public_feature_smoke.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_rate_limiter.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_real_feature_smoke_script.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_real_site_regressions.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_rendering.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_save_ndjson.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_save_sqlite.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_share.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_source_scoring.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_time_utils.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_trafilatura_extractor.py +0 -0
- {docpull-6.0.1 → docpull-6.1.0}/tests/test_typed_knowledge_packs.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docpull
|
|
3
|
-
Version: 6.0
|
|
3
|
+
Version: 6.1.0
|
|
4
4
|
Summary: Declare, sync, diff, and lock context dependencies for AI agents
|
|
5
5
|
Author-email: Zachary Roth <support@raintree.technology>
|
|
6
6
|
Maintainer-email: Raintree Technology <support@raintree.technology>
|
|
7
7
|
License-Expression: MIT
|
|
8
|
-
Project-URL: Homepage, https://
|
|
9
|
-
Project-URL: Documentation, https://
|
|
8
|
+
Project-URL: Homepage, https://github.com/raintree-technology/docpull
|
|
9
|
+
Project-URL: Documentation, https://github.com/raintree-technology/docpull#readme
|
|
10
10
|
Project-URL: Repository, https://github.com/raintree-technology/docpull
|
|
11
11
|
Project-URL: Source Code, https://github.com/raintree-technology/docpull
|
|
12
12
|
Project-URL: Bug Tracker, https://github.com/raintree-technology/docpull/issues
|
|
@@ -71,11 +71,16 @@ Requires-Dist: uvicorn>=0.30.0; extra == "serve"
|
|
|
71
71
|
Provides-Extra: parquet
|
|
72
72
|
Requires-Dist: pyarrow>=16.0.0; extra == "parquet"
|
|
73
73
|
Provides-Extra: markitdown
|
|
74
|
-
Requires-Dist:
|
|
74
|
+
Requires-Dist: pypdf>=6.14.2; extra == "markitdown"
|
|
75
|
+
Requires-Dist: markitdown[docx,pdf]>=0.1.0; extra == "markitdown"
|
|
75
76
|
Provides-Extra: unstructured
|
|
77
|
+
Requires-Dist: pypdf>=6.14.2; extra == "unstructured"
|
|
76
78
|
Requires-Dist: unstructured[all-docs]>=0.16.0; extra == "unstructured"
|
|
79
|
+
Provides-Extra: pdf
|
|
80
|
+
Requires-Dist: pypdf>=6.14.2; extra == "pdf"
|
|
77
81
|
Provides-Extra: parse
|
|
78
|
-
Requires-Dist:
|
|
82
|
+
Requires-Dist: pypdf>=6.14.2; extra == "parse"
|
|
83
|
+
Requires-Dist: markitdown[docx,pdf]>=0.1.0; extra == "parse"
|
|
79
84
|
Requires-Dist: unstructured[all-docs]>=0.16.0; extra == "parse"
|
|
80
85
|
Provides-Extra: presidio
|
|
81
86
|
Requires-Dist: presidio-analyzer>=2.2.0; extra == "presidio"
|
|
@@ -96,7 +101,8 @@ Requires-Dist: python-multipart>=0.0.27; extra == "all"
|
|
|
96
101
|
Requires-Dist: starlette>=1.3.1; extra == "all"
|
|
97
102
|
Requires-Dist: uvicorn>=0.30.0; extra == "all"
|
|
98
103
|
Requires-Dist: pyarrow>=16.0.0; extra == "all"
|
|
99
|
-
Requires-Dist:
|
|
104
|
+
Requires-Dist: pypdf>=6.14.2; extra == "all"
|
|
105
|
+
Requires-Dist: markitdown[docx,pdf]>=0.1.0; extra == "all"
|
|
100
106
|
Requires-Dist: unstructured[all-docs]>=0.16.0; extra == "all"
|
|
101
107
|
Requires-Dist: presidio-analyzer>=2.2.0; extra == "all"
|
|
102
108
|
Requires-Dist: e2b>=2.0.0; extra == "all"
|
|
@@ -181,6 +187,12 @@ pages such as blogs, API references, OpenAPI specs, changelogs, vendor pages,
|
|
|
181
187
|
product pages, filings, docs sites, and other pages where the useful content is
|
|
182
188
|
available in HTML or embedded page data.
|
|
183
189
|
|
|
190
|
+
Direct fetches also recognize standards-style plain text and common textual
|
|
191
|
+
formats from their response media type, including extensionless URLs. Remote
|
|
192
|
+
documents remain denied by default; explicitly opt into local PDF parsing with
|
|
193
|
+
`docpull URL --remote-documents pdf` after installing `docpull[markitdown]` or
|
|
194
|
+
`docpull[parse]`. This does not enable a browser, cloud parser, or paid route.
|
|
195
|
+
|
|
184
196
|
DocPull is browser-free by default. JS-only pages are skipped with a clear
|
|
185
197
|
reason unless you explicitly opt into a local renderer. See
|
|
186
198
|
[Web Source Boundary](docs/scraping-boundary.md) and
|
|
@@ -592,6 +604,18 @@ MarkItDown or Unstructured parsers for complex office/PDF files when installed.
|
|
|
592
604
|
Install `docpull[markitdown]`, `docpull[unstructured]`, or `docpull[parse]`
|
|
593
605
|
for those backends.
|
|
594
606
|
|
|
607
|
+
An HTTPS PDF can enter the ordinary fetch contract only with explicit consent:
|
|
608
|
+
|
|
609
|
+
```bash
|
|
610
|
+
docpull https://example.com/handbook.pdf --remote-documents pdf \
|
|
611
|
+
--remote-document-backend auto -o ./packs/handbook
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
The response must identify as PDF and contain a PDF signature. DocPull parses
|
|
615
|
+
it locally through a mode-`0600` temporary file, records the source hash and
|
|
616
|
+
parser provenance, and removes the temporary source. Other remote download
|
|
617
|
+
types remain blocked.
|
|
618
|
+
|
|
595
619
|
Every file-backed run writes `corpus.manifest.json` with stable document IDs,
|
|
596
620
|
chunk IDs, hashes, output paths, and chunk counts. See
|
|
597
621
|
[Corpus Manifest](docs/corpus-manifest.md).
|
|
@@ -754,7 +778,7 @@ docpull URL --preview-urls
|
|
|
754
778
|
|
|
755
779
|
## Links
|
|
756
780
|
|
|
757
|
-
- [
|
|
781
|
+
- [Documentation](https://github.com/raintree-technology/docpull#readme)
|
|
758
782
|
- [PyPI](https://pypi.org/project/docpull/)
|
|
759
783
|
- [GitHub](https://github.com/raintree-technology/docpull)
|
|
760
784
|
- [Metrics](METRICS.md)
|
|
@@ -63,6 +63,12 @@ pages such as blogs, API references, OpenAPI specs, changelogs, vendor pages,
|
|
|
63
63
|
product pages, filings, docs sites, and other pages where the useful content is
|
|
64
64
|
available in HTML or embedded page data.
|
|
65
65
|
|
|
66
|
+
Direct fetches also recognize standards-style plain text and common textual
|
|
67
|
+
formats from their response media type, including extensionless URLs. Remote
|
|
68
|
+
documents remain denied by default; explicitly opt into local PDF parsing with
|
|
69
|
+
`docpull URL --remote-documents pdf` after installing `docpull[markitdown]` or
|
|
70
|
+
`docpull[parse]`. This does not enable a browser, cloud parser, or paid route.
|
|
71
|
+
|
|
66
72
|
DocPull is browser-free by default. JS-only pages are skipped with a clear
|
|
67
73
|
reason unless you explicitly opt into a local renderer. See
|
|
68
74
|
[Web Source Boundary](docs/scraping-boundary.md) and
|
|
@@ -474,6 +480,18 @@ MarkItDown or Unstructured parsers for complex office/PDF files when installed.
|
|
|
474
480
|
Install `docpull[markitdown]`, `docpull[unstructured]`, or `docpull[parse]`
|
|
475
481
|
for those backends.
|
|
476
482
|
|
|
483
|
+
An HTTPS PDF can enter the ordinary fetch contract only with explicit consent:
|
|
484
|
+
|
|
485
|
+
```bash
|
|
486
|
+
docpull https://example.com/handbook.pdf --remote-documents pdf \
|
|
487
|
+
--remote-document-backend auto -o ./packs/handbook
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
The response must identify as PDF and contain a PDF signature. DocPull parses
|
|
491
|
+
it locally through a mode-`0600` temporary file, records the source hash and
|
|
492
|
+
parser provenance, and removes the temporary source. Other remote download
|
|
493
|
+
types remain blocked.
|
|
494
|
+
|
|
477
495
|
Every file-backed run writes `corpus.manifest.json` with stable document IDs,
|
|
478
496
|
chunk IDs, hashes, output paths, and chunk counts. See
|
|
479
497
|
[Corpus Manifest](docs/corpus-manifest.md).
|
|
@@ -636,7 +654,7 @@ docpull URL --preview-urls
|
|
|
636
654
|
|
|
637
655
|
## Links
|
|
638
656
|
|
|
639
|
-
- [
|
|
657
|
+
- [Documentation](https://github.com/raintree-technology/docpull#readme)
|
|
640
658
|
- [PyPI](https://pypi.org/project/docpull/)
|
|
641
659
|
- [GitHub](https://github.com/raintree-technology/docpull)
|
|
642
660
|
- [Metrics](METRICS.md)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "docpull"
|
|
7
|
-
version = "6.0
|
|
7
|
+
version = "6.1.0"
|
|
8
8
|
dynamic = []
|
|
9
9
|
description = "Declare, sync, diff, and lock context dependencies for AI agents"
|
|
10
10
|
readme = {file = "README.md", content-type = "text/markdown"}
|
|
@@ -123,13 +123,19 @@ parquet = [
|
|
|
123
123
|
"pyarrow>=16.0.0",
|
|
124
124
|
]
|
|
125
125
|
markitdown = [
|
|
126
|
-
"
|
|
126
|
+
"pypdf>=6.14.2",
|
|
127
|
+
"markitdown[docx,pdf]>=0.1.0",
|
|
127
128
|
]
|
|
128
129
|
unstructured = [
|
|
130
|
+
"pypdf>=6.14.2",
|
|
129
131
|
"unstructured[all-docs]>=0.16.0",
|
|
130
132
|
]
|
|
133
|
+
pdf = [
|
|
134
|
+
"pypdf>=6.14.2",
|
|
135
|
+
]
|
|
131
136
|
parse = [
|
|
132
|
-
"
|
|
137
|
+
"pypdf>=6.14.2",
|
|
138
|
+
"markitdown[docx,pdf]>=0.1.0",
|
|
133
139
|
"unstructured[all-docs]>=0.16.0",
|
|
134
140
|
]
|
|
135
141
|
presidio = [
|
|
@@ -154,7 +160,8 @@ all = [
|
|
|
154
160
|
"starlette>=1.3.1",
|
|
155
161
|
"uvicorn>=0.30.0",
|
|
156
162
|
"pyarrow>=16.0.0",
|
|
157
|
-
"
|
|
163
|
+
"pypdf>=6.14.2",
|
|
164
|
+
"markitdown[docx,pdf]>=0.1.0",
|
|
158
165
|
"unstructured[all-docs]>=0.16.0",
|
|
159
166
|
"presidio-analyzer>=2.2.0",
|
|
160
167
|
"e2b>=2.0.0",
|
|
@@ -179,8 +186,8 @@ dev = [
|
|
|
179
186
|
docpull = "docpull.cli:main"
|
|
180
187
|
|
|
181
188
|
[project.urls]
|
|
182
|
-
Homepage = "https://
|
|
183
|
-
Documentation = "https://
|
|
189
|
+
Homepage = "https://github.com/raintree-technology/docpull"
|
|
190
|
+
Documentation = "https://github.com/raintree-technology/docpull#readme"
|
|
184
191
|
Repository = "https://github.com/raintree-technology/docpull"
|
|
185
192
|
"Source Code" = "https://github.com/raintree-technology/docpull"
|
|
186
193
|
"Bug Tracker" = "https://github.com/raintree-technology/docpull/issues"
|
|
@@ -200,8 +200,8 @@ TOOL_DOC_TARGETS: tuple[_BenchmarkTarget, ...] = (
|
|
|
200
200
|
_BenchmarkTarget(
|
|
201
201
|
id="docpull_docs",
|
|
202
202
|
label="DocPull docs",
|
|
203
|
-
url="https://
|
|
204
|
-
include_domains=("
|
|
203
|
+
url="https://github.com/raintree-technology/docpull",
|
|
204
|
+
include_domains=("github.com",),
|
|
205
205
|
objective="Build an agent context pack for DocPull documentation",
|
|
206
206
|
queries=("DocPull documentation CLI provider benchmark docs",),
|
|
207
207
|
freshness_terms=("changelog", "release", "benchmark"),
|
|
@@ -335,6 +335,32 @@ Examples:
|
|
|
335
335
|
action="store_true",
|
|
336
336
|
help="Stream NDJSON records to stdout as each page completes (implies --format ndjson)",
|
|
337
337
|
)
|
|
338
|
+
parser.add_argument(
|
|
339
|
+
"--remote-documents",
|
|
340
|
+
choices=["off", "pdf"],
|
|
341
|
+
default=None,
|
|
342
|
+
help="Explicitly download and locally parse selected remote document types (default: off)",
|
|
343
|
+
)
|
|
344
|
+
parser.add_argument(
|
|
345
|
+
"--remote-document-backend",
|
|
346
|
+
choices=["auto", "pypdf", "markitdown", "unstructured"],
|
|
347
|
+
default=None,
|
|
348
|
+
help="Local parser backend for --remote-documents (default: auto)",
|
|
349
|
+
)
|
|
350
|
+
parser.add_argument(
|
|
351
|
+
"--remote-document-timeout-seconds",
|
|
352
|
+
type=int,
|
|
353
|
+
default=None,
|
|
354
|
+
metavar="SECONDS",
|
|
355
|
+
help="Wall-time limit for each isolated remote-document parser (default: 60)",
|
|
356
|
+
)
|
|
357
|
+
parser.add_argument(
|
|
358
|
+
"--remote-document-memory-mib",
|
|
359
|
+
type=int,
|
|
360
|
+
default=None,
|
|
361
|
+
metavar="MIB",
|
|
362
|
+
help="Address-space limit for each isolated remote-document parser (default: 1024)",
|
|
363
|
+
)
|
|
338
364
|
|
|
339
365
|
# Crawl settings
|
|
340
366
|
crawl_group = parser.add_argument_group("crawl settings")
|
|
@@ -677,6 +703,14 @@ def run_fetcher(args: argparse.Namespace) -> int:
|
|
|
677
703
|
filter_kwargs["enable_special_cases"] = False
|
|
678
704
|
if args.strict_js_required:
|
|
679
705
|
filter_kwargs["strict_js_required"] = True
|
|
706
|
+
if args.remote_documents:
|
|
707
|
+
filter_kwargs["remote_documents"] = args.remote_documents
|
|
708
|
+
if args.remote_document_backend:
|
|
709
|
+
filter_kwargs["remote_document_backend"] = args.remote_document_backend
|
|
710
|
+
if args.remote_document_timeout_seconds is not None:
|
|
711
|
+
filter_kwargs["remote_document_timeout_seconds"] = args.remote_document_timeout_seconds
|
|
712
|
+
if args.remote_document_memory_mib is not None:
|
|
713
|
+
filter_kwargs["remote_document_memory_mib"] = args.remote_document_memory_mib
|
|
680
714
|
if filter_kwargs:
|
|
681
715
|
config_kwargs["content_filter"] = filter_kwargs
|
|
682
716
|
|
|
@@ -1164,7 +1198,7 @@ def run_render_cli(argv: list[str]) -> int:
|
|
|
1164
1198
|
args.cloud_max_estimated_cost if backend in {"vercel-sandbox", "e2b-sandbox"} else None,
|
|
1165
1199
|
)
|
|
1166
1200
|
cloud_estimated_cost = (
|
|
1167
|
-
estimate_cloud_render_cost_usd(
|
|
1201
|
+
estimate_cloud_render_cost_usd(backend, config)
|
|
1168
1202
|
if backend in {"vercel-sandbox", "e2b-sandbox"}
|
|
1169
1203
|
else 0.0
|
|
1170
1204
|
)
|
|
@@ -16,6 +16,7 @@ import json
|
|
|
16
16
|
import logging
|
|
17
17
|
import re
|
|
18
18
|
from dataclasses import dataclass
|
|
19
|
+
from email.message import Message
|
|
19
20
|
from typing import Any, Protocol
|
|
20
21
|
from urllib.parse import urlparse
|
|
21
22
|
|
|
@@ -710,33 +711,143 @@ class RawTextExtractor:
|
|
|
710
711
|
|
|
711
712
|
name = "raw_text"
|
|
712
713
|
|
|
713
|
-
_TEXT_SUFFIXES = (
|
|
714
|
+
_TEXT_SUFFIXES = (
|
|
715
|
+
".csv",
|
|
716
|
+
".json",
|
|
717
|
+
".jsonl",
|
|
718
|
+
".markdown",
|
|
719
|
+
".md",
|
|
720
|
+
".mdx",
|
|
721
|
+
".ndjson",
|
|
722
|
+
".rst",
|
|
723
|
+
".text",
|
|
724
|
+
".tsv",
|
|
725
|
+
".txt",
|
|
726
|
+
".xml",
|
|
727
|
+
".yaml",
|
|
728
|
+
".yml",
|
|
729
|
+
)
|
|
730
|
+
_TEXT_CONTENT_TYPES = {
|
|
731
|
+
"application/json",
|
|
732
|
+
"application/ld+json",
|
|
733
|
+
"application/x-ndjson",
|
|
734
|
+
"application/xml",
|
|
735
|
+
"application/yaml",
|
|
736
|
+
"application/x-yaml",
|
|
737
|
+
"text/csv",
|
|
738
|
+
"text/markdown",
|
|
739
|
+
"text/plain",
|
|
740
|
+
"text/tab-separated-values",
|
|
741
|
+
"text/x-markdown",
|
|
742
|
+
"text/x-rst",
|
|
743
|
+
"text/xml",
|
|
744
|
+
"text/yaml",
|
|
745
|
+
}
|
|
714
746
|
_HTML_MARKERS = ("<html", "<body", "<!doctype")
|
|
715
|
-
|
|
716
|
-
|
|
747
|
+
_STRUCTURED_LANGUAGES = {
|
|
748
|
+
".csv": "csv",
|
|
749
|
+
".json": "json",
|
|
750
|
+
".jsonl": "ndjson",
|
|
751
|
+
".ndjson": "ndjson",
|
|
752
|
+
".rst": "rst",
|
|
753
|
+
".tsv": "tsv",
|
|
754
|
+
".xml": "xml",
|
|
755
|
+
".yaml": "yaml",
|
|
756
|
+
".yml": "yaml",
|
|
757
|
+
}
|
|
758
|
+
_MEDIA_LANGUAGES = {
|
|
759
|
+
"application/json": "json",
|
|
760
|
+
"application/ld+json": "json",
|
|
761
|
+
"application/x-ndjson": "ndjson",
|
|
762
|
+
"application/xml": "xml",
|
|
763
|
+
"application/yaml": "yaml",
|
|
764
|
+
"application/x-yaml": "yaml",
|
|
765
|
+
"text/csv": "csv",
|
|
766
|
+
"text/tab-separated-values": "tsv",
|
|
767
|
+
"text/x-rst": "rst",
|
|
768
|
+
"text/xml": "xml",
|
|
769
|
+
"text/yaml": "yaml",
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
def try_extract(
|
|
773
|
+
self,
|
|
774
|
+
html: bytes,
|
|
775
|
+
url: str,
|
|
776
|
+
*,
|
|
777
|
+
content_type: str | None = None,
|
|
778
|
+
) -> SpecialCaseResult | None:
|
|
717
779
|
parsed = urlparse(url)
|
|
718
780
|
path = parsed.path.lower()
|
|
719
|
-
|
|
781
|
+
media_type = self._media_type(content_type)
|
|
782
|
+
identified_by_type = media_type in self._TEXT_CONTENT_TYPES
|
|
783
|
+
if not identified_by_type and not path.endswith(self._TEXT_SUFFIXES):
|
|
720
784
|
return None
|
|
721
785
|
|
|
722
|
-
text =
|
|
786
|
+
text = self._decode_text(html, content_type).strip()
|
|
723
787
|
if not text:
|
|
724
788
|
return None
|
|
789
|
+
language = self._structured_language(path, media_type)
|
|
725
790
|
lower_head = text[:500].lower()
|
|
726
|
-
if any(marker in lower_head for marker in self._HTML_MARKERS):
|
|
791
|
+
if language is None and any(marker in lower_head for marker in self._HTML_MARKERS):
|
|
727
792
|
return None
|
|
728
|
-
if
|
|
793
|
+
if (
|
|
794
|
+
path.endswith((".txt", ".text"))
|
|
795
|
+
and not identified_by_type
|
|
796
|
+
and not self._looks_like_docs_text(text, path)
|
|
797
|
+
):
|
|
729
798
|
return None
|
|
730
799
|
|
|
731
800
|
title = self._extract_title(text) or parsed.path.rsplit("/", 1)[-1] or "Document"
|
|
732
801
|
source_type = "llms_txt" if path.endswith(("/llms.txt", "/llms-full.txt")) else self.name
|
|
802
|
+
markdown = self._fenced(text, language) if language else self._safe_direct_markdown(text)
|
|
733
803
|
return SpecialCaseResult(
|
|
734
|
-
markdown=
|
|
804
|
+
markdown=markdown,
|
|
735
805
|
title=title,
|
|
736
806
|
source_type=source_type,
|
|
737
807
|
extra={"framework": source_type},
|
|
738
808
|
)
|
|
739
809
|
|
|
810
|
+
@classmethod
|
|
811
|
+
def _structured_language(cls, path: str, media_type: str) -> str | None:
|
|
812
|
+
if media_type in {"text/markdown", "text/x-markdown"} or path.endswith((".markdown", ".md", ".mdx")):
|
|
813
|
+
return None
|
|
814
|
+
media_language = cls._MEDIA_LANGUAGES.get(media_type)
|
|
815
|
+
if media_language:
|
|
816
|
+
return media_language
|
|
817
|
+
return next(
|
|
818
|
+
(language for suffix, language in cls._STRUCTURED_LANGUAGES.items() if path.endswith(suffix)),
|
|
819
|
+
None,
|
|
820
|
+
)
|
|
821
|
+
|
|
822
|
+
@staticmethod
|
|
823
|
+
def _fenced(text: str, language: str) -> str:
|
|
824
|
+
longest_run = max((len(match.group(0)) for match in re.finditer(r"`+", text)), default=0)
|
|
825
|
+
fence = "`" * max(3, longest_run + 1)
|
|
826
|
+
return f"{fence}{language}\n{text.rstrip()}\n{fence}\n"
|
|
827
|
+
|
|
828
|
+
@staticmethod
|
|
829
|
+
def _safe_direct_markdown(text: str) -> str:
|
|
830
|
+
inert = re.sub(r"<(/?)script\b", r"<\1script", text, flags=re.IGNORECASE)
|
|
831
|
+
return inert.rstrip() + "\n"
|
|
832
|
+
|
|
833
|
+
@staticmethod
|
|
834
|
+
def _media_type(content_type: str | None) -> str:
|
|
835
|
+
return (content_type or "").split(";", 1)[0].strip().casefold()
|
|
836
|
+
|
|
837
|
+
@staticmethod
|
|
838
|
+
def _decode_text(body: bytes, content_type: str | None) -> str:
|
|
839
|
+
if body.startswith(b"\xef\xbb\xbf"):
|
|
840
|
+
return body.decode("utf-8-sig", errors="replace")
|
|
841
|
+
encoding = "utf-8"
|
|
842
|
+
if content_type:
|
|
843
|
+
message = Message()
|
|
844
|
+
message["content-type"] = content_type
|
|
845
|
+
encoding = message.get_content_charset() or encoding
|
|
846
|
+
try:
|
|
847
|
+
return body.decode(encoding)
|
|
848
|
+
except (LookupError, UnicodeDecodeError):
|
|
849
|
+
return body.decode("utf-8", errors="replace")
|
|
850
|
+
|
|
740
851
|
@staticmethod
|
|
741
852
|
def _looks_like_docs_text(text: str, path: str) -> bool:
|
|
742
853
|
if path.endswith(("/llms.txt", "/llms-full.txt")):
|
|
@@ -802,6 +913,33 @@ class SphinxObjectsInvExtractor:
|
|
|
802
913
|
)
|
|
803
914
|
|
|
804
915
|
|
|
916
|
+
class RfcEditorExtractor:
|
|
917
|
+
"""Preserve complete RFC Editor HTML documents instead of one scored section."""
|
|
918
|
+
|
|
919
|
+
name = "rfc_editor"
|
|
920
|
+
|
|
921
|
+
def try_extract(self, html: bytes, url: str) -> SpecialCaseResult | None:
|
|
922
|
+
parsed = urlparse(url)
|
|
923
|
+
if not _hostname_matches_domain(parsed.hostname or "", "rfc-editor.org"):
|
|
924
|
+
return None
|
|
925
|
+
if re.fullmatch(r"/rfc/rfc\d+\.html", parsed.path.casefold()) is None:
|
|
926
|
+
return None
|
|
927
|
+
|
|
928
|
+
from .extractor import MainContentExtractor
|
|
929
|
+
from .markdown import HtmlToMarkdown
|
|
930
|
+
|
|
931
|
+
extracted_html = MainContentExtractor(content_selectors=["body"]).extract(html, url)
|
|
932
|
+
markdown = HtmlToMarkdown().convert(extracted_html, url).strip()
|
|
933
|
+
if len(markdown) < 80:
|
|
934
|
+
return None
|
|
935
|
+
return SpecialCaseResult(
|
|
936
|
+
markdown=markdown + "\n",
|
|
937
|
+
title=_title_from_soup(_soup(html)),
|
|
938
|
+
source_type=self.name,
|
|
939
|
+
extra={"framework": "rfc_editor"},
|
|
940
|
+
)
|
|
941
|
+
|
|
942
|
+
|
|
805
943
|
class MdxSourceExtractor:
|
|
806
944
|
"""Rewrite ``edit-this-page`` GitHub links to raw MDX source URLs.
|
|
807
945
|
|
|
@@ -842,6 +980,7 @@ class MdxSourceExtractor:
|
|
|
842
980
|
DEFAULT_CHAIN: list[SpecialCaseExtractor] = [
|
|
843
981
|
OpenApiExtractor(),
|
|
844
982
|
RawTextExtractor(),
|
|
983
|
+
RfcEditorExtractor(),
|
|
845
984
|
MintlifyExtractor(),
|
|
846
985
|
NextDataExtractor(),
|
|
847
986
|
MkDocsMaterialExtractor(),
|
|
@@ -969,6 +1108,7 @@ __all__ = [
|
|
|
969
1108
|
"RawTextExtractor",
|
|
970
1109
|
"ReadMeExtractor",
|
|
971
1110
|
"RedocScalarExtractor",
|
|
1111
|
+
"RfcEditorExtractor",
|
|
972
1112
|
"SpecialCaseExtractor",
|
|
973
1113
|
"SpecialCaseResult",
|
|
974
1114
|
"SphinxObjectsInvExtractor",
|
|
@@ -34,6 +34,7 @@ from ..pipeline.steps import (
|
|
|
34
34
|
SqliteSaveStep,
|
|
35
35
|
ValidateStep,
|
|
36
36
|
)
|
|
37
|
+
from ..security.download_policy import SafeDownloadPolicy
|
|
37
38
|
from ..security.robots import RobotsChecker
|
|
38
39
|
from ..security.url_validator import UrlValidator
|
|
39
40
|
|
|
@@ -331,6 +332,9 @@ class Fetcher:
|
|
|
331
332
|
if self.config.content_filter.max_file_size is not None
|
|
332
333
|
else AsyncHttpClient.MAX_CONTENT_SIZE
|
|
333
334
|
)
|
|
335
|
+
allowed_remote_document_types = (
|
|
336
|
+
{"application/pdf"} if self.config.content_filter.remote_documents == "pdf" else set()
|
|
337
|
+
)
|
|
334
338
|
self._http_client = AsyncHttpClient(
|
|
335
339
|
rate_limiter=self._rate_limiter,
|
|
336
340
|
max_retries=self.config.network.max_retries,
|
|
@@ -344,6 +348,9 @@ class Fetcher:
|
|
|
344
348
|
auth_scope_hosts=auth_scope_hosts,
|
|
345
349
|
require_pinned_dns=self.config.network.require_pinned_dns,
|
|
346
350
|
log_retry_warnings=self.config.network.log_retry_warnings,
|
|
351
|
+
download_policy=SafeDownloadPolicy(
|
|
352
|
+
allowed_remote_document_types=allowed_remote_document_types,
|
|
353
|
+
),
|
|
347
354
|
)
|
|
348
355
|
await self._http_client.__aenter__()
|
|
349
356
|
|
|
@@ -396,6 +403,7 @@ class Fetcher:
|
|
|
396
403
|
http_client=self._http_client,
|
|
397
404
|
cache_manager=self._cache_manager,
|
|
398
405
|
skip_unchanged=self.config.cache.skip_unchanged,
|
|
406
|
+
allowed_remote_document_types=allowed_remote_document_types,
|
|
399
407
|
)
|
|
400
408
|
)
|
|
401
409
|
if render_mode == "fallback":
|
|
@@ -417,6 +425,10 @@ class Fetcher:
|
|
|
417
425
|
use_ensemble=self.config.content_filter.extractor == "ensemble",
|
|
418
426
|
strict_js_required=self.config.content_filter.strict_js_required,
|
|
419
427
|
clean_inline_xbrl=self.config.content_filter.clean_inline_xbrl,
|
|
428
|
+
remote_documents=self.config.content_filter.remote_documents,
|
|
429
|
+
remote_document_backend=self.config.content_filter.remote_document_backend,
|
|
430
|
+
remote_document_timeout_seconds=(self.config.content_filter.remote_document_timeout_seconds),
|
|
431
|
+
remote_document_memory_mib=self.config.content_filter.remote_document_memory_mib,
|
|
420
432
|
)
|
|
421
433
|
)
|
|
422
434
|
|