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.131.17";
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-bNaDC2n0VaI7L4/FdD8eQ4cqn5ewquy89wV/pQn9uo0=";
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 ]
60 ++ lib.optionals (pythonOlder "3.11") [ exceptiongroup ];
61
62 nativeCheckInputs = [
63 pexpect
64 pytest-xdist
65 pytestCheckHook
66 ]
67 ++ lib.optionals isPyPy [ tzdata ];
68
69 inherit doCheck;
70
71 # tox.ini changes how pytest runs and breaks it.
72 # Activate the CI profile (similar to setupHook below)
73 # by setting HYPOTHESIS_PROFILE [1].
74 #
75 # [1]: https://github.com/HypothesisWorks/hypothesis/blob/hypothesis-python-6.130.9/hypothesis-python/tests/common/setup.py#L78
76 preCheck = ''
77 rm tox.ini
78 export HYPOTHESIS_PROFILE=ci
79 '';
80
81 enabledTestPaths = [ "tests/cover" ];
82
83 # Hypothesis by default activates several "Health Checks", including one that fires if the builder is "too slow".
84 # This check is disabled [1] if Hypothesis detects a CI environment, i.e. either `CI` or `TF_BUILD` is defined [2].
85 # We set `CI=1` here using a setup hook to avoid spurious failures [3].
86 #
87 # Example error message for reference:
88 # 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).
89 #
90 # [1]: https://github.com/HypothesisWorks/hypothesis/blob/hypothesis-python-6.130.9/hypothesis-python/src/hypothesis/_settings.py#L816-L828
91 # [2]: https://github.com/HypothesisWorks/hypothesis/blob/hypothesis-python-6.130.9/hypothesis-python/src/hypothesis/_settings.py#L756
92 # [3]: https://github.com/NixOS/nixpkgs/issues/393637
93 setupHook = ./setup-hook.sh;
94
95 disabledTests = [
96 # racy, fails to find a file sometimes
97 "test_recreate_charmap"
98 "test_uses_cached_charmap"
99 # fail when using CI profile
100 "test_given_does_not_pollute_state"
101 "test_find_does_not_pollute_state"
102 "test_does_print_on_reuse_from_database"
103 "test_prints_seed_only_on_healthcheck"
104 # calls script with the naked interpreter
105 "test_constants_from_running_file"
106 ]
107 ++ lib.optionals (pythonOlder "3.10") [
108 # not sure why these tests fail with only 3.9
109 # FileNotFoundError: [Errno 2] No such file or directory: 'git'
110 "test_observability"
111 "test_assume_has_status_reason"
112 "test_observability_captures_stateful_reprs"
113 ]
114 ++ lib.optionals (pythonAtLeast "3.12") [
115 # AssertionError: assert [b'def \... f(): pass'] == [b'def\\', b' f(): pass']
116 # https://github.com/HypothesisWorks/hypothesis/issues/4355
117 "test_clean_source"
118 ];
119
120 pythonImportsCheck = [ "hypothesis" ];
121
122 passthru = {
123 doc = stdenv.mkDerivation {
124 # Forge look and feel of multi-output derivation as best as we can.
125 #
126 # Using 'outputs = [ "doc" ];' breaks a lot of assumptions.
127 name = "${pname}-${version}-doc";
128 inherit src pname version;
129
130 postInstallSphinx = ''
131 mv $out/share/doc/* $out/share/doc/python$pythonVersion-$pname-$version
132 '';
133
134 nativeBuildInputs = [
135 sphinxHook
136 sphinx-rtd-theme
137 sphinx-hoverxref
138 sphinx-codeautolink
139 ];
140
141 inherit (python) pythonVersion;
142 inherit meta;
143 };
144 };
145
146 meta = {
147 description = "Library for property based testing";
148 mainProgram = "hypothesis";
149 homepage = "https://github.com/HypothesisWorks/hypothesis";
150 changelog = "https://hypothesis.readthedocs.io/en/latest/changes.html#v${
151 lib.replaceStrings [ "." ] [ "-" ] version
152 }";
153 license = lib.licenses.mpl20;
154 maintainers = [
155 lib.maintainers.fliegendewurst
156 ];
157 };
158}