pytest-obligation 0.8.0__py3-none-any.whl

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.
Files changed (180) hide show
  1. due_work_harness/__init__.py +70 -0
  2. due_work_harness/__init__.pyi +2 -0
  3. due_work_harness/binding.pyi +1 -0
  4. due_work_harness/coherence.pyi +1 -0
  5. due_work_harness/contract.pyi +1 -0
  6. due_work_harness/coverage/__init__.pyi +1 -0
  7. due_work_harness/coverage/cli.pyi +1 -0
  8. due_work_harness/coverage/config.pyi +1 -0
  9. due_work_harness/coverage/declarations.pyi +1 -0
  10. due_work_harness/coverage/handoffs.pyi +1 -0
  11. due_work_harness/coverage/project.pyi +1 -0
  12. due_work_harness/coverage/report.pyi +1 -0
  13. due_work_harness/coverage/scan.pyi +1 -0
  14. due_work_harness/coverage/sites.pyi +1 -0
  15. due_work_harness/crash_histories.pyi +1 -0
  16. due_work_harness/evidence/__init__.pyi +1 -0
  17. due_work_harness/evidence/observation.pyi +1 -0
  18. due_work_harness/evidence/observation_report.pyi +1 -0
  19. due_work_harness/exemptions.pyi +1 -0
  20. due_work_harness/faults.pyi +1 -0
  21. due_work_harness/gap_probes.pyi +1 -0
  22. due_work_harness/helpers.pyi +1 -0
  23. due_work_harness/host.pyi +1 -0
  24. due_work_harness/integrations/__init__.pyi +1 -0
  25. due_work_harness/integrations/aiokafka.pyi +1 -0
  26. due_work_harness/integrations/celery.pyi +1 -0
  27. due_work_harness/integrations/celery_worker.pyi +1 -0
  28. due_work_harness/integrations/clocks.pyi +1 -0
  29. due_work_harness/integrations/dbos.pyi +1 -0
  30. due_work_harness/integrations/django/__init__.pyi +1 -0
  31. due_work_harness/integrations/django/admission.pyi +1 -0
  32. due_work_harness/integrations/django/callbacks.pyi +1 -0
  33. due_work_harness/integrations/django/commands.pyi +1 -0
  34. due_work_harness/integrations/django/commits.pyi +1 -0
  35. due_work_harness/integrations/django/lifecycle_references.pyi +1 -0
  36. due_work_harness/integrations/django/lifecycle_states.pyi +1 -0
  37. due_work_harness/integrations/django/lock_order.pyi +1 -0
  38. due_work_harness/integrations/django/receivers.pyi +1 -0
  39. due_work_harness/integrations/django/references.pyi +1 -0
  40. due_work_harness/integrations/django/selection.pyi +1 -0
  41. due_work_harness/integrations/django/writes.pyi +1 -0
  42. due_work_harness/integrations/django_tasks.pyi +1 -0
  43. due_work_harness/integrations/mongodb.pyi +1 -0
  44. due_work_harness/integrations/postgres_plans.pyi +1 -0
  45. due_work_harness/integrations/prefect.pyi +1 -0
  46. due_work_harness/integrations/procrastinate.pyi +1 -0
  47. due_work_harness/integrations/redis.pyi +1 -0
  48. due_work_harness/integrations/rq.pyi +1 -0
  49. due_work_harness/integrations/task_queues.pyi +1 -0
  50. due_work_harness/interleavings/__init__.pyi +1 -0
  51. due_work_harness/interleavings/adapters/__init__.pyi +1 -0
  52. due_work_harness/interleavings/adapters/integration.pyi +1 -0
  53. due_work_harness/interleavings/bindings.pyi +1 -0
  54. due_work_harness/interleavings/engine/__init__.pyi +1 -0
  55. due_work_harness/interleavings/engine/catalog.pyi +1 -0
  56. due_work_harness/interleavings/engine/causality.pyi +1 -0
  57. due_work_harness/interleavings/engine/provider.pyi +1 -0
  58. due_work_harness/interleavings/engine/runner.pyi +1 -0
  59. due_work_harness/interleavings/exploration/__init__.pyi +1 -0
  60. due_work_harness/interleavings/exploration/hypothesis.pyi +1 -0
  61. due_work_harness/interleavings/model.pyi +1 -0
  62. due_work_harness/interleavings/ports.pyi +1 -0
  63. due_work_harness/interleavings/testing/__init__.pyi +1 -0
  64. due_work_harness/interleavings/testing/reference.pyi +1 -0
  65. due_work_harness/models.pyi +1 -0
  66. due_work_harness/process_histories.pyi +1 -0
  67. due_work_harness/profiles/__init__.pyi +1 -0
  68. due_work_harness/profiles/automatic_recovery.pyi +1 -0
  69. due_work_harness/profiles/bounded_ownership.pyi +1 -0
  70. due_work_harness/profiles/catalog.pyi +1 -0
  71. due_work_harness/profiles/coverage.pyi +1 -0
  72. due_work_harness/profiles/crash_ambiguity.pyi +1 -0
  73. due_work_harness/profiles/durable_retention.pyi +1 -0
  74. due_work_harness/profiles/eventual_convergence.pyi +1 -0
  75. due_work_harness/profiles/fact_derived_obligations.pyi +1 -0
  76. due_work_harness/profiles/gated_execution.pyi +1 -0
  77. due_work_harness/profiles/harmless_replay.pyi +1 -0
  78. due_work_harness/profiles/indivisible_admission.pyi +1 -0
  79. due_work_harness/profiles/job_retry_limits.pyi +1 -0
  80. due_work_harness/profiles/reporting.pyi +1 -0
  81. due_work_harness/py.typed +1 -0
  82. due_work_harness/pytest_plugin.pyi +1 -0
  83. due_work_harness/recording.pyi +1 -0
  84. due_work_harness/references/__init__.pyi +1 -0
  85. due_work_harness/references/eligibility.pyi +1 -0
  86. due_work_harness/references/in_memory.pyi +1 -0
  87. due_work_harness/references/in_memory_handoffs.pyi +1 -0
  88. due_work_harness/worker_death.pyi +1 -0
  89. pytest_obligation/__init__.py +245 -0
  90. pytest_obligation/binding.py +884 -0
  91. pytest_obligation/coherence.py +118 -0
  92. pytest_obligation/contract.py +1850 -0
  93. pytest_obligation/coverage/__init__.py +55 -0
  94. pytest_obligation/coverage/cli.py +145 -0
  95. pytest_obligation/coverage/config.py +103 -0
  96. pytest_obligation/coverage/declarations.py +262 -0
  97. pytest_obligation/coverage/handoffs.py +467 -0
  98. pytest_obligation/coverage/project.py +261 -0
  99. pytest_obligation/coverage/report.py +45 -0
  100. pytest_obligation/coverage/scan.py +136 -0
  101. pytest_obligation/coverage/sites.py +152 -0
  102. pytest_obligation/crash_histories.py +948 -0
  103. pytest_obligation/evidence/__init__.py +13 -0
  104. pytest_obligation/evidence/observation.py +130 -0
  105. pytest_obligation/evidence/observation_report.py +76 -0
  106. pytest_obligation/exemptions.py +87 -0
  107. pytest_obligation/faults.py +41 -0
  108. pytest_obligation/gap_probes.py +314 -0
  109. pytest_obligation/helpers.py +204 -0
  110. pytest_obligation/host.py +338 -0
  111. pytest_obligation/integrations/__init__.py +0 -0
  112. pytest_obligation/integrations/aiokafka.py +104 -0
  113. pytest_obligation/integrations/celery.py +218 -0
  114. pytest_obligation/integrations/celery_worker.py +336 -0
  115. pytest_obligation/integrations/clocks.py +21 -0
  116. pytest_obligation/integrations/dbos.py +94 -0
  117. pytest_obligation/integrations/django/__init__.py +142 -0
  118. pytest_obligation/integrations/django/admission.py +35 -0
  119. pytest_obligation/integrations/django/callbacks.py +56 -0
  120. pytest_obligation/integrations/django/commands.py +74 -0
  121. pytest_obligation/integrations/django/commits.py +102 -0
  122. pytest_obligation/integrations/django/lifecycle_references.py +565 -0
  123. pytest_obligation/integrations/django/lifecycle_states.py +630 -0
  124. pytest_obligation/integrations/django/lock_order.py +428 -0
  125. pytest_obligation/integrations/django/receivers.py +47 -0
  126. pytest_obligation/integrations/django/references.py +35 -0
  127. pytest_obligation/integrations/django/selection.py +242 -0
  128. pytest_obligation/integrations/django/writes.py +186 -0
  129. pytest_obligation/integrations/django_tasks.py +257 -0
  130. pytest_obligation/integrations/mongodb.py +179 -0
  131. pytest_obligation/integrations/postgres_plans.py +343 -0
  132. pytest_obligation/integrations/prefect.py +86 -0
  133. pytest_obligation/integrations/procrastinate.py +308 -0
  134. pytest_obligation/integrations/redis.py +217 -0
  135. pytest_obligation/integrations/rq.py +455 -0
  136. pytest_obligation/integrations/task_queues.py +124 -0
  137. pytest_obligation/interleavings/__init__.py +42 -0
  138. pytest_obligation/interleavings/adapters/__init__.py +1 -0
  139. pytest_obligation/interleavings/adapters/integration.py +99 -0
  140. pytest_obligation/interleavings/bindings.py +393 -0
  141. pytest_obligation/interleavings/engine/__init__.py +1 -0
  142. pytest_obligation/interleavings/engine/catalog.py +292 -0
  143. pytest_obligation/interleavings/engine/causality.py +33 -0
  144. pytest_obligation/interleavings/engine/provider.py +99 -0
  145. pytest_obligation/interleavings/engine/runner.py +326 -0
  146. pytest_obligation/interleavings/exploration/__init__.py +1 -0
  147. pytest_obligation/interleavings/exploration/hypothesis.py +99 -0
  148. pytest_obligation/interleavings/model.py +152 -0
  149. pytest_obligation/interleavings/ports.py +34 -0
  150. pytest_obligation/interleavings/testing/__init__.py +1 -0
  151. pytest_obligation/interleavings/testing/reference.py +102 -0
  152. pytest_obligation/models.py +90 -0
  153. pytest_obligation/process_histories.py +207 -0
  154. pytest_obligation/profiles/__init__.py +6 -0
  155. pytest_obligation/profiles/automatic_recovery.py +1414 -0
  156. pytest_obligation/profiles/bounded_ownership.py +680 -0
  157. pytest_obligation/profiles/catalog.py +51 -0
  158. pytest_obligation/profiles/coverage.py +77 -0
  159. pytest_obligation/profiles/crash_ambiguity.py +291 -0
  160. pytest_obligation/profiles/durable_retention.py +119 -0
  161. pytest_obligation/profiles/eventual_convergence.py +308 -0
  162. pytest_obligation/profiles/fact_derived_obligations.py +389 -0
  163. pytest_obligation/profiles/gated_execution.py +389 -0
  164. pytest_obligation/profiles/harmless_replay.py +154 -0
  165. pytest_obligation/profiles/indivisible_admission.py +122 -0
  166. pytest_obligation/profiles/job_retry_limits.py +219 -0
  167. pytest_obligation/profiles/reporting.py +162 -0
  168. pytest_obligation/py.typed +0 -0
  169. pytest_obligation/pytest_plugin.py +245 -0
  170. pytest_obligation/recording.py +130 -0
  171. pytest_obligation/references/__init__.py +19 -0
  172. pytest_obligation/references/eligibility.py +222 -0
  173. pytest_obligation/references/in_memory.py +632 -0
  174. pytest_obligation/references/in_memory_handoffs.py +527 -0
  175. pytest_obligation/worker_death.py +65 -0
  176. pytest_obligation-0.8.0.dist-info/METADATA +227 -0
  177. pytest_obligation-0.8.0.dist-info/RECORD +180 -0
  178. pytest_obligation-0.8.0.dist-info/WHEEL +4 -0
  179. pytest_obligation-0.8.0.dist-info/entry_points.txt +6 -0
  180. pytest_obligation-0.8.0.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,70 @@
1
+ """Legacy imports, isolated from the canonical pytest_obligation implementation.
2
+
3
+ Aliases resolve lazily so importing this package never eagerly imports optional
4
+ framework adapters. Each old submodule points to the canonical module object:
5
+ contexts, registries, monkeypatches and class identities cannot diverge.
6
+ """
7
+
8
+ import importlib
9
+ import importlib.abc
10
+ import importlib.util
11
+ import sys
12
+ from collections.abc import Sequence
13
+ from importlib.machinery import ModuleSpec
14
+ from types import CodeType, ModuleType
15
+
16
+ import pytest_obligation as _canonical
17
+ from pytest_obligation import * # noqa: F403
18
+ from pytest_obligation import ObligationContract as DueWorkContract
19
+ from pytest_obligation import ObligationContractDesignError as DueWorkContractDesignError
20
+ from pytest_obligation import __version__ as __version__
21
+
22
+ __all__ = [*_canonical.__all__, "DueWorkContract", "DueWorkContractDesignError"]
23
+
24
+
25
+ class _AliasLoader(importlib.abc.Loader):
26
+ def __init__(self, canonical_name: str) -> None:
27
+ self.canonical_name = canonical_name
28
+ self.canonical_spec: ModuleSpec | None = None
29
+
30
+ def create_module(self, spec: ModuleSpec) -> ModuleType:
31
+ module = importlib.import_module(self.canonical_name)
32
+ self.canonical_spec = module.__spec__
33
+ # Old pickle/import paths resolve to actual renamed classes, not subclasses.
34
+ for legacy_name, canonical_name in (
35
+ ("DueWorkContract", "ObligationContract"),
36
+ ("DueWorkContractDesignError", "ObligationContractDesignError"),
37
+ ):
38
+ if canonical_name in module.__dict__:
39
+ module.__dict__[legacy_name] = module.__dict__[canonical_name]
40
+ return module
41
+
42
+ def exec_module(self, module: ModuleType) -> None:
43
+ # Import machinery overwrites __spec__ with the alias spec. Restore the
44
+ # canonical identity so relative imports, introspection and reload stay sound.
45
+ assert self.canonical_spec is not None
46
+ module.__spec__ = self.canonical_spec
47
+
48
+ def get_code(self, fullname: str) -> CodeType | None:
49
+ # Preserve `python -m due_work_harness.coverage.cli` as well as imports.
50
+ spec = importlib.util.find_spec(self.canonical_name)
51
+ assert spec is not None and isinstance(spec.loader, importlib.abc.InspectLoader)
52
+ return spec.loader.get_code(self.canonical_name)
53
+
54
+
55
+ class _AliasFinder(importlib.abc.MetaPathFinder):
56
+ def find_spec(
57
+ self, fullname: str, path: Sequence[str] | None = None, target: ModuleType | None = None
58
+ ) -> ModuleSpec | None:
59
+ if not fullname.startswith("due_work_harness."):
60
+ return None
61
+ canonical_name = "pytest_obligation" + fullname.removeprefix("due_work_harness")
62
+ spec = importlib.util.find_spec(canonical_name)
63
+ if spec is None:
64
+ return None
65
+ return importlib.util.spec_from_loader(
66
+ fullname, _AliasLoader(canonical_name), is_package=spec.submodule_search_locations is not None
67
+ )
68
+
69
+
70
+ sys.meta_path.insert(0, _AliasFinder())
@@ -0,0 +1,2 @@
1
+ from pytest_obligation import * # noqa: F403
2
+ from pytest_obligation import __version__ as __version__
@@ -0,0 +1 @@
1
+ from pytest_obligation.binding import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.coherence import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.contract import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.coverage import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.coverage.cli import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.coverage.config import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.coverage.declarations import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.coverage.handoffs import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.coverage.project import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.coverage.report import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.coverage.scan import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.coverage.sites import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.crash_histories import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.evidence import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.evidence.observation import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.evidence.observation_report import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.exemptions import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.faults import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.gap_probes import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.helpers import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.host import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.aiokafka import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.celery import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.celery_worker import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.clocks import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.dbos import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.django import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.django.admission import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.django.callbacks import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.django.commands import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.django.commits import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.django.lifecycle_references import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.django.lifecycle_states import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.django.lock_order import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.django.receivers import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.django.references import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.django.selection import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.django.writes import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.django_tasks import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.mongodb import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.postgres_plans import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.prefect import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.procrastinate import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.redis import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.rq import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.integrations.task_queues import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings.adapters import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings.adapters.integration import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings.bindings import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings.engine import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings.engine.catalog import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings.engine.causality import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings.engine.provider import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings.engine.runner import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings.exploration import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings.exploration.hypothesis import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings.model import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings.ports import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings.testing import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.interleavings.testing.reference import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.models import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.process_histories import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.profiles import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.profiles.automatic_recovery import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.profiles.bounded_ownership import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.profiles.catalog import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.profiles.coverage import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.profiles.crash_ambiguity import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.profiles.durable_retention import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.profiles.eventual_convergence import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.profiles.fact_derived_obligations import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.profiles.gated_execution import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.profiles.harmless_replay import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.profiles.indivisible_admission import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.profiles.job_retry_limits import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.profiles.reporting import * # noqa: F403
@@ -0,0 +1 @@
1
+
@@ -0,0 +1 @@
1
+ from pytest_obligation.pytest_plugin import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.recording import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.references import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.references.eligibility import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.references.in_memory import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.references.in_memory_handoffs import * # noqa: F403
@@ -0,0 +1 @@
1
+ from pytest_obligation.worker_death import * # noqa: F403
@@ -0,0 +1,245 @@
1
+ """
2
+ Conformance proofs for due work: work a program records now and a worker
3
+ completes later.
4
+
5
+ Due work can be delayed, retried, lost, duplicated or recovered. This package
6
+ proves an application's real production code handles each of those histories
7
+ without the application writing the proofs. An adopter declares a contract that
8
+ binds its real selection, worker and state; the harness generates the proofs.
9
+ The adopter never supplies an expected outcome.
10
+
11
+ Start here:
12
+
13
+ * :class:`ObligationContract` and :func:`due_work_contract_suite` — declare a
14
+ disposition (:class:`Claim`, :class:`Decline`, :class:`NotApplicable`,
15
+ :class:`KnownGap`) for every :class:`Profile` and get a pytest suite.
16
+ * :class:`Host` and :func:`configure` — what a framework supplies to the
17
+ framework-free proofs; integrations under ``pytest_obligation.integrations``
18
+ build hosts for particular frameworks.
19
+ * ``ARCHITECTURE.md`` for the layout and host contract, and
20
+ ``docs/what-a-green-result-means.md`` for what a pass does and does not mean.
21
+
22
+ The core imports no framework. Everything re-exported here loads with only
23
+ pytest installed.
24
+ """
25
+
26
+ from importlib.metadata import PackageNotFoundError, version
27
+
28
+ try:
29
+ __version__ = version("pytest-obligation")
30
+ except PackageNotFoundError: # running from a source tree that was never installed
31
+ __version__ = "0+unknown"
32
+
33
+
34
+ from pytest_obligation.contract import (
35
+ Adoption,
36
+ Claim,
37
+ ContractCase,
38
+ ConvergenceFamily,
39
+ Decline,
40
+ DueWorkSource,
41
+ ExtraProof,
42
+ KnownGap,
43
+ NotApplicable,
44
+ NotAssessed,
45
+ ObligationContract,
46
+ ObligationContractDesignError,
47
+ Profile,
48
+ SafetyContract,
49
+ ScheduledSelection,
50
+ contract_cases,
51
+ contract_report,
52
+ due_work_contract_suite,
53
+ due_work_database,
54
+ safety_contract_cases,
55
+ safety_contract_suite,
56
+ scheduled_selection_cases,
57
+ scheduled_selection_suite,
58
+ suite_cases,
59
+ )
60
+ from pytest_obligation.crash_histories import (
61
+ CallableDelivery,
62
+ Delivery,
63
+ ExternalCall,
64
+ Findings,
65
+ HandoffHistory,
66
+ HistoriesDiverged,
67
+ HistoryRun,
68
+ assert_crash_at_every_commit_converges,
69
+ assert_histories_converge,
70
+ assert_pinned_outcomes,
71
+ )
72
+ from pytest_obligation.exemptions import exempt_due_work_suite
73
+ from pytest_obligation.gap_probes import (
74
+ DisprovenCapability,
75
+ LossIsAbsorbedElsewhere,
76
+ MissingReclaim,
77
+ MissingScheduledConsumer,
78
+ )
79
+ from pytest_obligation.helpers import (
80
+ assert_provider_call_holds_no_transaction,
81
+ contract_params,
82
+ undeclared,
83
+ )
84
+ from pytest_obligation.host import (
85
+ Host,
86
+ SelectionInspector,
87
+ WorkerKiller,
88
+ configure,
89
+ current_host,
90
+ hosted,
91
+ )
92
+ from pytest_obligation.profiles.automatic_recovery import (
93
+ DUE_WORK_PROOFS,
94
+ SELECTION_PROOFS,
95
+ DueWorkSweep,
96
+ InFlightExecution,
97
+ OwedWorkVariant,
98
+ assert_due_work_recovery_contract,
99
+ )
100
+ from pytest_obligation.profiles.bounded_ownership import (
101
+ FENCED_OWNERSHIP_PROOFS,
102
+ FencedOwnership,
103
+ assert_fenced_ownership_contract,
104
+ )
105
+ from pytest_obligation.profiles.crash_ambiguity import (
106
+ AMBIGUITY_PROOFS,
107
+ AmbiguityAware,
108
+ assert_ambiguity_contract,
109
+ )
110
+ from pytest_obligation.profiles.durable_retention import (
111
+ RETENTION_PROOFS,
112
+ Retention,
113
+ assert_retention_contract,
114
+ assert_retention_preserves_non_terminal_work,
115
+ )
116
+ from pytest_obligation.profiles.eventual_convergence import (
117
+ CONVERGENT_WRITE_PROOFS,
118
+ SNAPSHOT_PROOFS,
119
+ ConvergentWrite,
120
+ SupersededSnapshot,
121
+ assert_convergent_write_contract,
122
+ assert_superseded_snapshot_contract,
123
+ assert_superseded_snapshot_does_not_write,
124
+ )
125
+ from pytest_obligation.profiles.fact_derived_obligations import (
126
+ STATE_DERIVED_PROOFS,
127
+ StateDerived,
128
+ assert_state_derived_contract,
129
+ )
130
+ from pytest_obligation.profiles.gated_execution import (
131
+ ELIGIBILITY_PROOFS,
132
+ ExecutionGate,
133
+ )
134
+ from pytest_obligation.profiles.harmless_replay import (
135
+ REPLAY_SAFETY_PROOFS,
136
+ ReplaySafeEffect,
137
+ assert_replay_safety_contract,
138
+ )
139
+ from pytest_obligation.profiles.indivisible_admission import AdmissionAtomicity, AdmissionPublication
140
+ from pytest_obligation.profiles.job_retry_limits import (
141
+ BOUNDED_RETRY_PROOFS,
142
+ BoundedRetry,
143
+ assert_bounded_retry_contract,
144
+ )
145
+
146
+ __all__ = [
147
+ "AdmissionAtomicity",
148
+ "AdmissionPublication",
149
+ "__version__",
150
+ "exempt_due_work_suite",
151
+ # Contract layer.
152
+ "Adoption",
153
+ "Claim",
154
+ "ContractCase",
155
+ "Decline",
156
+ "ObligationContract",
157
+ "ObligationContractDesignError",
158
+ "DueWorkSource",
159
+ "ExtraProof",
160
+ "KnownGap",
161
+ "NotApplicable",
162
+ "Profile",
163
+ "SafetyContract",
164
+ "NotAssessed",
165
+ "ConvergenceFamily",
166
+ "ScheduledSelection",
167
+ "contract_cases",
168
+ "contract_report",
169
+ "due_work_contract_suite",
170
+ "due_work_database",
171
+ "safety_contract_cases",
172
+ "safety_contract_suite",
173
+ "scheduled_selection_cases",
174
+ "scheduled_selection_suite",
175
+ "suite_cases",
176
+ # Host.
177
+ "Host",
178
+ "SelectionInspector",
179
+ "WorkerKiller",
180
+ "configure",
181
+ "current_host",
182
+ "hosted",
183
+ # Helpers.
184
+ "assert_provider_call_holds_no_transaction",
185
+ "contract_params",
186
+ "undeclared",
187
+ # Gap probes.
188
+ "DisprovenCapability",
189
+ "LossIsAbsorbedElsewhere",
190
+ "MissingReclaim",
191
+ "MissingScheduledConsumer",
192
+ # Crash histories.
193
+ "CallableDelivery",
194
+ "Delivery",
195
+ "ExternalCall",
196
+ "Findings",
197
+ "HandoffHistory",
198
+ "HistoriesDiverged",
199
+ "HistoryRun",
200
+ "assert_crash_at_every_commit_converges",
201
+ "assert_histories_converge",
202
+ "assert_pinned_outcomes",
203
+ # Profile A: automatic recovery.
204
+ "DUE_WORK_PROOFS",
205
+ "SELECTION_PROOFS",
206
+ "DueWorkSweep",
207
+ "InFlightExecution",
208
+ "OwedWorkVariant",
209
+ "assert_due_work_recovery_contract",
210
+ # Profile B: bounded ownership.
211
+ "FENCED_OWNERSHIP_PROOFS",
212
+ "FencedOwnership",
213
+ "assert_fenced_ownership_contract",
214
+ # Profile C: crash ambiguity.
215
+ "AMBIGUITY_PROOFS",
216
+ "AmbiguityAware",
217
+ "assert_ambiguity_contract",
218
+ # Profile D: durable retention.
219
+ "RETENTION_PROOFS",
220
+ "Retention",
221
+ "assert_retention_contract",
222
+ "assert_retention_preserves_non_terminal_work",
223
+ # Profile E: eventual convergence.
224
+ "CONVERGENT_WRITE_PROOFS",
225
+ "SNAPSHOT_PROOFS",
226
+ "ConvergentWrite",
227
+ "SupersededSnapshot",
228
+ "assert_convergent_write_contract",
229
+ "assert_superseded_snapshot_contract",
230
+ "assert_superseded_snapshot_does_not_write",
231
+ # Execution eligibility: blocked work stays owed and is neither run early nor forgotten.
232
+ "ELIGIBILITY_PROOFS",
233
+ "ExecutionGate",
234
+ # Profile F: fact-derived obligations.
235
+ "STATE_DERIVED_PROOFS",
236
+ "StateDerived",
237
+ "assert_state_derived_contract",
238
+ # Execution safety.
239
+ "BOUNDED_RETRY_PROOFS",
240
+ "REPLAY_SAFETY_PROOFS",
241
+ "BoundedRetry",
242
+ "ReplaySafeEffect",
243
+ "assert_bounded_retry_contract",
244
+ "assert_replay_safety_contract",
245
+ ]