1{
2 lib,
3 buildPythonPackage,
4 isPyPy,
5 fetchFromGitHub,
6 setuptools,
7 attrs,
8 exceptiongroup,
9 pexpect,
10 doCheck ? true,
11 pytestCheckHook,
12 pytest-xdist,
13 python,
14 sortedcontainers,
15 stdenv,
16 pythonAtLeast,
17 pythonOlder,
18 sphinxHook,
19 sphinx-rtd-theme,
20 sphinx-hoverxref,
21 sphinx-codeautolink,
22 tzdata,
23}:
24
25buildPythonPackage rec {
26 pname = "hypothesis";
27 version = "6.130.12";
28 pyproject = true;
29
30 disabled = pythonOlder "3.9";
31
32 src = fetchFromGitHub {
33 owner = "HypothesisWorks";
34 repo = "hypothesis";
35 rev = "hypothesis-python-${version}";
36 hash = "sha256-6p7OCjeZKZJ+3MDfdi+9XffET95pXGC6nzhTiMiEVQA=";
37 };
38
39 # I tried to package sphinx-selective-exclude, but it throws
40 # error about "module 'sphinx' has no attribute 'directives'".
41 #
42 # It probably has to do with monkey-patching internals of Sphinx.
43 # On bright side, this extension does not introduces new commands,
44 # only changes "::only" command, so we probably okay with stock
45 # implementation.
46 #
47 # I wonder how upstream of "hypothesis" builds documentation.
48 postPatch = ''
49 sed -i -e '/sphinx_selective_exclude.eager_only/ d' docs/conf.py
50 '';
51
52 postUnpack = "sourceRoot=$sourceRoot/hypothesis-python";
53
54 build-system = [ setuptools ];
55
56 dependencies = [
57 attrs
58 sortedcontainers
59 ] ++ lib.optionals (pythonOlder "3.11") [ exceptiongroup ];
60
61 nativeCheckInputs = [
62 pexpect
63 pytest-xdist
64 pytestCheckHook
65 ] ++ lib.optionals isPyPy [ tzdata ];
66
67 inherit doCheck;
68
69 # tox.ini changes how pytest runs and breaks it.
70 # Activate the CI profile (similar to setupHook below)
71 # by setting HYPOTHESIS_PROFILE [1].
72 #
73 # [1]: https://github.com/HypothesisWorks/hypothesis/blob/hypothesis-python-6.130.9/hypothesis-python/tests/common/setup.py#L78
74 preCheck = ''
75 rm tox.ini
76 export HYPOTHESIS_PROFILE=ci
77 '';
78
79 pytestFlagsArray = [ "tests/cover" ];
80
81 # Hypothesis by default activates several "Health Checks", including one that fires if the builder is "too slow".
82 # This check is disabled [1] if Hypothesis detects a CI environment, i.e. either `CI` or `TF_BUILD` is defined [2].
83 # We set `CI=1` here using a setup hook to avoid spurious failures [3].
84 #
85 # Example error message for reference:
86 # hypothesis.errors.FailedHealthCheck: Data generation is extremely slow: Only produced 2 valid examples in 1.28 seconds (1 invalid ones and 0 exceeded maximum size). Try decreasing size of the data you're generating (with e.g. max_size or max_leaves parameters).
87 #
88 # [1]: https://github.com/HypothesisWorks/hypothesis/blob/hypothesis-python-6.130.9/hypothesis-python/src/hypothesis/_settings.py#L816-L828
89 # [2]: https://github.com/HypothesisWorks/hypothesis/blob/hypothesis-python-6.130.9/hypothesis-python/src/hypothesis/_settings.py#L756
90 # [3]: https://github.com/NixOS/nixpkgs/issues/393637
91 setupHook = ./setup-hook.sh;
92
93 disabledTests =
94 [
95 # racy, fails to find a file sometimes
96 "test_recreate_charmap"
97 "test_uses_cached_charmap"
98 # fail when using CI profile
99 "test_given_does_not_pollute_state"
100 "test_find_does_not_pollute_state"
101 "test_does_print_on_reuse_from_database"
102 "test_prints_seed_only_on_healthcheck"
103 # calls script with the naked interpreter
104 "test_constants_from_running_file"
105 ]
106 ++ lib.optionals (pythonOlder "3.10") [
107 # not sure why these tests fail with only 3.9
108 # FileNotFoundError: [Errno 2] No such file or directory: 'git'
109 "test_observability"
110 "test_assume_has_status_reason"
111 "test_observability_captures_stateful_reprs"
112 ]
113 ++ lib.optionals (pythonAtLeast "3.12") [
114 # AssertionError: assert [b'def \... f(): pass'] == [b'def\\', b' f(): pass']
115 # https://github.com/HypothesisWorks/hypothesis/issues/4355
116 "test_clean_source"
117 ];
118
119 pythonImportsCheck = [ "hypothesis" ];
120
121 passthru = {
122 doc = stdenv.mkDerivation {
123 # Forge look and feel of multi-output derivation as best as we can.
124 #
125 # Using 'outputs = [ "doc" ];' breaks a lot of assumptions.
126 name = "${pname}-${version}-doc";
127 inherit src pname version;
128
129 postInstallSphinx = ''
130 mv $out/share/doc/* $out/share/doc/python$pythonVersion-$pname-$version
131 '';
132
133 nativeBuildInputs = [
134 sphinxHook
135 sphinx-rtd-theme
136 sphinx-hoverxref
137 sphinx-codeautolink
138 ];
139
140 inherit (python) pythonVersion;
141 inherit meta;
142 };
143 };
144
145 meta = {
146 description = "Library for property based testing";
147 mainProgram = "hypothesis";
148 homepage = "https://github.com/HypothesisWorks/hypothesis";
149 changelog = "https://hypothesis.readthedocs.io/en/latest/changes.html#v${
150 lib.replaceStrings [ "." ] [ "-" ] version
151 }";
152 license = lib.licenses.mpl20;
153 maintainers = [
154 lib.maintainers.fliegendewurst
155 ];
156 };
157}