summaryrefslogtreecommitdiff
path: root/pkgs/development/python-modules/hypothesis/default.nix
blob: 25c4db7fb3ebe2e2f71e3b1012d9734d1f818466 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
{
  lib,
  buildPythonPackage,
  isPyPy,
  fetchFromGitHub,
  setuptools,
  attrs,
  exceptiongroup,
  pexpect,
  doCheck ? true,
  pytestCheckHook,
  pytest-xdist,
  python,
  sortedcontainers,
  stdenv,
  pythonAtLeast,
  pythonOlder,
  sphinxHook,
  sphinx-rtd-theme,
  sphinx-hoverxref,
  sphinx-codeautolink,
  tzdata,
}:

buildPythonPackage rec {
  pname = "hypothesis";
  version = "6.145.1";
  pyproject = true;

  src = fetchFromGitHub {
    owner = "HypothesisWorks";
    repo = "hypothesis";
    tag = "hypothesis-python-${version}";
    hash = "sha256-xyUR3yY2tmF4LGhZRUlv6fdcfVyVWwukodA0WIW0bXU=";
  };

  # I tried to package sphinx-selective-exclude, but it throws
  # error about "module 'sphinx' has no attribute 'directives'".
  #
  # It probably has to do with monkey-patching internals of Sphinx.
  # On bright side, this extension does not introduces new commands,
  # only changes "::only" command, so we probably okay with stock
  # implementation.
  #
  # I wonder how upstream of "hypothesis" builds documentation.
  postPatch = ''
    sed -i -e '/sphinx_selective_exclude.eager_only/ d' docs/conf.py
  '';

  postUnpack = "sourceRoot=$sourceRoot/hypothesis-python";

  build-system = [ setuptools ];

  dependencies = [
    attrs
    sortedcontainers
  ]
  ++ lib.optionals (pythonOlder "3.11") [ exceptiongroup ];

  nativeCheckInputs = [
    pexpect
    pytest-xdist
    pytestCheckHook
  ]
  ++ lib.optionals isPyPy [ tzdata ];

  inherit doCheck;

  # tox.ini changes how pytest runs and breaks it.
  # Activate the CI profile (similar to setupHook below)
  # by setting HYPOTHESIS_PROFILE [1].
  #
  # [1]: https://github.com/HypothesisWorks/hypothesis/blob/hypothesis-python-6.130.9/hypothesis-python/tests/common/setup.py#L78
  preCheck = ''
    rm tox.ini
    export HYPOTHESIS_PROFILE=ci
  '';

  enabledTestPaths = [ "tests/cover" ];

  # Hypothesis by default activates several "Health Checks", including one that fires if the builder is "too slow".
  # This check is disabled [1] if Hypothesis detects a CI environment, i.e. either `CI` or `TF_BUILD` is defined [2].
  # We set `CI=1` here using a setup hook to avoid spurious failures [3].
  #
  # Example error message for reference:
  # 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).
  #
  # [1]: https://github.com/HypothesisWorks/hypothesis/blob/hypothesis-python-6.130.9/hypothesis-python/src/hypothesis/_settings.py#L816-L828
  # [2]: https://github.com/HypothesisWorks/hypothesis/blob/hypothesis-python-6.130.9/hypothesis-python/src/hypothesis/_settings.py#L756
  # [3]: https://github.com/NixOS/nixpkgs/issues/393637
  setupHook = ./setup-hook.sh;

  disabledTests = [
    # racy, fails to find a file sometimes
    "test_recreate_charmap"
    "test_uses_cached_charmap"
    # fail when using CI profile
    "test_given_does_not_pollute_state"
    "test_find_does_not_pollute_state"
    "test_does_print_on_reuse_from_database"
    "test_prints_seed_only_on_healthcheck"
    # calls script with the naked interpreter
    "test_constants_from_running_file"
  ]
  ++ lib.optionals (pythonAtLeast "3.12") [
    # AssertionError: assert [b'def      \...   f(): pass'] == [b'def\\', b'    f(): pass']
    # https://github.com/HypothesisWorks/hypothesis/issues/4355
    "test_clean_source"
  ]
  ++ lib.optionals (pythonAtLeast "3.14") [
    "test_attrs_inference_builds"
    "test_bound_missing_dot_access_forward_ref"
    "test_bound_missing_forward_ref"
    "test_bound_type_checking_only_forward_ref_wrong_type"
    "test_bound_type_cheking_only_forward_ref"
    "test_builds_suggests_from_type"
    "test_bytestring_not_treated_as_generic_sequence"
    "test_evil_prng_registration_nonsense"
    "test_issue_4194_regression"
    "test_passing_referenced_instance_within_function_scope_warns"
    "test_registering_a_Random_is_idempotent"
    "test_register_random_within_nested_function_scope"
    "test_resolve_fwd_refs"
    "test_resolves_forwardrefs_to_builtin_types"
    "test_resolving_standard_collection_as_generic"
    "test_resolving_standard_container_as_generic"
    "test_resolving_standard_contextmanager_as_generic"
    "test_resolving_standard_iterable_as_generic"
    "test_resolving_standard_reversible_as_generic"
    "test_resolving_standard_sequence_as_generic"
    "test_specialised_collection_types"
  ];

  pythonImportsCheck = [ "hypothesis" ];

  passthru = {
    doc = stdenv.mkDerivation {
      # Forge look and feel of multi-output derivation as best as we can.
      #
      # Using 'outputs = [ "doc" ];' breaks a lot of assumptions.
      pname = "${pname}-doc";
      inherit src version;

      postInstallSphinx = ''
        mv $out/share/doc/* $out/share/doc/python$pythonVersion-$pname-$version
      '';

      nativeBuildInputs = [
        sphinxHook
        sphinx-rtd-theme
        sphinx-hoverxref
        sphinx-codeautolink
      ];

      inherit (python) pythonVersion;
      inherit meta;
    };
  };

  meta = {
    description = "Library for property based testing";
    mainProgram = "hypothesis";
    homepage = "https://github.com/HypothesisWorks/hypothesis";
    changelog = "https://hypothesis.readthedocs.io/en/latest/changes.html#v${
      lib.replaceStrings [ "." ] [ "-" ] version
    }";
    license = lib.licenses.mpl20;
    maintainers = [
      lib.maintainers.fliegendewurst
    ];
  };
}