pulsecrawl 0.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.
- pulsecrawl-0.1.0/CHANGELOG.md +85 -0
- pulsecrawl-0.1.0/CITATION.cff +20 -0
- pulsecrawl-0.1.0/Dockerfile +24 -0
- pulsecrawl-0.1.0/Dockerfile.dockerignore +15 -0
- pulsecrawl-0.1.0/LICENSE +661 -0
- pulsecrawl-0.1.0/MANIFEST.in +9 -0
- pulsecrawl-0.1.0/PKG-INFO +104 -0
- pulsecrawl-0.1.0/PYPI_README.md +52 -0
- pulsecrawl-0.1.0/README.md +342 -0
- pulsecrawl-0.1.0/_build_backend.py +56 -0
- pulsecrawl-0.1.0/docs/AgentTemplateAuthoring.md +149 -0
- pulsecrawl-0.1.0/docs/PackageArchitecture.md +161 -0
- pulsecrawl-0.1.0/docs/PyPI.md +167 -0
- pulsecrawl-0.1.0/docs/ResponsibleCrawling.md +45 -0
- pulsecrawl-0.1.0/docs/ThreatModel.md +114 -0
- pulsecrawl-0.1.0/examples/README.md +159 -0
- pulsecrawl-0.1.0/examples/__init__.py +1 -0
- pulsecrawl-0.1.0/examples/agent_template_authoring.py +53 -0
- pulsecrawl-0.1.0/examples/chihuahua_news.py +17 -0
- pulsecrawl-0.1.0/examples/hosted_cases.py +15 -0
- pulsecrawl-0.1.0/examples/hosted_quickstart.py +98 -0
- pulsecrawl-0.1.0/examples/jobsearch/__init__.py +5 -0
- pulsecrawl-0.1.0/examples/jobsearch/hosted.py +12 -0
- pulsecrawl-0.1.0/examples/jobsearch/local.py +12 -0
- pulsecrawl-0.1.0/examples/jobsearch/recipes.py +364 -0
- pulsecrawl-0.1.0/examples/jobsearch/validate_recipes.py +21 -0
- pulsecrawl-0.1.0/examples/local_cases.py +19 -0
- pulsecrawl-0.1.0/examples/local_quickstart.py +62 -0
- pulsecrawl-0.1.0/examples/marketplace/__init__.py +1 -0
- pulsecrawl-0.1.0/examples/marketplace/clothes/__init__.py +1 -0
- pulsecrawl-0.1.0/examples/marketplace/clothes/hosted.py +12 -0
- pulsecrawl-0.1.0/examples/marketplace/clothes/local.py +12 -0
- pulsecrawl-0.1.0/examples/marketplace/clothes/recipes.py +337 -0
- pulsecrawl-0.1.0/examples/marketplace/clothes/validate_recipes.py +21 -0
- pulsecrawl-0.1.0/examples/marketplace/mro/__init__.py +1 -0
- pulsecrawl-0.1.0/examples/marketplace/mro/hosted.py +12 -0
- pulsecrawl-0.1.0/examples/marketplace/mro/local.py +12 -0
- pulsecrawl-0.1.0/examples/marketplace/mro/recipes.py +442 -0
- pulsecrawl-0.1.0/examples/marketplace/other_industries/__init__.py +1 -0
- pulsecrawl-0.1.0/examples/marketplace/other_industries/hosted.py +12 -0
- pulsecrawl-0.1.0/examples/marketplace/other_industries/local.py +12 -0
- pulsecrawl-0.1.0/examples/marketplace/other_industries/recipes.py +468 -0
- pulsecrawl-0.1.0/examples/marketplace/other_industries/validate_recipes.py +21 -0
- pulsecrawl-0.1.0/examples/marketplace/premium_commerce/README.md +82 -0
- pulsecrawl-0.1.0/examples/marketplace/premium_commerce/__init__.py +1 -0
- pulsecrawl-0.1.0/examples/marketplace/premium_commerce/audit.py +140 -0
- pulsecrawl-0.1.0/examples/marketplace/premium_commerce/controlled-demo-summary.json +231 -0
- pulsecrawl-0.1.0/examples/marketplace/premium_commerce/controlled.py +117 -0
- pulsecrawl-0.1.0/examples/marketplace/premium_commerce/live-sources.json +1559 -0
- pulsecrawl-0.1.0/examples/marketplace/premium_commerce/live.py +484 -0
- pulsecrawl-0.1.0/examples/marketplace/premium_commerce/local.py +196 -0
- pulsecrawl-0.1.0/examples/marketplace/premium_commerce/recipes.py +248 -0
- pulsecrawl-0.1.0/examples/marketplace/premium_commerce/research.md +85 -0
- pulsecrawl-0.1.0/examples/marketplace/premium_commerce/robots-audit-2026-10-11.json +141 -0
- pulsecrawl-0.1.0/examples/marketplace/supermarkets/__init__.py +1 -0
- pulsecrawl-0.1.0/examples/marketplace/supermarkets/hosted.py +12 -0
- pulsecrawl-0.1.0/examples/marketplace/supermarkets/local.py +12 -0
- pulsecrawl-0.1.0/examples/marketplace/supermarkets/recipes.py +405 -0
- pulsecrawl-0.1.0/examples/news/__init__.py +1 -0
- pulsecrawl-0.1.0/examples/news/chihuahua/__init__.py +1 -0
- pulsecrawl-0.1.0/examples/news/chihuahua/hosted.py +12 -0
- pulsecrawl-0.1.0/examples/news/chihuahua/local.py +12 -0
- pulsecrawl-0.1.0/examples/news/chihuahua/recipes.py +432 -0
- pulsecrawl-0.1.0/examples/news/mexico/__init__.py +1 -0
- pulsecrawl-0.1.0/examples/news/mexico/hosted.py +12 -0
- pulsecrawl-0.1.0/examples/news/mexico/local.py +12 -0
- pulsecrawl-0.1.0/examples/news/mexico/recipes.py +458 -0
- pulsecrawl-0.1.0/examples/news/stocks/__init__.py +1 -0
- pulsecrawl-0.1.0/examples/news/stocks/hosted.py +12 -0
- pulsecrawl-0.1.0/examples/news/stocks/local.py +12 -0
- pulsecrawl-0.1.0/examples/news/stocks/recipes.py +432 -0
- pulsecrawl-0.1.0/examples/shared/__init__.py +1 -0
- pulsecrawl-0.1.0/examples/shared/catalog.py +128 -0
- pulsecrawl-0.1.0/examples/shared/cli.py +76 -0
- pulsecrawl-0.1.0/examples/shared/fixtures.py +41 -0
- pulsecrawl-0.1.0/examples/shared/hosted.py +196 -0
- pulsecrawl-0.1.0/examples/shared/local.py +222 -0
- pulsecrawl-0.1.0/examples/shared/recipes.py +63 -0
- pulsecrawl-0.1.0/examples/shared/safety.py +18 -0
- pulsecrawl-0.1.0/examples/shared/validation.py +196 -0
- pulsecrawl-0.1.0/examples/workspace_quickstart.py +61 -0
- pulsecrawl-0.1.0/pyproject.toml +88 -0
- pulsecrawl-0.1.0/requirements-workspace.txt +25 -0
- pulsecrawl-0.1.0/scripts/check-distributions.py +232 -0
- pulsecrawl-0.1.0/scripts/check-doc-links.py +73 -0
- pulsecrawl-0.1.0/scripts/check-release-ci.py +96 -0
- pulsecrawl-0.1.0/scripts/check-release.py +72 -0
- pulsecrawl-0.1.0/scripts/check-secrets.py +53 -0
- pulsecrawl-0.1.0/scripts/export-oss.py +281 -0
- pulsecrawl-0.1.0/scripts/smoke-distribution.py +82 -0
- pulsecrawl-0.1.0/setup.cfg +4 -0
- pulsecrawl-0.1.0/src/pulsecrawl/__init__.py +72 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/inbound/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/inbound/cli/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/inbound/cli/main.py +385 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/inbound/cli/parser.py +220 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/inbound/python/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/inbound/python/ephemeral.py +142 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/inbound/python/intent.py +103 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/inbound/python/local.py +175 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/inbound/python/resources.py +15 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/inbound/python/schedules.py +27 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/inbound/python/tasks.py +25 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/inbound/python/workspace.py +71 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/inbound/scheduler/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/inbound/scheduler/process.py +62 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/credentials/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/credentials/profiles.py +37 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/cron/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/cron/calculator.py +54 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/duckdb/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/duckdb/local_result.py +112 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/duckdb/query.py +271 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/atomic.py +119 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/backup_io.py +34 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/backups.py +196 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/catalogs.py +46 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/dataset_files.py +83 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/doctor.py +106 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/downloads.py +140 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/drafts.py +51 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/legacy_execution.py +156 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/manifests.py +228 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/pages.py +32 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/publication.py +95 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/retention.py +120 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/windows_publication.py +66 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/filesystem/workspace.py +68 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/html/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/html/extraction/__init__.py +38 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/html/extraction/css.py +69 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/html/extraction/jsonld.py +123 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/html/extraction/meta.py +56 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/html/inspection.py +161 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/html/links.py +25 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/artifacts.py +104 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/client.py +194 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/constants.py +5 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/fetcher.py +273 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/resources/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/resources/base.py +6 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/resources/datasets.py +114 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/resources/executions.py +110 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/resources/fields.py +24 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/resources/jobs.py +119 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/resources/organizations.py +34 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/resources/schedules.py +29 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/resources/schemas.py +26 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/resources/templates.py +43 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/resources/urls.py +27 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/scope.py +31 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/http/workspace.py +40 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/memory/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/memory/crawling.py +215 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/memory/records.py +12 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/parquet/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/parquet/compaction.py +120 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/parquet/publication.py +151 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/sqlite/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/sqlite/clock.py +36 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/sqlite/crawling.py +305 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/sqlite/definitions.py +53 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/sqlite/executions.py +223 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/sqlite/health.py +46 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/sqlite/history.py +67 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/sqlite/leases.py +108 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/sqlite/maintenance_lease.py +77 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/sqlite/records.py +211 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/sqlite/scheduler_lease.py +46 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/sqlite/schedules.py +121 -0
- pulsecrawl-0.1.0/src/pulsecrawl/adapters/outbound/sqlite/state.py +365 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/crawling/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/crawling/admission.py +160 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/crawling/dispatch.py +152 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/crawling/engine.py +125 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/crawling/pages.py +291 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/crawling/records.py +50 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/crawling/robots.py +124 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/datasets/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/datasets/publication.py +24 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/datasets/service.py +169 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/executions/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/executions/service.py +310 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/ports/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/ports/cloud.py +23 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/ports/crawling.py +150 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/ports/workspace.py +98 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/scheduling/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/scheduling/service.py +126 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/synchronization/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/synchronization/profiles.py +110 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/synchronization/service.py +231 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/telemetry.py +46 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/templates/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/templates/authoring.py +398 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/templates/resolution.py +91 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/templates/validation.py +246 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/time.py +11 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/workspace/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/workspace/catalogs.py +154 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/workspace/jobs.py +240 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/workspace/maintenance.py +19 -0
- pulsecrawl-0.1.0/src/pulsecrawl/application/workspace/validation.py +117 -0
- pulsecrawl-0.1.0/src/pulsecrawl/bootstrap/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/bootstrap/authoring.py +46 -0
- pulsecrawl-0.1.0/src/pulsecrawl/bootstrap/cloud.py +124 -0
- pulsecrawl-0.1.0/src/pulsecrawl/bootstrap/crawling.py +135 -0
- pulsecrawl-0.1.0/src/pulsecrawl/bootstrap/datasets.py +107 -0
- pulsecrawl-0.1.0/src/pulsecrawl/bootstrap/ephemeral.py +46 -0
- pulsecrawl-0.1.0/src/pulsecrawl/bootstrap/maintenance.py +46 -0
- pulsecrawl-0.1.0/src/pulsecrawl/bootstrap/workspace.py +134 -0
- pulsecrawl-0.1.0/src/pulsecrawl/cli.py +9 -0
- pulsecrawl-0.1.0/src/pulsecrawl/client.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl/cloud.py +6 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/__init__.py +37 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/adapters/__init__.py +0 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/adapters/aiohttp_fetcher.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/adapters/memory.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/coerce.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/engine.py +15 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/extraction/__init__.py +6 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/extraction/css.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/extraction/jsonld.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/extraction/meta.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/local.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/model.py +13 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/politeness.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/ports.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/robots.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl/core/urls.py +4 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/crawling/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/crawling/model.py +359 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/crawling/politeness.py +19 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/crawling/retry.py +25 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/crawling/urls.py +134 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/datasets/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/datasets/identity.py +43 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/errors.py +46 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/executions/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/executions/lifecycle.py +73 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/scheduling/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/scheduling/identity.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/synchronization/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/synchronization/planner.py +325 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/synchronization/profiles.py +11 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/templates/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/templates/authoring.py +188 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/templates/coercion.py +71 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/templates/selection.py +44 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/workspace/__init__.py +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl/domain/workspace/definitions.py +136 -0
- pulsecrawl-0.1.0/src/pulsecrawl/errors.py +6 -0
- pulsecrawl-0.1.0/src/pulsecrawl/local.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl/local_dataset.py +6 -0
- pulsecrawl-0.1.0/src/pulsecrawl/local_scheduler.py +28 -0
- pulsecrawl-0.1.0/src/pulsecrawl/observability.py +6 -0
- pulsecrawl-0.1.0/src/pulsecrawl/sqlite_state.py +10 -0
- pulsecrawl-0.1.0/src/pulsecrawl/template_authoring.py +6 -0
- pulsecrawl-0.1.0/src/pulsecrawl/workspace.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl/workspace_maintenance.py +6 -0
- pulsecrawl-0.1.0/src/pulsecrawl/workspace_runtime.py +8 -0
- pulsecrawl-0.1.0/src/pulsecrawl.egg-info/PKG-INFO +104 -0
- pulsecrawl-0.1.0/src/pulsecrawl.egg-info/SOURCES.txt +311 -0
- pulsecrawl-0.1.0/src/pulsecrawl.egg-info/dependency_links.txt +1 -0
- pulsecrawl-0.1.0/src/pulsecrawl.egg-info/entry_points.txt +2 -0
- pulsecrawl-0.1.0/src/pulsecrawl.egg-info/requires.txt +34 -0
- pulsecrawl-0.1.0/src/pulsecrawl.egg-info/top_level.txt +1 -0
- pulsecrawl-0.1.0/tests/application/test_execution_service.py +132 -0
- pulsecrawl-0.1.0/tests/application/test_publication_order.py +87 -0
- pulsecrawl-0.1.0/tests/architecture/test_boundaries.py +170 -0
- pulsecrawl-0.1.0/tests/contracts/test_artifact_downloads.py +234 -0
- pulsecrawl-0.1.0/tests/contracts/test_backup_publication.py +107 -0
- pulsecrawl-0.1.0/tests/contracts/test_crawling_adapters.py +123 -0
- pulsecrawl-0.1.0/tests/contracts/test_durable_file_flush.py +53 -0
- pulsecrawl-0.1.0/tests/contracts/test_execution_preparation.py +81 -0
- pulsecrawl-0.1.0/tests/contracts/test_sqlite_cursor_synchronization.py +51 -0
- pulsecrawl-0.1.0/tests/core/__init__.py +0 -0
- pulsecrawl-0.1.0/tests/core/conftest.py +123 -0
- pulsecrawl-0.1.0/tests/core/test_aiohttp_fetcher.py +370 -0
- pulsecrawl-0.1.0/tests/core/test_coerce.py +76 -0
- pulsecrawl-0.1.0/tests/core/test_conformance.py +149 -0
- pulsecrawl-0.1.0/tests/core/test_engine.py +996 -0
- pulsecrawl-0.1.0/tests/core/test_extraction.py +140 -0
- pulsecrawl-0.1.0/tests/core/test_local.py +49 -0
- pulsecrawl-0.1.0/tests/core/test_model.py +54 -0
- pulsecrawl-0.1.0/tests/core/test_robots.py +81 -0
- pulsecrawl-0.1.0/tests/core/test_urls.py +126 -0
- pulsecrawl-0.1.0/tests/domain/test_lifecycle_policies.py +117 -0
- pulsecrawl-0.1.0/tests/test_business_scenarios.py +453 -0
- pulsecrawl-0.1.0/tests/test_client.py +537 -0
- pulsecrawl-0.1.0/tests/test_cloud.py +528 -0
- pulsecrawl-0.1.0/tests/test_container_dependencies.py +34 -0
- pulsecrawl-0.1.0/tests/test_dataset_versions.py +144 -0
- pulsecrawl-0.1.0/tests/test_example_workflows.py +415 -0
- pulsecrawl-0.1.0/tests/test_failure_scenarios.py +525 -0
- pulsecrawl-0.1.0/tests/test_hosted_examples.py +165 -0
- pulsecrawl-0.1.0/tests/test_live_commerce_example.py +157 -0
- pulsecrawl-0.1.0/tests/test_local.py +195 -0
- pulsecrawl-0.1.0/tests/test_premium_commerce_example.py +192 -0
- pulsecrawl-0.1.0/tests/test_production_validation.py +519 -0
- pulsecrawl-0.1.0/tests/test_release_artifacts.py +255 -0
- pulsecrawl-0.1.0/tests/test_release_ci.py +86 -0
- pulsecrawl-0.1.0/tests/test_soak_validation.py +75 -0
- pulsecrawl-0.1.0/tests/test_template_authoring.py +545 -0
- pulsecrawl-0.1.0/tests/test_workspace_hardening.py +649 -0
- pulsecrawl-0.1.0/tests/test_workspace_runtime.py +763 -0
- pulsecrawl-0.1.0/tools/soak_workspace.py +354 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Publishing preparation
|
|
4
|
+
|
|
5
|
+
- Serialize shared SQLite cursor reads as well as statement execution.
|
|
6
|
+
- Flush completed output files with Windows-compatible writable descriptors,
|
|
7
|
+
retain directory write/rename exclusion during downloads, and install Windows
|
|
8
|
+
timezone data for scheduling. Profile metadata uses POSIX modes or inherited
|
|
9
|
+
Windows ACLs; credentials remain outside that file on every platform.
|
|
10
|
+
- Generate the CI SBOM outside the checkout so the clean-source release gate
|
|
11
|
+
continues to reject genuine uncommitted source changes.
|
|
12
|
+
- Publish Windows downloads with a same-parent native rename so publication
|
|
13
|
+
does not reopen or unlock a parent protected against reparse mutation.
|
|
14
|
+
- Pin container aiohttp consistently with the package security floor, and test
|
|
15
|
+
container-lock compatibility to catch future dependency drift.
|
|
16
|
+
- Publish downloaded artifacts without clobbering concurrent writers by default;
|
|
17
|
+
pin validated parent directories before creating descendants or staging files.
|
|
18
|
+
- Reject ambiguous, duplicate, and platform-specific artifact paths before writes.
|
|
19
|
+
- Strip personal ownership/PAX metadata from source archives at build time and
|
|
20
|
+
reject identity leaks or personal maintainer metadata in distribution checks.
|
|
21
|
+
- Validate restored workspaces before atomic no-clobber publication; never
|
|
22
|
+
remove or replace a competing backup/restore destination.
|
|
23
|
+
- Explicitly reject multicast and special-purpose crawler destinations across
|
|
24
|
+
supported Python versions, including IPv4-mapped IPv6 addresses.
|
|
25
|
+
- Raise the aiohttp security floor to 3.14.5 and pytest to 9.0.3 (with compatible
|
|
26
|
+
pytest-asyncio); audit minimum dependencies including transitive packages.
|
|
27
|
+
- Use audited setuptools 84 or newer for source builds and backend tests.
|
|
28
|
+
- Require successful full CI on the exact tagged SHA and protected publishing
|
|
29
|
+
environments before allowing an upload.
|
|
30
|
+
- Add a PyPI-specific description, complete source archives, artifact validation,
|
|
31
|
+
and clean-install smoke checks.
|
|
32
|
+
- Prepare manual GitHub OIDC publishing with TestPyPI rehearsal and separate
|
|
33
|
+
production approval. Account, publisher, and environment setup remain launch tasks.
|
|
34
|
+
|
|
35
|
+
All notable changes to the public PulseCrawl package will be recorded here.
|
|
36
|
+
PulseCrawl has not yet published a tagged software release.
|
|
37
|
+
|
|
38
|
+
## Unreleased
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- Import-safe offline memory and workspace quickstarts, shared example
|
|
43
|
+
provisioners, runnable per-category entry points, and offline workflow tests.
|
|
44
|
+
- Recipe validation using saved HTML or explicitly opted-in governed sampling;
|
|
45
|
+
no samples checked is inconclusive rather than a successful validation.
|
|
46
|
+
- `pulsecrawl.core`, a cloud-independent crawl engine with bounded frontiers,
|
|
47
|
+
robots handling, request pacing, redirect reauthorization, response-size
|
|
48
|
+
limits, typed extraction, and explicit private-network opt-in.
|
|
49
|
+
- Top-level `pulsecrawl` APIs for synchronous local crawling and portable workspaces with SQLite
|
|
50
|
+
state, Parquet datasets, embedded DuckDB queries, schedules, compaction,
|
|
51
|
+
template authoring, and an optional explicitly configured hosted client.
|
|
52
|
+
- Native and Docker-based local operation without a required cloud account,
|
|
53
|
+
control plane, Redis deployment, or external database server.
|
|
54
|
+
- An allowlisted public-source exporter, cross-platform Python CI, package
|
|
55
|
+
build validation, dependency auditing, SBOM generation, secret scanning,
|
|
56
|
+
and release automation.
|
|
57
|
+
- GNU Affero General Public License v3.0 licensing, governance, DCO contribution terms, security
|
|
58
|
+
reporting, community standards, support boundaries, and responsible-use
|
|
59
|
+
guidance.
|
|
60
|
+
- Optional OS-keyring cloud profiles and explicit workspace plan/push/run/pull
|
|
61
|
+
commands; no local command contacts cloud implicitly and signed artifact
|
|
62
|
+
downloads never receive the hosted API key.
|
|
63
|
+
- A single `pulsecrawl` distribution containing both the engine and SDK,
|
|
64
|
+
replacing the pre-release split-package layout.
|
|
65
|
+
- Hexagonal internal layers (`domain`, `application`, `adapters`, `bootstrap`),
|
|
66
|
+
focused crawl services, repository and runtime ports, and executable
|
|
67
|
+
dependency-boundary tests. Existing public imports remain compatible.
|
|
68
|
+
|
|
69
|
+
### Fixed
|
|
70
|
+
|
|
71
|
+
- Concurrent preparation of the same execution ID now returns the original
|
|
72
|
+
execution and reserves lifetime capacity only once. Identity lookup,
|
|
73
|
+
reservation, and insertion share one immediate SQLite transaction.
|
|
74
|
+
|
|
75
|
+
### Safety and compatibility notes
|
|
76
|
+
|
|
77
|
+
- Network requests reject non-global IPv4 and IPv6 destinations by default,
|
|
78
|
+
including loopback, private, link-local, reserved, and metadata-service
|
|
79
|
+
addresses resolved directly or through DNS.
|
|
80
|
+
- Redirect destinations are returned to the crawl engine for scope, robots,
|
|
81
|
+
and origin-rate authorization before the next request.
|
|
82
|
+
- Hosted SDK clients have no built-in service endpoint and require an explicit
|
|
83
|
+
`base_url` or `PULSECRAWL_BASE_URL`.
|
|
84
|
+
- PulseCrawl is alpha software. Public compatibility begins with the first
|
|
85
|
+
tagged release; no earlier commit is a supported release.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use PulseCrawl or its research benchmark, cite this software artifact."
|
|
3
|
+
title: "PulseCrawl: Design and Evaluation of a Framework for Policy-Constrained Recurring Web Crawling and Versioned Structured Datasets"
|
|
4
|
+
type: software
|
|
5
|
+
authors:
|
|
6
|
+
- name: "PulseCrawl contributors"
|
|
7
|
+
version: "0.1.0"
|
|
8
|
+
license: "AGPL-3.0-only"
|
|
9
|
+
abstract: >-
|
|
10
|
+
A framework for policy-constrained recurring web crawling, structured
|
|
11
|
+
extraction, and versioned Parquet datasets, with explicit request policies,
|
|
12
|
+
durable safety invariants, URL-scoped template cascades, and a reproducible
|
|
13
|
+
comparative evaluation.
|
|
14
|
+
keywords:
|
|
15
|
+
- web crawling
|
|
16
|
+
- web scraping
|
|
17
|
+
- distributed systems
|
|
18
|
+
- data lake
|
|
19
|
+
- information extraction
|
|
20
|
+
repository-code: "https://github.com/pulsecrawl/PulseCrawl"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
FROM python:3.13.16-slim-bookworm@sha256:55e31428469cbd0e20d52b2b514e8ec20ca4742254ed2b9dbe0f0b2d39cc2d65
|
|
2
|
+
|
|
3
|
+
LABEL org.opencontainers.image.source="https://github.com/pulsecrawl/PulseCrawl" \
|
|
4
|
+
org.opencontainers.image.description="PulseCrawl local workspace scheduler" \
|
|
5
|
+
org.opencontainers.image.licenses="AGPL-3.0-only"
|
|
6
|
+
|
|
7
|
+
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
8
|
+
PYTHONUNBUFFERED=1 \
|
|
9
|
+
PIP_NO_CACHE_DIR=1
|
|
10
|
+
|
|
11
|
+
WORKDIR /opt/pulsecrawl
|
|
12
|
+
COPY . /opt/pulsecrawl/package
|
|
13
|
+
RUN python -m pip install --no-cache-dir --upgrade "pip==26.2.1" \
|
|
14
|
+
&& python -m pip install --no-cache-dir \
|
|
15
|
+
--constraint /opt/pulsecrawl/package/requirements-workspace.txt \
|
|
16
|
+
'/opt/pulsecrawl/package[workspace]'
|
|
17
|
+
|
|
18
|
+
RUN useradd --create-home --uid 10001 pulsecrawl \
|
|
19
|
+
&& mkdir -p /workspace \
|
|
20
|
+
&& chown pulsecrawl:pulsecrawl /workspace
|
|
21
|
+
USER pulsecrawl
|
|
22
|
+
|
|
23
|
+
ENTRYPOINT ["pulsecrawl"]
|
|
24
|
+
CMD ["--workspace", "/workspace", "schedule", "start"]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Only build inputs enter the container context: no Git data, credentials,
|
|
2
|
+
# local environments, test outputs, or previously built distributions.
|
|
3
|
+
**
|
|
4
|
+
!pyproject.toml
|
|
5
|
+
!_build_backend.py
|
|
6
|
+
!PYPI_README.md
|
|
7
|
+
!README.md
|
|
8
|
+
!LICENSE
|
|
9
|
+
!MANIFEST.in
|
|
10
|
+
!requirements-workspace.txt
|
|
11
|
+
!src/
|
|
12
|
+
!src/pulsecrawl/
|
|
13
|
+
!src/pulsecrawl/**
|
|
14
|
+
**/__pycache__/
|
|
15
|
+
**/*.py[cod]
|