assertpy 1.0__tar.gz → 2.35.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.
Files changed (327) hide show
  1. assertpy-2.35.0/.gitignore +34 -0
  2. assertpy-2.35.0/CONTRIBUTING.md +148 -0
  3. {assertpy-1.0 → assertpy-2.35.0}/LICENSE +2 -1
  4. assertpy-2.35.0/PKG-INFO +324 -0
  5. assertpy-2.35.0/README.md +271 -0
  6. assertpy-2.35.0/SECURITY.md +24 -0
  7. assertpy-2.35.0/assertpy/__init__.py +87 -0
  8. assertpy-2.35.0/assertpy/_clustering.py +511 -0
  9. assertpy-2.35.0/assertpy/_dangling.py +505 -0
  10. assertpy-2.35.0/assertpy/_engine/__init__.py +1 -0
  11. assertpy-2.35.0/assertpy/_engine/_builder_check_typing.py +1365 -0
  12. assertpy-2.35.0/assertpy/_engine/_capable_typing.py +772 -0
  13. assertpy-2.35.0/assertpy/_engine/_check_typing.py +753 -0
  14. assertpy-2.35.0/assertpy/_engine/_compare.py +983 -0
  15. assertpy-2.35.0/assertpy/_engine/_compat.py +38 -0
  16. assertpy-2.35.0/assertpy/_engine/_contract.py +1926 -0
  17. assertpy-2.35.0/assertpy/_engine/_diff.py +1058 -0
  18. assertpy-2.35.0/assertpy/_engine/_equality.py +843 -0
  19. assertpy-2.35.0/assertpy/_engine/_introspection.py +729 -0
  20. assertpy-2.35.0/assertpy/_engine/_membership.py +522 -0
  21. assertpy-2.35.0/assertpy/_engine/_mixin_base.py +258 -0
  22. assertpy-2.35.0/assertpy/_engine/_negated_typing.py +2176 -0
  23. assertpy-2.35.0/assertpy/_engine/_operations.py +75 -0
  24. assertpy-2.35.0/assertpy/_engine/_ordering.py +884 -0
  25. assertpy-2.35.0/assertpy/_engine/_pairing.py +70 -0
  26. assertpy-2.35.0/assertpy/_engine/_path.py +158 -0
  27. assertpy-2.35.0/assertpy/_engine/_poll_typing.py +6039 -0
  28. assertpy-2.35.0/assertpy/_engine/_require.py +312 -0
  29. assertpy-2.35.0/assertpy/_engine/_size.py +31 -0
  30. assertpy-2.35.0/assertpy/_engine/_text.py +39 -0
  31. assertpy-2.35.0/assertpy/_engine/_typing.py +1226 -0
  32. assertpy-2.35.0/assertpy/_hints.py +1213 -0
  33. assertpy-2.35.0/assertpy/_inline.py +484 -0
  34. assertpy-2.35.0/assertpy/_matcher_impls.py +1876 -0
  35. assertpy-2.35.0/assertpy/_passes.py +249 -0
  36. assertpy-2.35.0/assertpy/_renamed.py +64 -0
  37. assertpy-2.35.0/assertpy/_satisfies.py +835 -0
  38. assertpy-2.35.0/assertpy/_snapshot_codec.py +290 -0
  39. assertpy-2.35.0/assertpy/assertpy.py +2640 -0
  40. assertpy-2.35.0/assertpy/async_assertions.py +864 -0
  41. assertpy-2.35.0/assertpy/base.py +862 -0
  42. assertpy-2.35.0/assertpy/behave_matchers.py +96 -0
  43. assertpy-2.35.0/assertpy/bytes_mixin.py +158 -0
  44. assertpy-2.35.0/assertpy/collection.py +528 -0
  45. assertpy-2.35.0/assertpy/contains.py +1068 -0
  46. assertpy-2.35.0/assertpy/dataframe.py +200 -0
  47. assertpy-2.35.0/assertpy/date.py +327 -0
  48. assertpy-2.35.0/assertpy/dict.py +249 -0
  49. assertpy-2.35.0/assertpy/dynamic.py +222 -0
  50. assertpy-2.35.0/assertpy/errors.py +782 -0
  51. assertpy-2.35.0/assertpy/exception.py +838 -0
  52. assertpy-2.35.0/assertpy/extracting.py +266 -0
  53. assertpy-2.35.0/assertpy/file.py +324 -0
  54. assertpy-2.35.0/assertpy/helpers.py +747 -0
  55. assertpy-2.35.0/assertpy/http_mixin.py +218 -0
  56. assertpy-2.35.0/assertpy/json_mixin.py +1265 -0
  57. assertpy-2.35.0/assertpy/matchers.py +639 -0
  58. assertpy-2.35.0/assertpy/numeric.py +696 -0
  59. assertpy-2.35.0/assertpy/outcome.py +163 -0
  60. assertpy-2.35.0/assertpy/py.typed +0 -0
  61. assertpy-2.35.0/assertpy/pytest_plugin.py +1650 -0
  62. assertpy-2.35.0/assertpy/snapshot.py +1031 -0
  63. assertpy-2.35.0/assertpy/string.py +803 -0
  64. assertpy-2.35.0/assertpy/warning.py +137 -0
  65. assertpy-2.35.0/benchmarks/test_perf.py +492 -0
  66. assertpy-2.35.0/bridge/LICENSE +28 -0
  67. assertpy-2.35.0/bridge/README.md +17 -0
  68. assertpy-2.35.0/docs/assets/diff-equal.png +0 -0
  69. assertpy-2.35.0/docs/assets/diff-equal.svg +51 -0
  70. assertpy-2.35.0/docs/assets/diff-gallery.png +0 -0
  71. assertpy-2.35.0/docs/assets/diff-match.svg +50 -0
  72. assertpy-2.35.0/docs/assets/diff-sequence.svg +51 -0
  73. assertpy-2.35.0/docs/assets/diff-set.svg +47 -0
  74. assertpy-2.35.0/docs/assets/diff-string.svg +59 -0
  75. assertpy-2.35.0/docs/concepts/stability.md +190 -0
  76. assertpy-2.35.0/docs/concepts/type-safety.md +572 -0
  77. assertpy-2.35.0/docs/extending/custom-assertions.md +186 -0
  78. assertpy-2.35.0/docs/extending/integrations.md +487 -0
  79. assertpy-2.35.0/docs/getting-started/comparison.md +263 -0
  80. assertpy-2.35.0/docs/getting-started/migration.md +155 -0
  81. assertpy-2.35.0/docs/getting-started/quickstart.md +86 -0
  82. assertpy-2.35.0/docs/guides/assertions.md +1109 -0
  83. assertpy-2.35.0/docs/guides/data.md +254 -0
  84. assertpy-2.35.0/docs/guides/errors.md +1370 -0
  85. assertpy-2.35.0/docs/guides/fluent.md +199 -0
  86. assertpy-2.35.0/docs/guides/matchers.md +533 -0
  87. assertpy-2.35.0/docs/guides/testing.md +648 -0
  88. assertpy-2.35.0/docs/index.md +189 -0
  89. assertpy-2.35.0/docs/logo-dark.svg +5 -0
  90. assertpy-2.35.0/docs/logo.svg +5 -0
  91. assertpy-2.35.0/docs/recipes.md +324 -0
  92. assertpy-2.35.0/docs/reference/async.md +30 -0
  93. assertpy-2.35.0/docs/reference/bytes.md +5 -0
  94. assertpy-2.35.0/docs/reference/collections.md +5 -0
  95. assertpy-2.35.0/docs/reference/containment.md +5 -0
  96. assertpy-2.35.0/docs/reference/core.md +12 -0
  97. assertpy-2.35.0/docs/reference/dataframes.md +22 -0
  98. assertpy-2.35.0/docs/reference/dates.md +5 -0
  99. assertpy-2.35.0/docs/reference/dicts.md +5 -0
  100. assertpy-2.35.0/docs/reference/dynamic.md +6 -0
  101. assertpy-2.35.0/docs/reference/entry-points.md +105 -0
  102. assertpy-2.35.0/docs/reference/errors.md +54 -0
  103. assertpy-2.35.0/docs/reference/exceptions.md +5 -0
  104. assertpy-2.35.0/docs/reference/extracting.md +5 -0
  105. assertpy-2.35.0/docs/reference/files.md +11 -0
  106. assertpy-2.35.0/docs/reference/http.md +6 -0
  107. assertpy-2.35.0/docs/reference/json.md +5 -0
  108. assertpy-2.35.0/docs/reference/matchers.md +45 -0
  109. assertpy-2.35.0/docs/reference/numbers.md +5 -0
  110. assertpy-2.35.0/docs/reference/overview.md +31 -0
  111. assertpy-2.35.0/docs/reference/snapshots.md +29 -0
  112. assertpy-2.35.0/docs/reference/strings.md +6 -0
  113. assertpy-2.35.0/docs/reference/warnings.md +5 -0
  114. assertpy-2.35.0/docs/stylesheets/extra.css +56 -0
  115. assertpy-2.35.0/mkdocs.yml +164 -0
  116. assertpy-2.35.0/mkdocs_hooks.py +16 -0
  117. assertpy-2.35.0/pyproject.toml +434 -0
  118. assertpy-2.35.0/scripts/generate_check_protocols.py +169 -0
  119. assertpy-2.35.0/scripts/generate_poll_protocols.py +1748 -0
  120. assertpy-2.35.0/scripts/mutation_report.py +145 -0
  121. assertpy-2.35.0/scripts/regenerate.py +49 -0
  122. assertpy-2.35.0/tests/api_snapshot.json +7197 -0
  123. assertpy-2.35.0/tests/api_surface.py +514 -0
  124. assertpy-2.35.0/tests/chain_corpus.py +337 -0
  125. assertpy-2.35.0/tests/chain_model.py +633 -0
  126. assertpy-2.35.0/tests/chain_surfaces.py +226 -0
  127. assertpy-2.35.0/tests/conftest.py +111 -0
  128. assertpy-2.35.0/tests/data/json_schema_test_suite/LICENSE +19 -0
  129. assertpy-2.35.0/tests/data/json_schema_test_suite/date-time.json +226 -0
  130. assertpy-2.35.0/tests/data/json_schema_test_suite/date.json +423 -0
  131. assertpy-2.35.0/tests/data/json_schema_test_suite/duration.json +273 -0
  132. assertpy-2.35.0/tests/data/json_schema_test_suite/email.json +368 -0
  133. assertpy-2.35.0/tests/data/json_schema_test_suite/hostname.json +376 -0
  134. assertpy-2.35.0/tests/data/json_schema_test_suite/multipleOf.json +102 -0
  135. assertpy-2.35.0/tests/data/json_schema_test_suite/time.json +297 -0
  136. assertpy-2.35.0/tests/data/json_schema_test_suite/uri.json +248 -0
  137. assertpy-2.35.0/tests/docs_fixtures.py +251 -0
  138. assertpy-2.35.0/tests/format_corpus.py +137 -0
  139. assertpy-2.35.0/tests/group_compat.py +31 -0
  140. assertpy-2.35.0/tests/poll_parity_baseline.py +919 -0
  141. assertpy-2.35.0/tests/poll_parity_cases.py +3331 -0
  142. assertpy-2.35.0/tests/pyright_baseline.py +114 -0
  143. assertpy-2.35.0/tests/test_api_compatibility.py +471 -0
  144. assertpy-2.35.0/tests/test_api_vocabulary.py +147 -0
  145. assertpy-2.35.0/tests/test_architecture_doc.py +107 -0
  146. assertpy-2.35.0/tests/test_async.py +1705 -0
  147. assertpy-2.35.0/tests/test_async_predicates.py +195 -0
  148. assertpy-2.35.0/tests/test_attrs_support.py +480 -0
  149. assertpy-2.35.0/tests/test_behave_matchers.py +111 -0
  150. assertpy-2.35.0/tests/test_bool.py +33 -0
  151. assertpy-2.35.0/tests/test_boundary_cases.py +112 -0
  152. assertpy-2.35.0/tests/test_bytes.py +243 -0
  153. assertpy-2.35.0/tests/test_call_awaitables.py +163 -0
  154. assertpy-2.35.0/tests/test_callable.py +48 -0
  155. assertpy-2.35.0/tests/test_capable_protocol.py +1076 -0
  156. assertpy-2.35.0/tests/test_chain_machine.py +664 -0
  157. assertpy-2.35.0/tests/test_chaining.py +22 -0
  158. assertpy-2.35.0/tests/test_check.py +351 -0
  159. assertpy-2.35.0/tests/test_check_protocols.py +230 -0
  160. assertpy-2.35.0/tests/test_class.py +145 -0
  161. assertpy-2.35.0/tests/test_class_in_spec.py +293 -0
  162. assertpy-2.35.0/tests/test_clustering.py +1587 -0
  163. assertpy-2.35.0/tests/test_collection.py +321 -0
  164. assertpy-2.35.0/tests/test_compiled_patterns.py +209 -0
  165. assertpy-2.35.0/tests/test_complexity.py +124 -0
  166. assertpy-2.35.0/tests/test_core.py +194 -0
  167. assertpy-2.35.0/tests/test_custom_dict.py +1013 -0
  168. assertpy-2.35.0/tests/test_custom_list.py +47 -0
  169. assertpy-2.35.0/tests/test_dangling.py +1196 -0
  170. assertpy-2.35.0/tests/test_dataframe.py +299 -0
  171. assertpy-2.35.0/tests/test_datetime.py +1024 -0
  172. assertpy-2.35.0/tests/test_declared_floors.py +190 -0
  173. assertpy-2.35.0/tests/test_deep_nesting.py +438 -0
  174. assertpy-2.35.0/tests/test_description.py +29 -0
  175. assertpy-2.35.0/tests/test_dict.py +422 -0
  176. assertpy-2.35.0/tests/test_dict_compare.py +1086 -0
  177. assertpy-2.35.0/tests/test_diff_laws.py +1772 -0
  178. assertpy-2.35.0/tests/test_difference_places.py +223 -0
  179. assertpy-2.35.0/tests/test_docs_examples.py +334 -0
  180. assertpy-2.35.0/tests/test_docs_typing.py +122 -0
  181. assertpy-2.35.0/tests/test_duality.py +1018 -0
  182. assertpy-2.35.0/tests/test_dynamic.py +460 -0
  183. assertpy-2.35.0/tests/test_equality_signals.py +1206 -0
  184. assertpy-2.35.0/tests/test_equals.py +487 -0
  185. assertpy-2.35.0/tests/test_errors.py +464 -0
  186. assertpy-2.35.0/tests/test_evaluation_core.py +3291 -0
  187. assertpy-2.35.0/tests/test_exact_oracle.py +180 -0
  188. assertpy-2.35.0/tests/test_exception_context.py +90 -0
  189. assertpy-2.35.0/tests/test_exception_fields.py +267 -0
  190. assertpy-2.35.0/tests/test_expected_contract.py +303 -0
  191. assertpy-2.35.0/tests/test_expected_exception.py +1305 -0
  192. assertpy-2.35.0/tests/test_expected_warning.py +288 -0
  193. assertpy-2.35.0/tests/test_extensions.py +639 -0
  194. assertpy-2.35.0/tests/test_extracting.py +494 -0
  195. assertpy-2.35.0/tests/test_fail.py +15 -0
  196. assertpy-2.35.0/tests/test_file.py +297 -0
  197. assertpy-2.35.0/tests/test_fixed_width_integers.py +717 -0
  198. assertpy-2.35.0/tests/test_grouped_soft.py +148 -0
  199. assertpy-2.35.0/tests/test_hints.py +1025 -0
  200. assertpy-2.35.0/tests/test_hostile_values.py +238 -0
  201. assertpy-2.35.0/tests/test_http.py +599 -0
  202. assertpy-2.35.0/tests/test_import_cost.py +44 -0
  203. assertpy-2.35.0/tests/test_in.py +66 -0
  204. assertpy-2.35.0/tests/test_inline_record.py +1075 -0
  205. assertpy-2.35.0/tests/test_inline_snapshot.py +280 -0
  206. assertpy-2.35.0/tests/test_integer_arguments.py +113 -0
  207. assertpy-2.35.0/tests/test_iterable_cluster.py +426 -0
  208. assertpy-2.35.0/tests/test_json.py +209 -0
  209. assertpy-2.35.0/tests/test_list.py +1012 -0
  210. assertpy-2.35.0/tests/test_log_passes.py +1957 -0
  211. assertpy-2.35.0/tests/test_match_result.py +256 -0
  212. assertpy-2.35.0/tests/test_matcher_algebra.py +230 -0
  213. assertpy-2.35.0/tests/test_matcher_parity.py +204 -0
  214. assertpy-2.35.0/tests/test_matcher_registry.py +292 -0
  215. assertpy-2.35.0/tests/test_matchers.py +1630 -0
  216. assertpy-2.35.0/tests/test_membership_failures.py +270 -0
  217. assertpy-2.35.0/tests/test_membership_family.py +523 -0
  218. assertpy-2.35.0/tests/test_message_elision.py +278 -0
  219. assertpy-2.35.0/tests/test_message_values.py +345 -0
  220. assertpy-2.35.0/tests/test_missing_names.py +488 -0
  221. assertpy-2.35.0/tests/test_moment_relations.py +866 -0
  222. assertpy-2.35.0/tests/test_namedtuple.py +79 -0
  223. assertpy-2.35.0/tests/test_negated_protocols.py +422 -0
  224. assertpy-2.35.0/tests/test_none.py +27 -0
  225. assertpy-2.35.0/tests/test_not.py +421 -0
  226. assertpy-2.35.0/tests/test_number_zoo.py +491 -0
  227. assertpy-2.35.0/tests/test_numbers.py +2208 -0
  228. assertpy-2.35.0/tests/test_numeric_questions.py +322 -0
  229. assertpy-2.35.0/tests/test_one_shot_chains.py +572 -0
  230. assertpy-2.35.0/tests/test_one_shot_matchers.py +421 -0
  231. assertpy-2.35.0/tests/test_openapi_30_keywords.py +576 -0
  232. assertpy-2.35.0/tests/test_openapi_contract.py +1048 -0
  233. assertpy-2.35.0/tests/test_openapi_format_suite.py +118 -0
  234. assertpy-2.35.0/tests/test_openapi_formats.py +1007 -0
  235. assertpy-2.35.0/tests/test_openapi_multiple_of.py +322 -0
  236. assertpy-2.35.0/tests/test_openapi_oracle.py +328 -0
  237. assertpy-2.35.0/tests/test_openapi_part_read.py +441 -0
  238. assertpy-2.35.0/tests/test_operation_contract.py +404 -0
  239. assertpy-2.35.0/tests/test_optional_integration_contracts.py +86 -0
  240. assertpy-2.35.0/tests/test_overload_order.py +174 -0
  241. assertpy-2.35.0/tests/test_overloads.py +58 -0
  242. assertpy-2.35.0/tests/test_pin_coverage.py +784 -0
  243. assertpy-2.35.0/tests/test_pipeline.py +187 -0
  244. assertpy-2.35.0/tests/test_poll_parity.py +388 -0
  245. assertpy-2.35.0/tests/test_poll_protocols.py +489 -0
  246. assertpy-2.35.0/tests/test_prerequisites.py +376 -0
  247. assertpy-2.35.0/tests/test_property_attrs.py +123 -0
  248. assertpy-2.35.0/tests/test_property_based.py +3140 -0
  249. assertpy-2.35.0/tests/test_protocol_parity.py +698 -0
  250. assertpy-2.35.0/tests/test_public_surface.py +423 -0
  251. assertpy-2.35.0/tests/test_pyright_baseline.py +156 -0
  252. assertpy-2.35.0/tests/test_pytest_plugin.py +4426 -0
  253. assertpy-2.35.0/tests/test_recursive_assertion.py +227 -0
  254. assertpy-2.35.0/tests/test_recursive_compare.py +275 -0
  255. assertpy-2.35.0/tests/test_recursive_compare_attrs.py +81 -0
  256. assertpy-2.35.0/tests/test_recursive_compare_config.py +1509 -0
  257. assertpy-2.35.0/tests/test_recursive_compare_pydantic.py +466 -0
  258. assertpy-2.35.0/tests/test_refusal_frames.py +292 -0
  259. assertpy-2.35.0/tests/test_refusals.py +440 -0
  260. assertpy-2.35.0/tests/test_regex_groups.py +114 -0
  261. assertpy-2.35.0/tests/test_relative_tolerance.py +298 -0
  262. assertpy-2.35.0/tests/test_renamed.py +196 -0
  263. assertpy-2.35.0/tests/test_render_laws.py +651 -0
  264. assertpy-2.35.0/tests/test_requirement.py +673 -0
  265. assertpy-2.35.0/tests/test_rich_diff.py +2664 -0
  266. assertpy-2.35.0/tests/test_same_as.py +42 -0
  267. assertpy-2.35.0/tests/test_satisfy.py +651 -0
  268. assertpy-2.35.0/tests/test_skip_guard.py +240 -0
  269. assertpy-2.35.0/tests/test_snapshots.py +1975 -0
  270. assertpy-2.35.0/tests/test_soft.py +645 -0
  271. assertpy-2.35.0/tests/test_soft_fail.py +61 -0
  272. assertpy-2.35.0/tests/test_soft_summary_blocks.py +356 -0
  273. assertpy-2.35.0/tests/test_strict_reach.py +466 -0
  274. assertpy-2.35.0/tests/test_string.py +747 -0
  275. assertpy-2.35.0/tests/test_structural.py +5395 -0
  276. assertpy-2.35.0/tests/test_structure_sentence.py +539 -0
  277. assertpy-2.35.0/tests/test_surface_conformance.py +488 -0
  278. assertpy-2.35.0/tests/test_sync_eventually.py +312 -0
  279. assertpy-2.35.0/tests/test_text_relations.py +404 -0
  280. assertpy-2.35.0/tests/test_traceback.py +84 -0
  281. assertpy-2.35.0/tests/test_type.py +311 -0
  282. assertpy-2.35.0/tests/test_type_expression_failures.py +148 -0
  283. assertpy-2.35.0/tests/test_typing.py +922 -0
  284. assertpy-2.35.0/tests/test_typing_chain_corpus.py +38 -0
  285. assertpy-2.35.0/tests/test_typing_claims.py +195 -0
  286. assertpy-2.35.0/tests/test_typing_completeness.py +142 -0
  287. assertpy-2.35.0/tests/test_typing_conformance.py +489 -0
  288. assertpy-2.35.0/tests/test_typing_from_a_wheel.py +97 -0
  289. assertpy-2.35.0/tests/test_typing_harness.py +79 -0
  290. assertpy-2.35.0/tests/test_typing_http.py +98 -0
  291. assertpy-2.35.0/tests/test_typing_integrations.py +110 -0
  292. assertpy-2.35.0/tests/test_typing_negative.py +208 -0
  293. assertpy-2.35.0/tests/test_typing_promises.py +76 -0
  294. assertpy-2.35.0/tests/test_unrenderable_values.py +244 -0
  295. assertpy-2.35.0/tests/test_vacuity_contract.py +686 -0
  296. assertpy-2.35.0/tests/test_verdict_corpus.py +137 -0
  297. assertpy-2.35.0/tests/test_verdicts_held_to_python.py +294 -0
  298. assertpy-2.35.0/tests/test_warn.py +158 -0
  299. assertpy-2.35.0/tests/test_warn_on_failure.py +158 -0
  300. assertpy-2.35.0/tests/typing_cases.py +702 -0
  301. assertpy-2.35.0/tests/typing_chain_corpus_baseline.json +256 -0
  302. assertpy-2.35.0/tests/typing_harness.py +166 -0
  303. assertpy-2.35.0/tests/typing_http.py +81 -0
  304. assertpy-2.35.0/tests/typing_integrations.py +65 -0
  305. assertpy-2.35.0/tests/typing_integrations_baseline.py +94 -0
  306. assertpy-2.35.0/tests/typing_negative_baseline.py +562 -0
  307. assertpy-2.35.0/tests/typing_promises.py +288 -0
  308. assertpy-2.35.0/tests/verdict_corpus.py +632 -0
  309. assertpy-2.35.0/tests/verdict_golden.txt +127 -0
  310. assertpy-1.0/PKG-INFO +0 -62
  311. assertpy-1.0/assertpy/__init__.py +0 -3
  312. assertpy-1.0/assertpy/assertpy.py +0 -433
  313. assertpy-1.0/assertpy/base.py +0 -422
  314. assertpy-1.0/assertpy/collection.py +0 -194
  315. assertpy-1.0/assertpy/contains.py +0 -360
  316. assertpy-1.0/assertpy/date.py +0 -183
  317. assertpy-1.0/assertpy/dict.py +0 -234
  318. assertpy-1.0/assertpy/dynamic.py +0 -114
  319. assertpy-1.0/assertpy/exception.py +0 -111
  320. assertpy-1.0/assertpy/extracting.py +0 -229
  321. assertpy-1.0/assertpy/file.py +0 -223
  322. assertpy-1.0/assertpy/helpers.py +0 -242
  323. assertpy-1.0/assertpy/numeric.py +0 -511
  324. assertpy-1.0/assertpy/snapshot.py +0 -206
  325. assertpy-1.0/assertpy/string.py +0 -411
  326. assertpy-1.0/setup.cfg +0 -8
  327. assertpy-1.0/setup.py +0 -68
@@ -0,0 +1,34 @@
1
+ # .gitignore
2
+ *.py[cod]
3
+ .cache
4
+ .pytest_cache
5
+ __pycache__
6
+
7
+ # testing output
8
+ *.xml
9
+ *.log
10
+ cover
11
+ .coverage
12
+ htmlcov
13
+ .hypothesis
14
+ __snapshots
15
+ mycustompath
16
+
17
+ # packaging
18
+ MANIFEST
19
+ dist
20
+
21
+ # mac
22
+ .DS_Store
23
+
24
+ # venv
25
+ .venv
26
+
27
+ # IDE
28
+ /.idea
29
+ .vscode
30
+
31
+ # docs output
32
+ docs/build
33
+ docs/out
34
+ /site/
@@ -0,0 +1,148 @@
1
+ # Contributing
2
+
3
+ Contributions of docs, tests, or code are welcome.
4
+
5
+ ## Workflow
6
+
7
+ 1. For a new assertion or matcher, open an issue first. The API grows from demand, and a working
8
+ implementation on its own is not enough to land one
9
+ 2. Fork the repo
10
+ 3. Clone your fork (`git clone <your_fork_url>`)
11
+ 4. Create a branch (`git checkout -b my_branch`)
12
+ 5. Install dependencies with the [one sync command](#verification-pipeline) below, not a bare `uv sync`
13
+ 6. Make your changes
14
+ 7. Run the [verification pipeline](#verification-pipeline) and fix any issues
15
+ 8. Commit using [Conventional Commits](#commit-style)
16
+ 9. Push your branch (`git push origin my_branch`)
17
+ 10. Open a [Pull Request](http://github.com/assertpy/assertpy/pulls)
18
+
19
+ Read more about how pulls work on GitHub's [About pull requests](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) page.
20
+
21
+ ## Requirements
22
+
23
+ - Python 3.10+
24
+ - [uv](https://docs.astral.sh/uv/) as the package manager
25
+
26
+ ## Before you change a public signature
27
+
28
+ Read [ARCHITECTURE.md](ARCHITECTURE.md). Five files under `assertpy/_engine/` are generated, the public
29
+ surface is pinned by a recorded snapshot, and neither is discoverable from the files themselves.
30
+
31
+ ## Verification pipeline
32
+
33
+ Run all checks before submitting a PR. Every step must pass.
34
+
35
+ ### Install
36
+
37
+ A bare `uv sync` leaves out the optional libraries several tests import, and those tests then fail
38
+ rather than skip. Install exactly this set:
39
+
40
+ ```bash
41
+ uv sync --extra json --extra data --extra inline --group integrations --group docs-examples
42
+ ```
43
+
44
+ ### The main gate
45
+
46
+ ```bash
47
+ uv run ruff check .
48
+ uv run ruff format --check .
49
+ uv run ty check assertpy/ tests/test_typing.py
50
+ uv run pytest --cov=assertpy --cov-fail-under=100 --ignore=tests/test_docs_examples.py tests
51
+ uv run pytest tests/test_docs_examples.py tests/test_typing_claims.py
52
+ uv run --group docs mkdocs build --strict
53
+ ```
54
+
55
+ CI requires 100% code coverage.
56
+
57
+ ### Then once on the supported floor
58
+
59
+ Run the suite on Python 3.10 as well. This is not optional, and the block above does not cover it.
60
+
61
+ A union carries `__name__` from 3.14 onwards and not before. `logging.LoggerAdapter` became
62
+ subscriptable in 3.11. Neither difference is visible to a type checker told to target 3.10, and both
63
+ shipped as defects that every other gate passed.
64
+
65
+ Use a throwaway environment. `uv run --python 3.10` inside the project rebuilds `.venv` for that
66
+ version, and on Windows it can fail partway and leave you without pytest:
67
+
68
+ ```bash
69
+ uv venv /tmp/py310 --python 3.10
70
+
71
+ export VIRTUAL_ENV=/tmp/py310
72
+ uv pip install -e ".[json,data,inline]"
73
+ uv pip install pytest pytest-cov hypothesis ruff
74
+ uv pip install attrs pydantic requests httpx flask
75
+
76
+ /tmp/py310/bin/python -m pytest tests --ignore=tests/test_docs_examples.py -q
77
+ ```
78
+
79
+ `ruff` belongs in that list: the tests that compare a generated file against its generator shell out
80
+ to it, and without it they fail for a reason that has nothing to do with your change.
81
+
82
+ ### The four type checkers
83
+
84
+ Run these after the main gate, not before. `uv run --group typecheck` adds the checkers to the same
85
+ `.venv` and leaves them there, and a coverage run with them installed collects a different set:
86
+
87
+ ```bash
88
+ uv run --group typecheck mypy --strict --follow-imports=silent tests/test_typing.py
89
+ PYRIGHT_PYTHON_FORCE_VERSION=1.1.414 uv run --group typecheck pyright --pythonversion 3.14 tests/test_typing.py
90
+ uv run --group typecheck pyrefly check tests/test_typing.py
91
+ uv run --group typecheck pytest tests/test_pyright_baseline.py
92
+ ```
93
+
94
+ `PYRIGHT_PYTHON_FORCE_VERSION` picks the engine rather than the launcher. The `pyright` distribution on
95
+ PyPI is released separately from the npm engine it launches, and the two have drifted apart before: PyPI
96
+ stayed at 1.1.411 from June to September while npm shipped two builds. The baseline is recorded against
97
+ one engine, and `tests/typing_harness.py` pins the same build, so only this direct invocation needs the
98
+ variable.
99
+
100
+ `--pythonversion 3.14` is not decoration. Pyright reports against the interpreter it finds unless
101
+ told otherwise, and the count moves with it: 174 diagnostics for this package on 3.10 against 169 on
102
+ 3.14.
103
+
104
+ Without it a contributor on the supported floor meets a red baseline that says nothing about their
105
+ change. The baseline test passes the same target itself, so it gives one answer everywhere.
106
+
107
+ ### Three details that cost time if you meet them the hard way
108
+
109
+ - `ty check` is scoped on purpose. Run over the whole tree it reports hundreds of diagnostics from
110
+ `tests/`, which is full of deliberate negative typing cases: calls that must not type-check.
111
+ - `--all-extras` is not a shortcut for the sync line. Installing `allure` or `behave` makes 100%
112
+ coverage unreachable by construction, because the `except ImportError` branch guarding them stops
113
+ being executed. CI never installs them for the coverage job either.
114
+ - `tests/test_docs_examples.py` is run separately because it executes the snippets in `docs/`, which
115
+ needs the `docs-examples` group and a different collection.
116
+
117
+ ### When a gate says an answer moved
118
+
119
+ Two gates record what the library currently decides rather than what it should. Both fail on a change
120
+ and neither is a failure to paper over: read the diff, decide whether the change is meant to ship, then
121
+ re-record it in the same commit so the diff carries the decision into review.
122
+
123
+ ```bash
124
+ ASSERTPY_UPDATE_API=1 uv run pytest tests/test_api_compatibility.py # the public surface
125
+ ASSERTPY_UPDATE_VERDICTS=1 uv run pytest tests/test_verdict_corpus.py # what each input decides
126
+ ```
127
+
128
+ The second one's diff is the draft of the release's Behaviour changes section, so read it before
129
+ writing that section rather than after.
130
+
131
+ ## Commit style
132
+
133
+ Use [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `refactor:`, `test:`, `docs:`, `chore:`, etc.
134
+
135
+ ## Tests
136
+
137
+ Write tests for every new feature or bug fix. Use `assertpy` assertions in tests.
138
+
139
+ ## Documentation examples
140
+
141
+ Guide code blocks are type-checked in CI, and every page that can run in the suite is executed, with what
142
+ each block prints compared with the comment beside it, so an example you add has to run. A block that
143
+ cannot (pseudo-context, a deliberate failure, a rejected counter-example) is marked with an HTML comment
144
+ above the fence. `tests/test_docs_examples.py` lists the markers and what each one exempts, and it and
145
+ `tests/test_docs_typing.py` each name the pages they leave out, with the reason.
146
+
147
+ Setup a page assumes (a domain class, a repository, an HTTP response) goes in
148
+ `tests/docs_fixtures.py`, not into an extra block on the page.
@@ -1,4 +1,5 @@
1
1
  Copyright (c) 2015-2019, Activision Publishing, Inc.
2
+ Copyright (c) 2026, Solganis
2
3
  All rights reserved.
3
4
 
4
5
  Redistribution and use in source and binary forms, with or without modification,
@@ -13,7 +14,7 @@ are permitted provided that the following conditions are met:
13
14
 
14
15
  3. Neither the name of the copyright holder nor the names of its contributors
15
16
  may be used to endorse or promote products derived from this software without
16
- specific prior written permission.
17
+ specific prior written permission.
17
18
 
18
19
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
20
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -0,0 +1,324 @@
1
+ Metadata-Version: 2.5
2
+ Name: assertpy
3
+ Version: 2.35.0
4
+ Summary: Fluent, fully typed assertion library for Python: your type checker sees only the assertions that fit the value, and every failure carries a structured diff. Soft assertions, polling, inline snapshots, OpenAPI contracts.
5
+ Project-URL: Homepage, https://github.com/assertpy/assertpy
6
+ Project-URL: Repository, https://github.com/assertpy/assertpy
7
+ Project-URL: Issues, https://github.com/assertpy/assertpy/issues
8
+ Author-email: Justin Shacklette <justin@saturnboy.com>
9
+ Maintainer-email: Solganis <solganis.dev@gmail.com>
10
+ License-Expression: BSD-3-Clause
11
+ License-File: LICENSE
12
+ Keywords: assert,assert_that,assertion,assertpy,assertthat,fluent,matchers,pytest,test,testing,type-safe,unittest
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: BSD License
16
+ Classifier: Natural Language :: English
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
+ Classifier: Programming Language :: Python :: 3.15
26
+ Classifier: Topic :: Software Development
27
+ Classifier: Topic :: Software Development :: Testing
28
+ Requires-Python: >=3.10
29
+ Requires-Dist: typing-extensions>=4.0; python_version < '3.11'
30
+ Provides-Extra: allure
31
+ Requires-Dist: allure-pytest>=2.13; extra == 'allure'
32
+ Provides-Extra: behave
33
+ Requires-Dist: behave>=1.3.0; extra == 'behave'
34
+ Provides-Extra: data
35
+ Requires-Dist: numpy>=1.26; extra == 'data'
36
+ Requires-Dist: pandas>=2.0; extra == 'data'
37
+ Requires-Dist: polars>=1.0; extra == 'data'
38
+ Provides-Extra: inline
39
+ Requires-Dist: asttokens>=2.0.4; extra == 'inline'
40
+ Requires-Dist: executing>=2.2; extra == 'inline'
41
+ Provides-Extra: json
42
+ Requires-Dist: idna>=3.7; extra == 'json'
43
+ Requires-Dist: jsonpath-ng>=1.8; extra == 'json'
44
+ Requires-Dist: jsonschema>=4.18; extra == 'json'
45
+ Requires-Dist: referencing>=0.28.4; extra == 'json'
46
+ Provides-Extra: numpy
47
+ Requires-Dist: numpy>=1.26; extra == 'numpy'
48
+ Provides-Extra: pandas
49
+ Requires-Dist: pandas>=2.0; extra == 'pandas'
50
+ Provides-Extra: polars
51
+ Requires-Dist: polars>=1.0; extra == 'polars'
52
+ Description-Content-Type: text/markdown
53
+
54
+ <p align="center">
55
+ <picture>
56
+ <source media="(prefers-color-scheme: dark)" srcset="docs/logo-dark.svg">
57
+ <source media="(prefers-color-scheme: light)" srcset="docs/logo.svg">
58
+ <img src="docs/logo.svg" alt="assertpy" width="280">
59
+ </picture>
60
+ <br>
61
+ <b>Fully typed fluent assertion library for Python</b>
62
+ </p>
63
+
64
+ <p align="center">
65
+ <a href="https://github.com/assertpy/assertpy/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/assertpy/assertpy/ci.yml?branch=main&amp;label=CI" alt="CI"></a>
66
+ <a href="https://codecov.io/gh/assertpy/assertpy"><img src="https://codecov.io/gh/assertpy/assertpy/graph/badge.svg" alt="Coverage"></a>
67
+ <a href="https://pypi.org/project/assertpy/"><img src="https://img.shields.io/pypi/v/assertpy" alt="PyPI version"></a>
68
+ <a href="https://pypi.org/project/assertpy/"><img src="https://img.shields.io/pypi/pyversions/assertpy" alt="Python"></a>
69
+ <a href="https://pepy.tech/projects/assertpy"><img src="https://static.pepy.tech/badge/assertpy/month" alt="Downloads"></a>
70
+ <br>
71
+ <a href="https://assertpy.github.io/assertpy/concepts/type-safety/"><img src="https://img.shields.io/badge/overloads-ty%20%7C%20mypy%20%7C%20pyright%20%7C%20pyrefly-2ea043" alt="every public overload checked by ty, mypy --strict, pyright and pyrefly with zero suppressions"></a>
72
+ <a href="https://assertpy.github.io/assertpy/"><img src="https://img.shields.io/badge/docs-online-black" alt="Documentation"></a>
73
+ <a href="https://scorecard.dev/viewer/?uri=github.com/assertpy/assertpy"><img src="https://img.shields.io/ossf-scorecard/github.com/assertpy/assertpy?label=OpenSSF%20Scorecard" alt="OpenSSF Scorecard"></a>
74
+ </p>
75
+
76
+ <h2 align="center"><a href="https://assertpy.github.io/assertpy/getting-started/quickstart/">Quick start</a></h2>
77
+
78
+ ```bash
79
+ pip install assertpy
80
+ ```
81
+
82
+ ```python
83
+ from assertpy import assert_that
84
+
85
+ def test_user():
86
+ user = {"name": "Alice", "age": 30, "roles": ["viewer", "editor"]}
87
+
88
+ assert_that(user).contains_key("name", "age")
89
+ assert_that(user).contains_entry({"name": "Alice"})
90
+ assert_that(user["age"]).is_between(18, 120)
91
+ assert_that(user["roles"]).contains("viewer").does_not_contain("admin")
92
+ ```
93
+
94
+ The [full documentation](https://assertpy.github.io/assertpy/) covers every assertion, matcher, and integration.
95
+
96
+ <table>
97
+ <tr>
98
+ <td valign="top" width="50%">
99
+ <a href="#why-fluent-assertions"><b>Failures that point at the difference</b></a><br>
100
+ A recursive diff names the exact path that differs, in color, instead of dumping both structures
101
+ </td>
102
+ <td valign="top" width="50%">
103
+ <a href="#type-aware-autocomplete"><b>Type-aware autocomplete</b></a><br>
104
+ <code>assert_that()</code> returns a protocol per value type, so your IDE offers the methods that fit
105
+ </td>
106
+ </tr>
107
+ <tr>
108
+ <td valign="top">
109
+ <a href="#typed-narrowing"><b>Typed narrowing</b></a><br>
110
+ An assertion hands the value back statically narrowed, with no <code>cast</code> and no bare <code>assert</code>
111
+ </td>
112
+ <td valign="top">
113
+ <a href="#features"><b>Composable matchers</b></a><br>
114
+ 45 matchers that combine with <code>&amp;</code>, <code>|</code>, <code>~</code> and nest inside the expected structure itself
115
+ </td>
116
+ </tr>
117
+ <tr>
118
+ <td valign="top">
119
+ <a href="#features"><b>Built for test suites</b></a><br>
120
+ Soft assertions, polling for eventual consistency, snapshots, and expected-exception chains
121
+ </td>
122
+ <td valign="top">
123
+ <a href="#integrations"><b>Integrations</b></a><br>
124
+ Allure, Behave, JSON Path and Schema, pandas, polars, numpy, and OpenAPI response contracts
125
+ </td>
126
+ </tr>
127
+ </table>
128
+
129
+ <h2 align="center"><a href="https://assertpy.github.io/assertpy/getting-started/comparison/">Why fluent assertions?</a></h2>
130
+
131
+ `assert` states a condition well. pytest reports it well.
132
+
133
+ What it cannot say is *where* two structures differ. It prints both and leaves the reading to you:
134
+
135
+ ```text
136
+ assert response == expected
137
+ E AssertionError: assert {'id': 1, ...} == {'id': 1, ...}
138
+ E Omitting 1 identical items, use -vv to show
139
+ E Differing items:
140
+ E {'user': {'name': 'Alice', 'role': 'superadmin'}} != {'user': {'name': 'Alice', 'role': 'admin'}}
141
+ E {'status': 'active'} != {'status': 'disabled'}
142
+ ```
143
+
144
+ assertpy names the [exact path](https://assertpy.github.io/assertpy/guides/errors/#rich-pytest-diffs), in color:
145
+
146
+ <!-- docs-guard: skip -->
147
+ ```python
148
+ assert_that(response).is_equal_to(expected)
149
+ ```
150
+
151
+ <p align="center">
152
+ <img src="https://raw.githubusercontent.com/assertpy/assertpy/main/docs/assets/diff-equal.png" width="300" alt="Structured diff in the terminal: user.role shown with its path, removal in red and addition in green">
153
+ </p>
154
+
155
+ It recurses through nested containers. Matcher predicates get the same treatment.
156
+
157
+ For dynamic fields like IDs, assert a subset with
158
+ [`matches_structure()`](https://assertpy.github.io/assertpy/guides/matchers/#structural-matching).
159
+
160
+ The chain is the other half. Your IDE offers only the
161
+ [methods that fit the value](https://assertpy.github.io/assertpy/concepts/type-safety/).
162
+
163
+ <!-- docs-guard: skip -->
164
+ ```python
165
+ assert_that(items).is_instance_of(list).is_length(3).contains("admin")
166
+ ```
167
+
168
+ Matchers are ordinary values that answer `==`, the way `unittest.mock.ANY` does.
169
+
170
+ Nothing is patched, so a matcher can sit inside the expected structure at any depth:
171
+
172
+ ```python
173
+ response = {"id": 7, "user": {"name": "Alice", "age": 30}, "tags": ["a", "b"]}
174
+
175
+ assert_that(response).is_equal_to(
176
+ {
177
+ "id": match.greater_than(0),
178
+ "user": {"name": "Alice", "age": match.between(18, 120)},
179
+ "tags": ["a", "b"],
180
+ }
181
+ )
182
+
183
+ # or keep the bare `assert`, and pytest's own rewriting reports it
184
+ assert response == {
185
+ "id": match.greater_than(0),
186
+ "user": match.ignore(),
187
+ "tags": ["a", "b"],
188
+ }
189
+ ```
190
+
191
+ The fluent form keeps the path-level diff, the bare form keeps pytest's.
192
+
193
+ There are [45 matchers](https://assertpy.github.io/assertpy/guides/matchers/), combining with `&`, `|` and `~`.
194
+
195
+ <p align="center">
196
+ <img src="https://raw.githubusercontent.com/assertpy/assertpy/main/docs/assets/diff-gallery.png" width="640" alt="Structured diffs in the terminal: dict path, list element, set extra/missing, and structural-matcher predicate diffs, side by side">
197
+ </p>
198
+
199
+ <h2 align="center"><a href="https://assertpy.github.io/assertpy/concepts/type-safety/">Type-aware autocomplete</a></h2>
200
+
201
+ `assert_that()` uses `@overload` to return type-specific Protocols.<br>
202
+ Your IDE shows only methods relevant to the value you're testing, not the whole surface:
203
+
204
+ - `assert_that("hello").` &rarr; string methods: `starts_with`, `matches`, `is_alpha`, ...
205
+ - `assert_that(42).` &rarr; numeric methods: `is_positive`, `is_between`, `is_close_to`, ...
206
+ - `assert_that(Path("/tmp")).` &rarr; path methods: `exists`, `is_file`, `is_readable`, ...
207
+ - `assert_that(my_dict).` &rarr; dict methods: `contains_key`, `contains_entry`, `has_json_path`, ...
208
+ - `assert_that(b"\x89PNG").` &rarr; bytes methods: `starts_with_bytes`, `is_valid_utf8`, `decoded_as`, ...
209
+
210
+ 15 type-specific Protocols instead of one `Any`<br>
211
+ Works in PyCharm, VS Code, and any editor that runs a type checker
212
+
213
+ <h2 align="center"><a href="https://assertpy.github.io/assertpy/concepts/type-safety/#typed-narrowing-with-value">Typed narrowing</a></h2>
214
+
215
+ An assertion hands the value back, statically narrowed.
216
+
217
+ `is_not_none()` strips `None`, `is_instance_of()` narrows to the class, and `.value` returns it:
218
+
219
+ <!-- docs-guard: skip -->
220
+ ```python
221
+ order = assert_that(repo.find(42)).is_not_none().is_instance_of(PaidOrder).value
222
+ order.refund() # statically PaidOrder - verified by ty, mypy, pyright and pyrefly
223
+ ```
224
+
225
+ For API tests,
226
+ [`assert_conforms()`](https://assertpy.github.io/assertpy/concepts/type-safety/#contract-narrowing-with-assert_conforms)
227
+ validates a payload against a Pydantic model and narrows to it. `exact=True` catches contract drift:
228
+
229
+ <!-- docs-guard: skip -->
230
+ ```python
231
+ data = assert_conforms(response.json(), OrderModel).value # data: OrderModel
232
+ ```
233
+
234
+ <h2 align="center"><a href="https://assertpy.github.io/assertpy/guides/errors/#asking-instead-of-asserting">A failure you can read from code</a></h2>
235
+
236
+ An exception is the right default. Reading the result means catching it.
237
+
238
+ `check()` runs the next assertion for its verdict instead:
239
+
240
+ ```python
241
+ response = {"user": {"name": "Alice", "role": "superadmin"}, "status": "active"}
242
+ expected = {"user": {"name": "Alice", "role": "admin"}, "status": "active"}
243
+
244
+ outcome = assert_that(response).check().is_equal_to(expected)
245
+
246
+ if not outcome and outcome.diff:
247
+ print(outcome.diff.entries[0].path) # user.role
248
+ ```
249
+
250
+ It is truthy when the assertion held. When it did not, it carries `.message`, `.actual`, `.expected`
251
+ and a walkable `.diff`. So does `AssertionFailure`.
252
+
253
+ So a reporter reads structure instead of parsing a string. That is how the
254
+ [Allure integration](https://assertpy.github.io/assertpy/extending/integrations/#allure) works.
255
+ Anything else you build can too.
256
+
257
+ <h2 align="center">Features</h2>
258
+
259
+ **Fluent API**
260
+
261
+ - [**Structural matching**](https://assertpy.github.io/assertpy/guides/matchers/#structural-matching): `matches_structure()` for declarative dict/API-response validation
262
+ - [**Recursive field assertions**](https://assertpy.github.io/assertpy/guides/assertions/#recursive-field-assertions): `all_fields_satisfy()` / `has_no_none_fields()` apply a predicate to every leaf of an object graph
263
+ - [**Universal negation**](https://assertpy.github.io/assertpy/guides/fluent/#universal-negation): `.not_` inverts any assertion, no dedicated `is_not_*` methods
264
+ - [**Collection pipeline**](https://assertpy.github.io/assertpy/guides/fluent/#collection-pipeline): `filtered_on()`, `mapped()`, `flat_mapped()`, `first()`, `last()`, `element()`, `single()`
265
+ - [**Positional & pairwise checks**](https://assertpy.github.io/assertpy/guides/assertions/#lists): `satisfies_exactly()`, `zip_satisfies()`, `contains_only_once()`, `has_same_size_as()`, plus `*_in_any_order` variants
266
+
267
+ **Type safety**
268
+
269
+ - [**Refinement predicates**](https://assertpy.github.io/assertpy/concepts/type-safety/#refinement-narrowing-with-a-typeis-predicate-advanced): `satisfies()` takes a `TypeIs` predicate, so a domain check narrows the chain too
270
+ - [**Contract testing**](https://assertpy.github.io/assertpy/concepts/type-safety/#contract-narrowing-with-assert_conforms): `assert_conforms()` validates a raw payload against a Pydantic model and narrows to it. [`exact=True`](https://assertpy.github.io/assertpy/concepts/type-safety/#contract-drift-with-exacttrue) catches contract drift, `each=True` validates list endpoints
271
+
272
+ **Built-in types**
273
+
274
+ - [Strings](https://assertpy.github.io/assertpy/guides/assertions/#strings), [numbers](https://assertpy.github.io/assertpy/guides/assertions/#numbers), [lists](https://assertpy.github.io/assertpy/guides/assertions/#lists), [tuples](https://assertpy.github.io/assertpy/guides/assertions/#tuples), [sets](https://assertpy.github.io/assertpy/guides/assertions/#sets), [dicts](https://assertpy.github.io/assertpy/guides/assertions/#dicts), [dates](https://assertpy.github.io/assertpy/guides/assertions/#dates), [booleans](https://assertpy.github.io/assertpy/guides/assertions/#booleans), [objects](https://assertpy.github.io/assertpy/guides/assertions/#objects), [bytes](https://assertpy.github.io/assertpy/guides/assertions/#bytes--bytearray), [files](https://assertpy.github.io/assertpy/guides/assertions/#files), [exceptions](https://assertpy.github.io/assertpy/guides/errors/#expected-exceptions)
275
+ - [**Bytes assertions**](https://assertpy.github.io/assertpy/guides/assertions/#bytes--bytearray): `is_valid_utf8()`, `starts_with_bytes()`, `is_hex_equal_to()`, `decoded_as()` for `bytes`/`bytearray`
276
+ - [**Dynamic assertions**](https://assertpy.github.io/assertpy/guides/assertions/#dynamic-assertions-on-objects): `has_<name>()` for any attribute, property, or zero-argument method
277
+ - [**Dict comparison**](https://assertpy.github.io/assertpy/guides/assertions/#selective-comparison-ignore--include): `is_equal_to(ignore=..., include=...)` for selective key/field matching by name, regex, or type
278
+ - [**Recursive comparison**](https://assertpy.github.io/assertpy/guides/assertions/#recursive-comparison-tolerance--custom-comparators): `is_equal_to()` with `tolerance`, `comparators`, or `ignore_null` for nested structures
279
+ - [**Extracting**](https://assertpy.github.io/assertpy/guides/assertions/#extracting-attributes-from-objects): flatten collections on attributes with `filter` and `sort` support
280
+ - [**Regex group extraction**](https://assertpy.github.io/assertpy/guides/data/#regex-group-extraction): `extracting_group()` and `matches_with_groups()` for regex captures
281
+
282
+ **Testing**
283
+
284
+ - [**Soft assertions**](https://assertpy.github.io/assertpy/guides/testing/#soft-assertions): thread-safe and async-safe via `contextvars`, each failure reported with its `file:line`. Group with `sa.group()` or `assert_all()`
285
+ - [**Polling assertions**](https://assertpy.github.io/assertpy/guides/testing/#async-assertions): `eventually()` (async) / `eventually_sync()` (blocking) retry for eventual consistency, with a convergence trace on timeout
286
+ - [**Expected exceptions**](https://assertpy.github.io/assertpy/guides/errors/#expected-exceptions): `raises().when_called_with()`, walk the cause chain (`caused_by()`, `has_root_cause()`), search an `ExceptionGroup` (`contains_error()`, `errors()`, `error_of()`), or pivot to the object (`raised()`)
287
+ - [**HTTP responses**](https://assertpy.github.io/assertpy/recipes/#test-an-http-api-response): assert on the response itself and every failure names the request it came from, with `decoded_as_json()` to step into the body. No client library is a dependency
288
+ - [**Snapshot testing**](https://assertpy.github.io/assertpy/guides/testing/#snapshot-testing): an external JSON file, an [inline](https://assertpy.github.io/assertpy/guides/testing/#inline-snapshots) value recorded into the test source, or a [value-tolerant contract](https://assertpy.github.io/assertpy/guides/testing/#contract-snapshots), all updated with `--assertpy-snapshot-update`
289
+ - [**OpenAPI response contracts**](https://assertpy.github.io/assertpy/reference/json/#assertpy.json_mixin.JsonMixin.conforms_to_openapi): `conforms_to_openapi()` checks a JSON body against an operation's response schema, reporting every violation with its JSON path
290
+
291
+ **Failure reporting**
292
+
293
+ - [**Structured errors**](https://assertpy.github.io/assertpy/guides/errors/#structured-errors): `AssertionFailure` carries `.actual`, `.expected` and `.diff`, and the diff renders into the message, so it shows off pytest too
294
+ - [**Assertions as values**](https://assertpy.github.io/assertpy/guides/errors/#asking-instead-of-asserting): `check()` runs the next assertion for its verdict instead of raising, handing back an `AssertionOutcome`
295
+ - [**Rich pytest diffs**](https://assertpy.github.io/assertpy/guides/errors/#rich-pytest-diffs): recursive diffs across containers, dataclasses, attrs and Pydantic models, with intra-line carets for strings
296
+ - [**Failures that say why**](https://assertpy.github.io/assertpy/guides/errors/#some-failures-say-why-not-only-what): where one fact explains a failure, a line under the message says it. An id the payload holds as text (`7` against `"7"`), a NaN, two instances compared by identity, surrounding whitespace. A failed `contains()` or `is_in()` names the closest row, and forty rows that differ in one field are named as one place
297
+
298
+ **Plugin for pytest**
299
+
300
+ Set from the command line or from `[tool.pytest.ini_options]`, not from a call
301
+
302
+ - [**Failure clustering**](https://assertpy.github.io/assertpy/guides/errors/#what-the-failures-had-in-common): forty failing tests are usually not forty problems. Where three or more differ at the same place, the run ends with a line saying where. On by default, `assertpy_failure_clusters = "off"` turns it off
303
+ - [**IDE comparison window**](https://assertpy.github.io/assertpy/guides/errors/#the-comparison-window-of-an-ide): a failed `is_equal_to()` or `has_<name>()` gets PyCharm's "Click to see difference" link, as a plain `assert` does, and the window shows the two values it compared. Under `ignore=` or `include=` those go without the keys left out. The plugin hands them to `pytest_assertrepr_compare`, the hook the IDE's runner listens to. On by default, `assertpy_comparison = "off"` turns it off
304
+ - [**Diagnostic profiles**](https://assertpy.github.io/assertpy/guides/errors/#configuration): `assertpy_profile` turns the guards below on in one line. `compatible` (default) leaves them off, `safe` warns, `strict` fails the tests they find. A setting you name yourself still wins
305
+ - [**Vacuous-assertion guard**](https://assertpy.github.io/assertpy/guides/assertions/#assertions-that-checked-nothing): `--assertpy-vacuous` warns when a universal assertion passes over an empty collection, having checked nothing
306
+ - [**Dangling-assertion detector**](https://assertpy.github.io/assertpy/guides/assertions/#assertions-that-never-ran): `--assertpy-dangling` warns when a chain builds an assertion and never runs it. `assert assert_that(x).is_positive` passes on any value, and neither ruff nor coverage sees it
307
+
308
+ **Extensibility**
309
+
310
+ - [**Custom matchers**](https://assertpy.github.io/assertpy/guides/matchers/#custom-matchers): `register_matcher()` composes existing ones, `BaseMatcher` carries its own predicate. Both compose with `&`, `|`, `~`
311
+ - [**Custom assertions**](https://assertpy.github.io/assertpy/extending/custom-assertions/): `add_extension()` adds a method to the builder
312
+
313
+ <h2 align="center"><a href="https://assertpy.github.io/assertpy/extending/integrations/">Integrations</a></h2>
314
+
315
+ - [**Allure**](https://assertpy.github.io/assertpy/extending/integrations/#allure) (`pip install assertpy[allure]`): the pytest plugin auto-attaches structured diff and actual/expected data to Allure reports, in three configurable modes
316
+ - [**Behave**](https://assertpy.github.io/assertpy/extending/integrations/#behave) (`pip install assertpy[behave]`): ready-made parameter types (`PositiveInt`, `NonEmptyString`, ...) for step definitions like `{age:PositiveInt}`
317
+ - [**JSON**](https://assertpy.github.io/assertpy/guides/data/#json-path--schema) (`pip install assertpy[json]`): JSONPath navigation (`at_json_path()`, `has_json_path()`) and JSON Schema validation (`matches_json_schema()`)
318
+ - [**Data frames**](https://assertpy.github.io/assertpy/extending/integrations/#data-frames-and-arrays) (`pip install assertpy[pandas]` / `[polars]` / `[numpy]`): fluent equality for pandas/polars frames and numpy arrays, carrying each library's own diff
319
+
320
+ ---
321
+
322
+ <p align="center">
323
+ <a href="https://github.com/assertpy/assertpy/blob/main/LICENSE">BSD 3-Clause License</a>
324
+ </p>