[
  {
    "path": ".claude/CLAUDE.md",
    "content": "# Hypothesis Development Guide\n\n## Essential Reading\n\n**Always read `CONTRIBUTING.rst` before starting work**, especially before writing tests or creating a PR.\n\n## Testing\n\n### Running Tests\n\nRun tests using the build system:\n- **Quick test run**: `./build.sh check-coverage` (curated subset with coverage verification)\n- **Python version-specific**: `./build.sh check-py311` (replace with target version)\n- **Fine-grained control**: `./build.sh tox py311-custom 3.11.3 -- [pytest args]`\n- **Direct pytest** (after setup): `pytest hypothesis-python/tests/cover/`\n\n### Writing Tests\n\n**Never use `.example()` method in tests.** Instead:\n- Use `@given` decorator directly for property-based tests\n- Use helper functions from `tests.common.debug`:\n  - `minimal()` - find minimal failing example\n  - `find_any()` - find any example matching condition\n  - `assert_all_examples()` - verify all examples match predicate\n  - `assert_simple_property()` - verify simple properties with few examples\n  - `check_can_generate_examples()` - verify strategy can generate without error\n\n## Changelog & Pull Requests\n\nWhen creating a PR that changes `hypothesis-python/src/`:\n1. Create `hypothesis-python/RELEASE.rst` with `RELEASE_TYPE: patch` (bugfixes) or `minor` (features)\n2. See `RELEASE-sample.rst` for examples\n3. **Imitate the style in `changelog.rst`** for consistency\n4. Follow all changelog instructions in `CONTRIBUTING.rst`\n\n**Note:** Test-only changes (no modifications to `src/`) do not require a RELEASE.rst file.\n\n## Before Committing\n\n1. Do a final edit pass on all code to ensure it is:\n   - **Concise** - remove unnecessary verbosity\n   - **Idiomatic** - follows Python and Hypothesis conventions\n   - **Minimally commented** - code should be self-documenting; only add comments where truly needed\n2. **Run `./build.sh format; ./build.sh lint`** immediately before committing to auto-format and lint code\n3. **Do not reference issues or PRs in commit messages** (e.g., avoid `Fixes #1234` or `See #5678`) - this clutters the issue timeline with unnecessary links\n"
  },
  {
    "path": ".claude/commands/hypothesis.md",
    "content": "---\ndescription: Write property-based tests with Hypothesis\n---\n\nYou are an expert developer of property-based tests, specifically using Hypothesis. Your goal is to identify and implement a small number of the most valuable Hypothesis tests that would benefit an existing codebase right now. You focus on clarity and maintainability, as your code will be reviewed by a developer. Your goal is to write precise tests, not comprehensive test suites.\n\nCreate and follow this todo list using the `Todo` tool:\n\n1. [ ] Explore the provided code and identify valuable properties.\n2. [ ] For each property, explore how its related code is used.\n3. [ ] Write Hypothesis tests based on those properties.\n4. [ ] Run the new Hypothesis tests, and reflect on the result.\n\n## 1. Explore the code provided and identify valuable properties\n\nFirst, explore the provided code, and identify valuable properties to test. A \"valuable property\" is an invariant or property about the code that is valuable to the codebase right now and that a knowledgeable developer for this codebase would have written a Hypothesis test for. The following are indicative of a valuable property:\n\n- Would catch important bugs: Testing this property would reveal bugs that could cause serious issues.\n- Documents important behavior: The property captures essential assumptions or guarantees that are important to future or current developers.\n- Benefits significantly from Hypothesis: The property is concisely and powerfully expressed as a Hypothesis test, rather than a series of unit tests.\n\nKeep the following in mind:\n\n- Only identify properties that you strongly believe to be true and that are supported by evidence in the codebase, for example in docstrings, comments, code use patterns, type hints, etc. Do not include properties you are at all unsure about.\n- Each property should provide a substantial improvement in testing power or clarity when expressed as a Hypothesis test, rather than a unit test. Properties which could have been equally well tested with a unit test are not particularly valuable.\n- You may come across many possible properties. Your goal is to identify only a small number of the most valuable of those properties that would benefit the codebase right now.\n\nIf the provided code is large, focus on exploring in this order:\n\n1. Public API functions/classes\n2. Well-documented implementations of core functionality\n3. Other implementations of core functionality\n4. Internal/private helpers or utilities\n\nHere are some examples of typical properties:\n\n- Round-trip property: `decode(encode(x)) = x`, `parse(format(x)) = x`.\n- Inverse relationship: `add/remove`, `push/pop`, `create/destroy`.\n- Multiple equivalent implementations: Optimized vs reference implementation, complicated vs simple implementation.\n- Mathematical property: Idempotence `f(f(x)) = f(x)`, commutativity `f(x, y) = f(y, x)`.\n- Invariants: `len(filter(x)) <= len(x)`, `set(sort(x)) == set(x)`.\n- Confluence: the order of function application doesn't matter (for example, in compiler optimization passes).\n- Metamorphic property: some relationship between `f(x)` and `g(x)` holds for all x. For example, `sin(π − x) = sin(x)`.\n- Single entry point. If a library has a narrow public API, a nice property-based test simply calls the library with valid inputs. Common in parsers.\n\nWhile the following should generally not be tested:\n\n- Obvious code wrappers\n- Implementation details\n\nThe user has provided the following guidance for where and how to add Hypothesis tests: <user_input>$ARGUMENTS</user_input>.\n\n- If the user has provided no direction, explore the entire codebase.\n- If the user has provided a specific module, explore that module.\n- If the user has provided a specific file, explore that file.\n- If the user has provided a specific function, explore that function.\n- If the user has given more complex guidance, follow that instead.\n\nIf you don't identify any valuable properties during exploration, that's fine; just tell the user as much, and then stop.\n\nAt the end of this step, you should tell the user the small list of the most valuable properties that you intend to test.\n\n## 2. For each valuable property, explore how its related code is used\n\nBefore writing Hypothesis tests, explore how the codebase uses the related code of each valuable property. For example, if a property involves a function `some_function`, explore how the codebase calls `some_function`: what kinds of inputs are passed to it? in what context? etc. This helps correct any misunderstanding about the property before writing a test for it.\n\n## 3. Write Hypothesis tests based on those properties.\n\nFor each property, write a new Hypothesis test for it, and add it to the codebase's test suite, following its existing testing conventions.\n\nWhen writing Hypothesis tests, follow these guidelines:\n\n- Each Hypothesis test should be both sound (tests only inputs the code can actually be called with) and complete (tests all inputs the code can actually be called with). Sometimes this is difficult. In those cases, prefer sound and mostly-complete tests; stopping at 90% completeness is better than over-complicating a test.\n- Only place constraints on Hypothesis strategies if required by the code. For example, prefer `st.lists(...)` (with no size bound) to `st.lists(..., max_size=100)`, unless the property explicitly happens to only be valid for lists with no more than 100 elements.\n\n## 4. Run the new Hypothesis tests, and reflect on the result.\n\nRun the new Hypothesis tests that you just added. If any fail, reflect on why. Is the test failing because of a genuine bug, or because it's not testing the right thing? Often, when a new Hypothesis test fails, it's because the test generates inputs that the codebase assumes will never occur. If necessary, re-explore related parts of the codebase to check your understanding. You should only report that the codebase has a bug to the user if you are truly confident, and can justify why.\n\n# Hypothesis Reference\n\nDocumentation reference (fetch with the `WebFetch` tool if required):\n\n- **Strategies API reference**: https://hypothesis.readthedocs.io/en/latest/reference/strategies.html\n- **Other API reference**: https://hypothesis.readthedocs.io/en/latest/reference/api.html\n  - Documents `@settings`, `@given`, etc.\n\nThese Hypothesis strategies are under-appreciated for how effective they are. Use them if they are a perfect or near-perfect fit for a property:\n\n- `st.from_regex`\n- `st.from_lark` - for context-free grammars\n- `st.functions` - generates arbitrary callable functions\n"
  },
  {
    "path": ".gitattributes",
    "content": "*    text eol=lf\n\n# Denote all files that are truly binary and should not be modified.\n*.png binary\n*.jpg binary\n*.gif binary\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "# Engine changes need to be approved by Zac-HD, as per\n# https://github.com/HypothesisWorks/hypothesis/blob/master/guides/review.rst#engine-changes\n/hypothesis-python/src/hypothesis/internal/conjecture/ @Zac-HD @Liam-DeVoe\n\n# Changes to the paper also need to be approved by DRMacIver or Zac, as authors\n/paper.md @DRMacIver @Zac-HD\n/paper.bib @DRMacIver @Zac-HD\n"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.rst",
    "content": "---------------\nCode of conduct\n---------------\n\nHypothesis's community is an inclusive space, and everyone in it is expected to abide by a code of conduct.\nThis applies in issues, pull requests, etc. as well as in the various Hypothesis community spaces.\n\nAt the high level the code of conduct goes like this:\n\n1. Be kind\n2. Be respectful\n3. Be helpful\n\nWhile it is impossible to enumerate everything that is unkind, disrespectful or unhelpful, here are some specific things that are definitely against the code of conduct:\n\n1. -isms and -phobias (e.g. racism, sexism, transphobia and homophobia) are unkind, disrespectful *and* unhelpful. Just don't.\n2. All software is broken. This is not a moral failing on the part of the authors. Don't give people a hard time for bad code.\n3. It's OK not to know things. Everybody was a beginner once, nobody should be made to feel bad for it.\n4. It's OK not to *want* to know something. If you think someone's question is fundamentally flawed, you should still ask permission before explaining what they should actually be asking.\n5. Note that \"I was just joking\" is not a valid defence.\n6. Don't suggest violence as a response to things, e.g. \"People who do/think X should be Y-ed\".\n   Even if you think it is obvious hyperbole and that it's very clear that no actual threat is meant,\n   it still contributes to a culture that makes people feel unsafe.\n\n\n~~~~~~~~~~~~~~~~~~~~~~~~\nResolution of Violations\n~~~~~~~~~~~~~~~~~~~~~~~~\n\nDavid R. MacIver (the project lead) acts as the main point of contact and enforcer for code of conduct violations.\nYou can email him at david@drmaciver.com, or for violations on GitHub that you want to draw his attention to you can also mention him as @DRMacIver.\n\nOther people (especially Hypothesis team members) should feel free to call people on code of conduct violations when they see them,\nand it is appreciated but not required (especially if doing so would make you feel uncomfortable or unsafe).\n\nWe don't currently have a formal policy for resolutions and it's mostly based on subjective judgement calls,\nbut the high level intent is as follows:\n\n* minor one-off infractions will just be met with a request not to repeat the behaviour and, where it would be useful,\n  for an apology.\n* Major infractions and repeat offenders will be banned from the community.\n\nIf you disagree with David's judgement on any particular event, please feel free to tell him so.\n\nAlso, people who have a track record of bad behaviour outside of the Hypothesis community may be banned even\nif they obey all these rules if their presence is making people uncomfortable.\n"
  },
  {
    "path": ".github/actions/install-base/action.yml",
    "content": "name: \"Install\"\ndescription: \"Install python, then cache\"\ninputs:\n  python-version:\n    description: \"Python version\"\n    required: true\n  python-architecture:\n    description: \"Python architecture, if not default for platform\"\n  task:\n    description: \"Task name\"\n    required: true\nruns:\n  using: \"composite\"\n  steps:\n  - name: Set up Python ${{ inputs.python-version }} ${{ inputs.python-architecture }}\n    uses: actions/setup-python@v4\n    with:\n      python-version: ${{ inputs.python-version }}\n      architecture: ${{ inputs.python-architecture }}\n  - name: Install dotnet6 for Pyjion\n    if: ${{ endsWith(inputs.task, '-pyjion') }}\n    shell: bash\n    run: |\n      wget https://packages.microsoft.com/config/ubuntu/21.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb\n      sudo dpkg -i packages-microsoft-prod.deb\n      rm packages-microsoft-prod.deb\n      sudo apt-get update\n      sudo apt-get install -y apt-transport-https && \\\n        sudo apt-get update && \\\n        sudo apt-get install -y dotnet-sdk-6.0\n  - name: Restore cache\n    uses: actions/cache@v3\n    with:\n      path: |\n        .tox/\n        vendor/bundle\n        ~/.cache\n        ~/.local\n        ~/appdata/local/pip/cache\n        ~/Library/Caches/pip\n        ~/wheelhouse\n      key: deps-${{ runner.os }}-${{ hashFiles('requirements/*.txt') }}-${{ inputs.python-version }}-${{ inputs.python-architecture }}-${{ inputs.task }}\n      restore-keys: |\n        deps-${{ runner.os }}-${{ hashFiles('requirements/*.txt') }}-${{ inputs.python-version }}-${{ inputs.python-architecture }}\n        deps-${{ runner.os }}-${{ hashFiles('requirements/*.txt') }}\n        deps-${{ runner.os }}\n"
  },
  {
    "path": ".github/workflows/fuzz.yml",
    "content": "name: Fuzzing\n\nenv:\n  # Tell pytest and other tools to produce coloured terminal output.\n  # Make sure this is also in the \"passenv\" section of the tox config.\n  PY_COLORS: 1\n\non:\n  # Run every six hours, for six hours each time\n  schedule:\n    - cron:  '0 */6 * * *'\n  # Allow manual launching too so we can test any branch we like\n  workflow_dispatch:\n  # # Enable this and reduce the timeout below to check a PR is working\n  # pull_request:\n  #   branches: [ master ]\n\njobs:\n  fuzz:\n    if: github.repository == 'HypothesisWorks/hypothesis' || github.event_name == 'workflow_dispatch'\n    # Keep all of this stuff synced with the setup in main.yml for CI\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        fetch-depth: 0\n    - name: Set up Python 3.14\n      uses: actions/setup-python@v4\n      with:\n        python-version: \"3.14.2\"\n    - name: Restore cache\n      uses: actions/cache@v3\n      with:\n        path: |\n          ~/.cache\n          ~/wheelhouse\n          ~/.local\n          vendor/bundle\n          .tox/\n        key: deps-${{ runner.os }}-${{ hashFiles('requirements/*.txt') }}-${{ matrix.task }}\n        restore-keys: |\n          deps-${{ runner.os }}-${{ hashFiles('requirements/*.txt') }}\n          deps-${{ runner.os }}\n\n    # OK, on to the fuzzing-specific part.\n    # We're going to stick everything into a single run for now instead of\n    # sharding it, because we'd have to manually specify all the databases\n    # we want to multiplex across and that would be annoying to manage.\n    # TODO: revisit this later; a redis-like service would be so much nicer.\n    - name: Download example database\n      uses: dawidd6/action-download-artifact@v9\n      with:\n        name: hypothesis-example-db\n        path: .hypothesis/examples\n        if_no_artifact_found: warn\n        workflow_conclusion: completed\n\n    - name: Install dependencies\n      run: |\n        pip install --upgrade setuptools pip wheel\n        pip install -r requirements/fuzzing.txt\n        pip install hypothesis-python/[all]\n\n    - name: Run hypofuzz session\n      continue-on-error: true\n      # The timeout ensures that we finish all steps within the six-hour\n      # maximum runtime for Github Actions.\n      # Then run the fuzzer on everything, as for our Windows CI; avoiding\n      # the --no-dashboard option because that also disables .patch writing.\n      run: |\n        timeout --preserve-status 5.5h \\\n          hypothesis fuzz -- hypothesis-python/tests/ \\\n            --ignore=hypothesis-python/tests/quality/ \\\n            --ignore=hypothesis-python/tests/ghostwriter/\n\n    - name: Upload patch files with covering and failing `@example()`s\n      uses: actions/upload-artifact@v4\n      if: always()\n      with:\n        name: explicit-example-patches\n        path: .hypothesis/patches/latest_hypofuzz_*.patch\n\n    # Upload the database so it'll be persisted between runs.\n    # Note that we can also pull it down to use locally via\n    # https://hypothesis.readthedocs.io/en/latest/database.html#hypothesis.database.GitHubArtifactDatabase\n    - name: Upload example database\n      uses: actions/upload-artifact@v4\n      if: always()\n      with:\n        name: hypothesis-example-db\n        path: .hypothesis/examples\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: Hypothesis CI\n\nenv:\n  # Tell pytest and other tools to produce coloured terminal output.\n  # Make sure this is also in the \"passenv\" section of the tox config.\n  PY_COLORS: 1\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n  workflow_dispatch:\n\n# Cancel in-progress PR builds if another commit is pushed.\n# On non-PR builds, fall back to the globally-unique run_id and don't cancel.\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\njobs:\n  basic:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        task:\n          - tox-cover\n          - tox-nocover\n          - tox-rest\n          - check-whole-repo-tests\n          - check-types-hypothesis\n          - lint\n          - check-format\n      fail-fast: false\n    env:\n      PYTHON_VERSION: \"3.14\"\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        fetch-depth: 0\n    - name: \"Install base for Python ${{ env.PYTHON_VERSION }}\"\n      uses: ./.github/actions/install-base\n      with:\n        python-version: ${{ env.PYTHON_VERSION }}\n        task: ${{ matrix.task }}\n    - name: Install tox\n      if: ${{ startsWith(matrix.task, 'tox-') }}\n      run: |\n        pip install --upgrade setuptools pip wheel\n        pip install tox\n    - name: Run tests\n      run: |\n        export TASK=${{ matrix.task }}\n        if [[ $TASK == tox-* ]]; then\n           TOX_TASK=\"${TASK#tox-}\"\n           cd hypothesis-python\n           tox -e $TOX_TASK\n        else\n          ./build.sh\n        fi\n\n  req:\n    needs: [basic]\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        task:\n          - check-documentation\n          - check-types-api\n          - check-coverage\n          - check-conjecture-coverage\n          - check-py310-cover\n          - check-py310-nocover\n          - check-py310-niche\n          - check-pypy310-cover\n          # - check-py310-pyjion  # see notes in tox.ini\n          - check-py311-cover\n          - check-py311-nocover\n          - check-py311-niche\n          - check-pypy311-cover\n          - check-py312-cover\n          - check-py312-nocover\n          - check-py312-niche\n          - check-py313-cover\n          - check-py313-nocover\n          - check-py313-niche\n          - check-py313t-cover\n          - check-py313t-nocover\n          - check-py313t-niche\n          - check-quality\n          - check-pytest9\n          - check-pytest84\n          - check-pytest74\n          - check-py311-pytest62\n          - check-django60\n          - check-django42\n          - check-py313-pandas22\n          - check-py312-pandas21\n          - check-py311-pandas20\n          - check-py311-pandas15\n          - check-py310-pandas14\n          - check-py310-pandas13\n          ## FIXME: actions update means Python builds without eg _bz2, which was required\n          # - check-py310-pandas12\n          # - check-py310-pandas11\n      fail-fast: false\n    env:\n      PYTHON_VERSION: \"3.14\"\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        fetch-depth: 0\n    - name: \"Install base for Python ${{ env.PYTHON_VERSION }}\"\n      uses: ./.github/actions/install-base\n      with:\n        python-version: ${{ env.PYTHON_VERSION }}\n        task: ${{ matrix.task }}\n    - name: Run tests\n      run: |\n        export TASK=${{ matrix.task }}\n        if [[ $TASK == check-crosshair-custom-* ]]; then\n          GROUP=\"${TASK#check-crosshair-custom-}\"\n          ./build.sh check-crosshair-custom -- -n auto $(cd hypothesis-python && echo tests/$GROUP | xargs -n1 echo | grep -Ev \"_py312|_py314\" | xargs)\n        else\n          ./build.sh\n        fi\n    - name: Upload coverage data\n      uses: actions/upload-artifact@v4\n      # Invoke the magic `always` function to run on both success and failure.\n      if: ${{ always() && endsWith(matrix.task, '-coverage') }}\n      with:\n        name: ${{ matrix.task }}-data\n        include-hidden-files: true\n        path: |\n          hypothesis-python/.coverage*\n          !hypothesis-python/.coveragerc\n          hypothesis-python/branch-check*\n\n  nonreq:\n    needs: [basic]\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        task:\n          - check-py314-cover\n          - check-py314-nocover\n          # Blocked by a 3.14rc1 bug. see\n          # https://github.com/HypothesisWorks/hypothesis/pull/4490#issuecomment-3144989862.\n          # Can revisit in 3.14rc2.\n          # - check-py314-niche\n          - check-py314t-cover\n          - check-py314t-nocover\n          - check-py314t-niche\n          # - check-py315-cover\n          # - check-py315-nocover\n          # - check-py315-niche\n          # - check-py315t-cover\n          # - check-py315t-nocover\n          # - check-py315t-niche\n          - check-django52\n          ## `-cover` is too slow under crosshair; use a custom split\n          - check-crosshair-custom-cover/test_[a-d]*\n          - check-crosshair-custom-cover/test_[e-i]*\n          - check-crosshair-custom-cover/test_[j-r]*\n          - check-crosshair-custom-cover/test_[s-z]*\n          - check-crosshair-custom-pytest/test_*\n          - check-crosshair-custom-nocover/test_[a-d]*\n          - check-crosshair-custom-nocover/test_[e-i]*\n          - check-crosshair-custom-nocover/test_[j-r]*\n          - check-crosshair-custom-nocover/test_[s-z]*\n          # - check-crosshair-niche\n          - check-threading\n          - check-py310-oldestnumpy\n          - check-numpy-nightly\n      fail-fast: false\n    env:\n      PYTHON_VERSION: \"3.14\"\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        fetch-depth: 0\n    - name: \"Install base for Python ${{ env.PYTHON_VERSION }}\"\n      uses: ./.github/actions/install-base\n      with:\n        python-version: ${{ env.PYTHON_VERSION }}\n        task: ${{ matrix.task }}\n    - name: Run tests\n      run: |\n        export TASK=${{ matrix.task }}\n        if [[ $TASK == check-crosshair-custom-* ]]; then\n          GROUP=\"${TASK#check-crosshair-custom-}\"\n          ./build.sh check-crosshair-custom -- -n auto $(cd hypothesis-python && echo tests/$GROUP | xargs -n1 echo | grep -Ev \"_py312|_py314\" | xargs)\n        else\n          ./build.sh\n        fi\n\n  cross:\n    needs: [basic]\n    strategy:\n      matrix:\n        os:\n          - windows-latest\n          - macos-latest\n        python-version:\n          - \"3.11\"\n          - \"3.14\"\n        python-architecture:\n          - null\n          - \"x86\"\n        task:\n          - cover\n          - nocover\n          - rest\n          - alt-nocover\n          - alt-rest\n        exclude:\n          - { os: macos-latest, python-architecture: \"x86\" }\n          - { python-version: \"3.14\", python-architecture: \"x86\" }\n          - { python-version: \"3.11\", task: nocover }\n          - { python-version: \"3.11\", task: rest }\n          - { python-version: \"3.14\", task: alt-nocover }\n          - { python-version: \"3.14\", task: alt-rest }\n      fail-fast: false\n    runs-on: ${{ matrix.os }}\n    env:\n      # Override default from tox.ini\n      PYTHONWARNDEFAULTENCODING: \"\"\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        fetch-depth: 0\n    - name: \"Install base for Python ${{ matrix.python-version }} ${{ matrix.python-architecture }}\"\n      uses: ./.github/actions/install-base\n      with:\n        python-version: ${{ matrix.python-version }}\n        python-architecture: ${{ matrix.python-architecture }}\n        task: ${{ matrix.task }}\n    - name: Install tox\n      run: |\n        pip install --upgrade setuptools pip wheel\n        pip install tox\n    - name: Run tests\n      working-directory: ./hypothesis-python\n      run: |\n        tox -e ${{ matrix.task }}\n\n  # See https://pyodide.org/en/stable/usage/building-and-testing-packages.html\n  # and https://github.com/numpy/numpy/blob/9a650391651c8486d8cb8b27b0e75aed5d36033e/.github/workflows/emscripten.yml\n  test-pyodide:\n    needs: [basic]\n    runs-on: ubuntu-latest\n    env:\n      NODE_VERSION: 22\n      # Note that the versions below are updated by `update_pyodide_versions()` in our weekly cronjob.\n      # The versions of pyodide-build and the Pyodide runtime may differ.\n      PYODIDE_VERSION: 0.29.3\n      PYODIDE_BUILD_VERSION: 0.33.0\n      # pyodide 0.29.0 (latest at time of writing) doesn't yet support 3.14\n      PYTHON_VERSION: 3.13.2\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        fetch-depth: 0\n    - name: \"Install base for Python ${{ env.PYTHON_VERSION }}\"\n      uses: ./.github/actions/install-base\n      with:\n        python-version: ${{ env.PYTHON_VERSION }}\n        task: pyodide\n    - name: Set up Node\n      uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1\n      with:\n        node-version: ${{ env.NODE_VERSION }}\n    - name: Install pyodide-build and Pyodide cross-build environment\n      run: |\n        pip install pyodide-build==${{ env.PYODIDE_BUILD_VERSION }}\n        pyodide xbuildenv install ${{ env.PYODIDE_VERSION }}\n    - name: Set up Pyodide venv and install dependencies\n      run: |\n        pip install --upgrade setuptools pip wheel build\n        python -m build --wheel hypothesis-python --outdir dist/\n        pip download --dest=dist/ hypothesis-python/ pytest tzdata  # fetch all the wheels\n         rm dist/packaging-*.whl  # fails with `invalid metadata entry 'name'`\n         pyodide venv .venv-pyodide\n        source .venv-pyodide/bin/activate\n        pip install dist/*.whl\n    - name: Run tests\n      run: |\n        source .venv-pyodide/bin/activate\n        # pyodide can't run multiple processes internally, so parallelize explicitly over\n        # discovered test files instead (20 at a time)\n        TEST_FILES=$(ls hypothesis-python/tests/cover/test*.py | grep -v \"_py314\")\n        echo \"test files: $TEST_FILES\"\n        parallel --max-procs 100% --max-args 20 --keep-order --line-buffer \\\n          python -m pytest -p no:cacheprovider <<< $TEST_FILES\n\n  check-required:\n    if: always()\n    needs: [basic, req, cross]\n    runs-on: ubuntu-latest\n    steps:\n    - name: Check required jobs\n      uses: re-actors/alls-green@release/v1\n      with:\n        jobs: ${{ toJSON(needs) }}\n\n  deploy:\n    if: \"github.event_name == 'push' && github.repository == 'HypothesisWorks/hypothesis'\"\n    runs-on: ubuntu-latest\n    needs: [check-required]\n    strategy:\n      matrix:\n        task:\n          - deploy\n      fail-fast: false\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        fetch-depth: 0\n        token: ${{ secrets.GH_TOKEN }}\n    - uses: ./.github/actions/install-base\n      with:\n        python-version: \"3.14\"\n    - name: Deploy package\n      env:\n        GH_TOKEN: ${{ secrets.GH_TOKEN }}\n        TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}\n      run: |\n        TASK=${{ matrix.task }} ./build.sh\n"
  },
  {
    "path": ".github/workflows/update-deps.yml",
    "content": "name: Update pinned dependencies\n\non:\n  schedule:\n    - cron: 0 0 * * 0\n  workflow_dispatch:\n\njobs:\n  release:\n    name: Update pinned dependencies\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - name: Set up Python 3.14\n        uses: actions/setup-python@v4\n        with:\n          python-version: '3.14'\n      - name: Update pinned dependencies\n        run: ./build.sh upgrade-requirements\n      - name: Open pull request\n        uses: peter-evans/create-pull-request@v7\n        with:\n          token: ${{secrets.GH_TOKEN}}\n          delete-branch: true\n          title: Update pinned dependencies\n          body: |\n            Automatically update pinned dependencies\n          commit-message: 'Update pinned dependencies'\n          committer: 'CI on behalf of the Hypothesis team <zac@zhd.dev>'\n          author: 'CI on behalf of the Hypothesis team <zac@zhd.dev>'\n"
  },
  {
    "path": ".github/workflows/website.yml",
    "content": "name: Build website & deploy to GitHub Pages\n\non:\n  # Runs on pushes targeting the default branch\n  push:\n    branches: [\"master\"]\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\n# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages\npermissions:\n  contents: read\n  pages: write\n  id-token: write\n\n# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.\n# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.\nconcurrency:\n  group: \"pages\"\n  cancel-in-progress: false\n\njobs:\n  # Single deploy job since we're just deploying\n  deploy:\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Build website\n        run: ./build.sh website\n      - name: Upload artifact\n        uses: actions/upload-pages-artifact@v3\n        with:\n          path: 'website/output/'\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v4\n"
  },
  {
    "path": ".gitignore",
    "content": "# mypyc\n\n*.so\n\n# misc (editors, file systems, etc)\n\n*.swo\n*.swp\n.idea\n.vagrant\n.DS_Store\n.hypothesis\n.vscode/\n.claude/settings.local.json\n\n# generic build components\n\n.runtimes\n/hypothesis-python/branch-check*\n/pythonpython3.*\n/pythonpypy3.*\n.pyodide-xbuildenv\n\n# python\n\n*.pyc\n*.pyo\nvenv*\n.cache\n.pytest_cache\n.mypy_cache\ndocs/_build\n*.egg-info\n_build\n.tox\n.coverage\n.coverage.*\n.pypirc\nhtmlcov\nbuild\ndist\n.doctrees/\n.v*/\n\n# encrypted files\nsecrets.tar\nsecrets\n\n\n_site/\n.sass-cache/\n.docker\n\n# =========================\n# Operating System Files\n# =========================\n\n# OSX\n# =========================\n\n.AppleDouble\n.LSOverride\n\n# Thumbnails\n._*\n\n# Files that might appear on external disk\n.Spotlight-V100\n.Trashes\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n# Windows\n# =========================\n\n# Windows image file caches\nThumbs.db\nehthumbs.db\n\n# Folder config file\nDesktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\nsftp-config.json\n\n# Vim files\n\n*.sw*\n\n__pycache__\n\n.jekyll-metadata\n\nHypothesisWorks.github.io.iml\njekyll.log\n/website/output/\n/t.py\n"
  },
  {
    "path": ".readthedocs.yml",
    "content": "# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details\n\n# Required\nversion: 2\n\n# Optionally build your docs in additional formats such as PDF and ePub\nformats:\n  - htmlzip\n  - epub\n  # - pdf  # busted by latex crash on unicode U+030A combining ring above, in text() docs\n\n# Optionally set the version of Python and requirements required to build your docs\nbuild:\n   os: ubuntu-22.04\n   tools:\n      python: \"3.14\"\npython:\n   install:\n      - requirements: requirements/tools.txt\n      - path: hypothesis-python/\n        extra_requirements:\n           - all\nsphinx:\n   configuration: hypothesis-python/docs/conf.py\n"
  },
  {
    "path": "AUTHORS.rst",
    "content": "--------------------\nList of Contributors\n--------------------\n\nThe primary author for most of Hypothesis is David R. MacIver (me). However the following\npeople have also contributed work. As well as my thanks, they also have copyright over\ntheir individual contributions.\n\n.. NOTE - this list is in alphabetical order by first name (or handle).\n\n* `A. Jesse Jiryu Davis <https://github.com/ajdavis>`_\n* `Aaron Meurer <https://github.com/asmeurer>`_\n* `Adam Johnson <https://github.com/adamchainz>`_\n* `Adam Matan <https://github.com/adamatan/adamatan>_`\n* `Adam Sven Johnson <https://www.github.com/pkqk>`_\n* `Afrida Tabassum <https://github.com/oxfordhalfblood>`_ (afrida@gmail.com)\n* `Afonso Silva <https://github.com/ajcerejeira>`_ (ajcerejeira@gmail.com)\n* `Agriya Khetarpal <https://github.com/agriyakhetarpal>`_\n* `Agustín Covarrubias <https://github.com/agucova>`_ (gh@agucova.dev)\n* `Akash Suresh <https://www.github.com/akash-suresh>`_ (akashsuresh36@gmail.com)\n* `Alex Gaynor <https://github.com/alex>`_\n* `Alex Stapleton <https://www.github.com/public>`_\n* `Alex Willmer <https://github.com/moreati>`_ (alex@moreati.org.uk)\n* `Andrea Pierré <https://www.github.com/kir0ul>`_\n* `Andrea Reina <https://www.github.com/andreareina>`_\n* `Andrew Sansom <https://www.github.com/qthequartermasterman>`_\n* `Anne Archibald <https://www.github.com/td-anne>`_\n* `Arjoonn Sharma <https://github.com/thesage21>`_\n* `Ben Anhalt <https://github.com/benanhalt>`_\n* `Ben Peterson <https://github.com/killthrush>`_ (killthrush@hotmail.com)\n* `Benjamin Lee <https://github.com/Benjamin-Lee>`_ (benjamindlee@me.com)\n* `Benjamin Palmer <https://github.com/benjpalmer>`_\n* `Bex Dunn <https://github.com/BexDunn>`_ (bex.dunn@gmail.com)\n* `Bill Tucker <https://github.com/imbilltucker>`_ (imbilltucker@gmail.com)\n* `Brandon Chinn <https://github.com/brandonchinn178>`_\n* `Bryant Eisenbach <https://github.com/fubuloubu>`_\n* `Buck Evan, copyright Google LLC <https://github.com/bukzor>`_\n* `Cameron McGill <https://www.github.com/Cameron-JM>`_\n* `Carl Meyer <https://www.github.com/carljm>`_\n* `Charles O'Farrell <https://www.github.com/charleso>`_\n* `Charlie Tanksley <https://www.github.com/charlietanksley>`_\n* `Chase Garner <https://www.github.com/chasegarner>`_ (chase@garner.red)\n* `Cheuk Ting Ho <https://github.com/Cheukting>`_\n* `Chris Down  <https://chrisdown.name>`_\n* `Chris van Dronkelaar <https://github.com/Chrisvandr>`_\n* `Chris Wesseling <https://github.com/CharString>`_\n* `Christopher Martin <https://www.github.com/chris-martin>`_ (ch.martin@gmail.com)\n* `Claudio Jolowicz <https://github.com/cjolowicz>`_\n* `Conrad Ho <https://www.github.com/conradho>`_ (conrad.alwin.ho@gmail.com)\n* `Cory Benfield <https://www.github.com/Lukasa>`_\n* `Cristi Cobzarenco <https://github.com/cristicbz>`_ (cristi@reinfer.io)\n* `Damon Francisco <https://github.com/dtfrancisco>`_ (damontfrancisco@yahoo.com)\n* `Daniel J. West <https://github.com/danieljwest>`_\n* `Daniel Knell <https://github.com/danielknell>`_ (contact@danielknell.co.uk)\n* `David Bonner <https://github.com/rascalking>`_ (dbonner@gmail.com)\n* `David Chudzicki <https://github.com/dchudz>`_ (dchudz@gmail.com)\n* `David Mascharka <https://github.com/davidmascharka>`_\n* `Dawn E. Collett <https://github.com/lisushka>`_\n* `Derek Gustafson <https://www.github.com/degustaf>`_\n* `Dion Misic <https://www.github.com/kingdion>`_ (dion.misic@gmail.com)\n* `Dmitry Dygalo <https://www.github.com/Stranger6667>`_\n* `Ed Rogers <https://www.github.com/edrogers>`-\n* `Eduardo Enriquez <https://www.github.com/eduzen>`_ (eduardo.a.enriquez@gmail.com)\n* `El Awbery <https://www.github.com/ElAwbery>`_\n* `Emmanuel Leblond <https://www.github.com/touilleMan>`_\n* `Evan Tey <https://github.com/evantey14>`_\n* `Felix Divo <https://www.github.com/felixdivo>`_\n* `Felix Grünewald <https://www.github.com/fgruen>`_\n* `Felix Sheldon <https://www.github.com/darkpaw>`_\n* `Florian Bruhin <https://www.github.com/The-Compiler>`_\n* `follower <https://www.github.com/follower>`_\n* `Francesc Elies <https://www.github.com/FrancescElies>`_\n* `Gabe Joseph <https://github.com/gjoseph92>`_\n* `Gary Donovan <https://www.github.com/garyd203>`_\n* `Genevieve Mendoza <https://www.github.com/genevieve-me>`_\n* `George Macon <https://www.github.com/gmacon>`_\n* `Glenn Lehman <https://www.github.com/glnnlhmn>`_\n* `Graham Williamson <https://github.com/00willo>`_\n* `Grant David Bachman <https://github.com/grantbachman>`_ (grantbachman@gmail.com)\n* `Gregory Petrosyan <https://github.com/flyingmutant>`_\n* `Grzegorz Zieba <https://github.com/gzaxel>`_ (g.zieba@erax.pl)\n* `Grigorios Giannakopoulos <https://github.com/grigoriosgiann>`_\n* `Hal Blackburn <https://github.com/h4l>`_\n* `Hugo van Kemenade <https://github.com/hugovk>`_\n* `Humberto Rocha <https://github.com/humrochagf>`_\n* `Ilya Lebedev <https://github.com/melevir>`_ (melevir@gmail.com)\n* `Israel Fruchter <https://github.com/fruch>`_\n* `Ivan Tham <https://github.com/pickfire>`_\n* `Iyassou Shimels <https://github.com/iyassou>`_\n* `Jack Massey <https://github.com/massey101>`_\n* `Jakub Nabaglo <https://github.com/nbgl>`_ (j@nab.gl)\n* `James Lamb <https://github.com/jameslamb>`_\n* `Jenny Rouleau <https://github.com/jennyrou>`_\n* `Jens Heinrich <https://github.com/JensHeinrich>`_\n* `Jens Tröger <https://github.com/jenstroeger>`_\n* `Jeremy Thurgood <https://github.com/jerith>`_\n* `J.J. Green <http://soliton.vm.bytemark.co.uk/pub/jjg/>`_\n* `JP Viljoen <https://github.com/froztbyte>`_ (froztbyte@froztbyte.net)\n* `Jochen Müller <https://github.com/jomuel>`_\n* `Joseph Weston <https://github.com/jbweston>`_\n* `Joey Tuong <https://github.com/tetrapus>`_\n* `Jonathan Gayvallet <https://github.com/Meallia>`_ (jonathan.gayvallet@orange.com)\n* `Jonty Wareing <https://www.github.com/Jonty>`_ (jonty@jonty.co.uk)\n* `Joshua Boone <https://www.github.com/patchedwork>`_ (joshuaboone4190@gmail.com)\n* `Joshua Munn <https://www.github.com/jams2>`_ (public@elysee-munn.family)\n* `jmhsi <https://www.github.com/jmhsi>`_\n* `Justus Magin <https://github.com/keewis>`_\n* `jwg4 <https://www.github.com/jwg4>`_\n* `Kai Chen <https://www.github.com/kx-chen>`_ (kaichen120@gmail.com)\n* `Karthikeyan Singaravelan <https://www.github.com/tirkarthi>`_ (tir.karthi@gmail.com)\n* `Katelyn Gigante <https://github.com/silasary>`_\n* `Katrina Durance <https://github.com/kdurance>`_\n* `kbara <https://www.github.com/kbara>`_\n* `Keeri Tramm <keerilynn>`_\n* `Kristian Glass <https://www.github.com/doismellburning>`_\n* `Krzysztof Przybyła <https://github.com/kprzybyla>`_\n* `Kyle Reeve <https://www.github.com/kreeve>`_ (krzw92@gmail.com)\n* `Lampros Mountrakis <https://www.github.com/lmount>`_\n* `Lea Provenzano <https://github.com/leaprovenzano>`_\n* `Lee Begg <https://www.github.com/llnz2>`_\n* `Liam DeVoe <https://github.com/tybug>`_\n* `Libor Martínek <https://github.com/bibajz>`_\n* `Lisa Goeller <https://www.github.com/lgoeller>`_\n* `Louis Taylor <https://github.com/kragniz>`_\n* `Luke Barone-Adesi <https://github.com/baluke>`_\n* `Lundy Bernard <https://github.com/lundybernard>`_\n* `Marco Ricci <https://github.com/the-13th-letter>`_\n* `Marco Sirabella <https://www.github.com/mjsir911>`_\n* `marekventur <https://www.github.com/marekventur>`_\n* `Marius Gedminas <https://www.github.com/mgedmin>`_ (marius@gedmin.as)\n* `Markus Unterwaditzer <https://github.com/untitaker>`_ (markus@unterwaditzer.net)\n* `Mateusz Sokół <https://github.com/mtsokol>`_\n* `Mathieu Paturel <https://github.com/math2001>`_ (mathieu.paturel@gmail.com)\n* `Matt Bachmann <https://www.github.com/bachmann1234>`_ (bachmann.matt@gmail.com)\n* `Matthew Barber <https://www.github.com/honno>`_ (quitesimplymatt@gmail.com)\n* `Max Nordlund <https://www.github.com/maxnordlund>`_ (max.nordlund@gmail.com)\n* `Maxim Kulkin <https://www.github.com/maximkulkin>`_ (maxim.kulkin@gmail.com)\n* `Mel Seto <https://github.com/mel-seto>`_\n* `Michel Alexandre Salim <https://github.com/michel-slm>`_ (michel@michel-slm.name)\n* `mulkieran <https://www.github.com/mulkieran>`_\n* `Munir Abdinur <https://www.github.com/mabdinur>`_\n* `Nathan Goldbaum <https://www/github.com/ngoldbaum>`_\n* `Nicholas Chammas <https://www.github.com/nchammas>`_\n* `Nick Anyos <https://www.github.com/NickAnyos>`_\n* `Nick Collins <https://github.com/nickcollins>` _\n* `Nick Muoh <https://github.com/OdinTech3>`_ (nickspirit3@gmail.com)\n* `Nicolas Erni <https://www.github.com/ThunderKey>`_\n* `Nikita Sobolev <https://github.com/sobolevn>`_ (mail@sobolevn.me)\n* `Oleg Höfling <https://github.com/hoefling>`_ (oleg.hoefling@gmail.com)\n* `Paul Ganssle <https://ganssle.io>`_ (paul@ganssle.io)\n* `Paul Kehrer <https://github.com/reaperhulk>`_\n* `Paul Lorett Amazona <https://github.com/whatevergeek>`_\n* `Paul Stiverson <https://github.com/thismatters>`_\n* `Pax (R. Margret) W. <https://github.com/paxcodes>`_\n* `Peadar Coyle <https://github.com/springcoil>`_ (peadarcoyle@gmail.com)\n* `Petr Viktorin <https://github.com/encukou>`_\n* `Phillip Schanely <https://github.com/pschanely>`_ (pschanely@gmail.com)\n* `Pierre-Jean Campigotto <https://github.com/PJCampi>`_\n* `Przemek Konopko <https://github.com/soutys>`_\n* `Reagan Lee <https://github.com/reaganjlee>`_\n* `Richard Boulton <https://www.github.com/rboulton>`_ (richard@tartarus.org)\n* `Richard Scholtens <https://github.com/richardscholtens>`_ (richardscholtens2@gmail.com)\n* `Robert Howlett <https://github.com/jebob>`_\n* `Robert Knight <https://github.com/robertknight>`_ (robertknight@gmail.com)\n* `Rodrigo Girão Serrão <https://github.com/rodrigogiraoserrao>`_ (rodrigo@mathspp.com)\n* `Rónán Carrigan <https://www.github.com/rcarriga>`_ (rcarriga@tcd.ie)\n* `Ruben Opdebeeck <https://github.com/ROpdebee>`_\n* `Ryan Soklaski <https://www.github.com/rsokl>`_ (rsoklaski@gmail.com)\n* `Ryan Turner <https://github.com/rdturnermtl>`_ (ryan.turner@uber.com)\n* `Sam Bishop (TechDragon) <https://github.com/techdragon>`_ (sam@techdragon.io)\n* `Sam Clamons <https://github.com/sclamons>`_ (sclamons@gmail.com)\n* `Sam Hames <https://www.github.com/SamHames>`_\n* `Sam Watts <https://www.github.com/sam-watts>`_\n* `Sangarshanan <https://www.github.com/sangarshanan>`_ (sangarshanan1998@gmail.com)\n* `Sanyam Khurana <https://github.com/CuriousLearner>`_\n* `Saul Shanabrook <https://www.github.com/saulshanabrook>`_ (s.shanabrook@gmail.com)\n* `Sebastiaan Zeeff <https://github.com/SebastiaanZ>`_ (sebastiaan.zeeff@ordina.nl)\n* `Sharyar Memon <https://github.com/sharyar>`_ (smemon.cal@gmail.com)\n* `Shaun Read <https://github.com/philastrophist>`_\n* `Shlok Gandhi <https://github.com/shlok57>`_ (shlok.gandhi@gmail.com)\n* `Sogata Ray <https://github.com/rayardinanda>`_ (rayardinanda@gmail.com)\n* `Stuart Cook <https://www.github.com/Zalathar>`_\n* `SuperStormer <https://github.com/SuperStormer>`_\n* `Sushobhit <https://github.com/sushobhit27>`_ (sushobhitsolanki@gmail.com)\n* `Tariq Khokhar <https://www.github.com/tkb>`_ (tariq@khokhar.net)\n* `Tessa Bradbury <https://www.github.com/tessereth>`_\n* `Thea Koutsoukis <https://www.github.com/theakaterina>`_\n* `Thomas Ball <https://www.github.com/bomtall>`_ (bomtall1@hotmail.com)\n* `Thomas Grainge <https://www.github.com/tgrainge>`_\n* `Thomas Kluyver <https://www.github.com/takluyver>`_ (thomas@kluyver.me.uk)\n* `Tim Martin <https://www.github.com/timmartin>`_ (tim@asymptotic.co.uk)\n* `Tom McDermott <https://www.github.com/sponster-au>`_ (sponster@gmail.com)\n* `Tom Milligan <https://www.github.com/tommilligan>`_ (code@tommilligan.net)\n* `Tyler Gibbons <https://www.github.com/kavec>`_ (tyler.gibbons@flexport.com)\n* `Tyler Nickerson <https://www.github.com/nmbrgts>`_\n* `Vidya Rani <https://www.github.com/vidyarani-dg>`_ (vidyarani.d.g@gmail.com)\n* `Vince Reuter <https://github.com/vreuter>`_ (vince.reuter@gmail.com)\n* `Vincent Michel <https://www.github.com/vxgmichel>`_ (vxgmichel@gmail.com)\n* `Viorel Pluta <https://github.com/viopl>`_ (viopluta@gmail.com)\n* `Vytautas Strimaitis <https://www.github.com/vstrimaitis>`_\n* `Will Hall <https://www.github.com/wrhall>`_ (wrsh07@gmail.com)\n* `Will Thompson <https://www.github.com/wjt>`_ (will@willthompson.co.uk)\n* `Wilfred Hughes <https://www.github.com/wilfred>`_\n* `Yiyang Zhan <https://www.github.com/zhanpon>`_\n* `Zac Hatfield-Dodds <https://www.github.com/Zac-HD>`_ (zac.hatfield.dodds@gmail.com)\n* `Zebulun Arendsee <https://www.github.com/arendsee>`_ (zbwrnz@gmail.com)\n"
  },
  {
    "path": "CITATION.cff",
    "content": "cff-version: 1.2.0\nmessage: |\n  If you use Hypothesis as part of a published research project,\n  please cite our paper in the Journal of Open Source Software:\n\n  Text:\n\n  MacIver et al., (2019). Hypothesis: A new approach to property-based testing.\n  Journal of Open Source Software, 4(43), 1891, https://doi.org/10.21105/joss.01891\n\n  BibTeX:\n\n  @article{MacIver2019Hypothesis,\n    journal = {Journal of Open Source Software},\n    doi = {10.21105/joss.01891},\n    issn = {2475-9066},\n    number = {43},\n    publisher = {The Open Journal},\n    title = {Hypothesis: A new approach to property-based testing},\n    url = {http://dx.doi.org/10.21105/joss.01891},\n    volume = {4},\n    author = {MacIver, David and Hatfield-Dodds, Zac and Contributors, Many},\n    pages = {1891},\n    date = {2019-11-21},\n    year = {2019},\n    month = {11},\n    day = {21},\n  }\n\n  To reference a particular version of Hypothesis as a software artifact,\n  you can use the version-specific DOIs we create for each release under\n  https://doi.org/10.5281/zenodo.1412597\n\n\npreferred-citation:\n  title: 'Hypothesis: A new approach to property-based testing'\n  date-released: 2019-11-21\n  type: article\n  doi: 10.21105/joss.01891\n  authors:\n    - family-names: MacIver\n      given-names: David R.\n      orcid: https://orcid.org/0000-0002-8635-3223\n      affiliation: Imperial College London\n    - family-names: Hatfield-Dodds\n      given-names: Zac\n      orcid: https://orcid.org/0000-0002-8646-8362\n      affiliation: Australian National University\n    - name: \"many other contributors\"\n\n# Citation metadata for the software itself, as required by the CFF spec\ndoi: 10.5281/zenodo.1412597  # Version-independent DOI for the software archive\ntitle: 'Hypothesis: Property-Based Testing for Python'\nrepository-code: https://github.com/HypothesisWorks/hypothesis\nlicense: MPL-2.0\nauthors:\n  - family-names: MacIver\n    given-names: David R.\n    orcid: https://orcid.org/0000-0002-8635-3223\n    affiliation: Imperial College London\n  - family-names: Hatfield-Dodds\n    given-names: Zac\n    orcid: https://orcid.org/0000-0002-8646-8362\n    affiliation: Australian National University\n  - name: \"many other contributors\"\n"
  },
  {
    "path": "CONTRIBUTING.rst",
    "content": "=============\nContributing\n=============\n\nFirst off: It's great that you want to contribute to Hypothesis! Thanks!\n\n---------------------------------------\nJust tell me how to make a pull request\n---------------------------------------\n\n1. Make your change and ensure it has adequate tests\n2. Create ``hypothesis-python/RELEASE.rst`` with ``RELEASE_TYPE: patch``\n   for small bugfixes, or ``minor`` for new features.  See ``RELEASE-sample.rst``\n   as an example.\n3. Add yourself to the list in ``AUTHORS.rst`` and open a PR!\n\nFor more detail, read on; for even more, continue to the ``guides/`` directory!\n\n------------------\nWays to Contribute\n------------------\n\nHypothesis is a mature yet active project. This means that there are many\nways in which you can contribute.\n\nFor example, it's super useful and highly appreciated if you do any of:\n\n* Submit bug reports\n* Submit feature requests\n* Write about Hypothesis\n* Give a talk about Hypothesis\n* Build libraries and tools on top of Hypothesis outside the main repo\n* Submit PRs\n\nIf you build a Hypothesis strategy that you would like to be more widely known\nplease add it to the list of external strategies by preparing a PR against\nthe docs/strategies.rst file.\n\nIf you find an error in the documentation, please feel free to submit a PR that\nfixes the error. Spot a tyop? Fix it up and send us a PR!\nYou can read more about how we document Hypothesis in ``guides/documentation.rst``\n\nThe process for submitting source code PRs is generally more involved\n(don't worry, we'll help you through it), so do read the rest of this document.\nIf you're planning a larger change, the contributor guides (in the ``guides/``\ndirectory) will make sure you're on the right track.\n\n----------------------------------\nInstalling from source and testing\n----------------------------------\n\nIf you want to install directly from the source code (e.g. because you want to\nmake changes and install the changed version) you can do this with:\n\n.. code:: bash\n\n  pip install -r requirements/test.in\n  pip install -r requirements/tools.in\n  pip install -e hypothesis-python/\n\n  # You don't need to run the tests, but here's the command:\n  pytest hypothesis-python/tests/cover/\n\nYou may wish to do all of this in a\n`virtualenv <https://docs.python.org/3/library/venv.html>`_. For example:\n\n.. code:: bash\n\n  python3 -m venv .venv\n  source .venv/bin/activate\n  pip install hypothesis\n\nWill create an isolated environment where you can install and try out\nHypothesis without affecting your system packages.\n\n-----------------------\nCopyright and Licensing\n-----------------------\n\nIt's important to make sure that you own the rights to the work you are submitting.\nIf it is done on work time, or you have a particularly onerous contract, make sure\nyou've checked with your employer.\n\nAll work in Hypothesis is licensed under the terms of the\n`Mozilla Public License, version 2.0 <https://mozilla.org/MPL/2.0/>`_. By\nsubmitting a contribution you are agreeing to licence your work under those\nterms.\n\nFinally, if it is not there already, add your name (and a link to your GitHub\nand email address if you want) to the list of contributors found in\nAUTHORS.rst, in alphabetical order. It doesn't have to be your\n\"real\" name (whatever that means), any sort of public identifier\nis fine. In particular a GitHub account is sufficient.\n\n-----------------------\nThe actual contribution\n-----------------------\n\nOK, so you want to make a contribution and have sorted out the legalese. What now?\n\nFirst off: If you're planning on implementing a new feature, talk to us\nfirst! Come `join us on the mailing list <https://hypothesis.readthedocs.io/en/latest/community.html#community>`_,\nor open an issue. If it's really small feel free to open a work in progress pull request sketching\nout the idea, but it's best to get feedback from the Hypothesis maintainers\nbefore sinking a bunch of work into it.\nIf you're working on an existing issue, leave a comment so we can try to avoid\nduplicating your work before you open a pull request.\n\nIn general work-in-progress pull requests are totally welcome if you want early feedback\nor help with some of the tricky details. Don't be afraid to ask for help.\n\nIn order to get merged, a pull request will have to have a green build (naturally) and\nto be approved by a Hypothesis maintainer (and, depending on what it is, possibly specifically\nby DRMacIver).  Most pull requests will also need to `write a changelog entry in\nhypothesis-python/RELEASE.rst <guides/documentation.rst#changelog-entries>`_.\n\nThe review process is the same one that all changes to Hypothesis go through, regardless of\nwhether you're an established maintainer or entirely new to the project. It's very much\nintended to be a collaborative one: It's not us telling you what we think is wrong with\nyour code, it's us working with you to produce something better together.\n\nWe have `a lengthy check list <guides/review.rst>`_ of things we look for in a review. Feel\nfree to have a read of it in advance and go through it yourself if you'd like to. It's not\nrequired, but it might speed up the process.\n\nOnce your pull request has a green build and has passed review, it will be merged to\nmaster fairly promptly. This will immediately trigger a release! Don't be scared. If that\nbreaks things, that's our fault not yours - the whole point of this process is to ensure\nthat problems get caught before we merge rather than after.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nPull request or external package?\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nNew strategies can be added to Hypothesis, or published as an external package\non PyPI - either is fine for most strategies.  If in doubt, ask!\n\nIt's generally much easier to get things working outside, because there's\nmore freedom to experiment and fewer requirements in stability and API style.\nWe're happy to review and help with external packages as well as pull requests;\nseveral parts of Hypothesis started life outside and were integrated later\n(with permission, of course).\n\nTo help people find your package, please use the `Framework :: Hypothesis\n<https://pypi.org/search/?c=Framework+%3A%3A+Hypothesis>`__ `trove classifier\n<https://pypi.org/classifiers/>`__.  We also recommend naming your package\nin the pattern of ``hypothesis-graphql`` and ``hypothesis-protobuf`` on PyPI.\n\nOn the other hand, being inside gets you access to some deeper implementation\nfeatures (if you need them) and better long-term guarantees about maintenance.\nWe particularly encourage pull requests for new composable primitives that\nmake implementing other strategies easier, or for widely used types in the\nPython standard library.  Strategies for other things are also welcome;\nanything with external dependencies just goes in ``hypothesis.extra``.\n\n~~~~~~~~~\nThe build\n~~~~~~~~~\n\nThe build is driven by a ``build.sh`` shell script, which delegates to a custom Python-based build system.\nActually running the tests is managed by `tox <https://tox.readthedocs.io/en/latest/>`_, but the build system\nwill call out to the relevant tox environments so you mostly don't have to know anything about that\nunless you want to make changes to the test config. You also mostly don't need to know anything about the build system\nexcept to type ``./build.sh`` followed by the name of the task you want to run.\n\nAll of it will be checked on CI so you don't *have* to run anything locally, but you might\nfind it useful to do so: A full CI run can take up to twenty minutes,\nso running a smaller set of tests locally can be helpful.\n\nThe build system should be \"fairly\" portable, but is currently only known to work on Linux or macOS. It *might* work\non a BSD or on Windows with cygwin installed, but it hasn't been tried.  Windows with WSL does work,\nas for Linux, and since OS-specific issues are rare for Hypothesis that's pretty useful.\nIf you try it and find it doesn't work, please do submit patches to fix that.\n\nSome notable commands:\n\n``./build.sh check-coverage`` will verify 100% code coverage by running a\ncurated subset of the test suite.\n\n``./build.sh check-py311`` (etc.) will run most of the test suite against a\nparticular python version.\n\n``./build.sh format`` will reformat your code according to the Hypothesis coding style. You should use this before each\ncommit ideally, but you only really have to use it when you want your code to be ready to merge.\n\nYou can also use ``./build.sh check-format``, which will run format and some linting and will then error if you have a\ngit diff. Note: This will error even if you started with a git diff, so if you've got any uncommitted changes\nthis will necessarily report an error.\n\nRun ``./build.sh tasks`` for a list of all supported build task names.\n\nNote: The build requires a lot of different versions of python, so rather than have you install them yourself,\nthe build system will install them itself in a local directory. This means that the first time you run a task you\nmay have to wait a while as the build downloads and installs the right version of python for you.\n\n~~~~~~~~~~~~~\nRunning Tests\n~~~~~~~~~~~~~\n\nThe tasks described above will run all of the tests (e.g. ``check-py311``). But\nthe ``tox`` task will give finer-grained control over the test runner. At a\nhigh level, the task takes the form:\n\n.. code-block::\n\n    ./build.sh tox py311-custom 3.11.3 [tox args] -- [pytest args]\n\nNamely, first provide the tox environment (see ``tox.ini``), then the python\nversion to test with, then any ``tox`` or ``pytest`` args as needed. For\nexample, to run all of the tests in the file\n``tests/nocover/test_conjecture_engine.py`` with python 3.12:\n\n.. code-block::\n\n    ./build.sh tox py312-custom 3.12.7 -- tests/nocover/test_conjecture_engine.py\n\nSee the ``tox`` docs and ``pytest`` docs for more information:\n* https://docs.pytest.org/en/latest/how-to/usage.html\n* https://tox.wiki/en/latest/config.html#cli\n\n^^^^^^^^^^^\nTest Layout\n^^^^^^^^^^^\n\nSee ``hypothesis-python/tests/README.rst``\n\n^^^^^^^^^^^^^^^^\nUseful Arguments\n^^^^^^^^^^^^^^^^\n\nSome useful arguments to pytest include:\n\n* You can pass ``-n 0`` to turn off ``pytest-xdist``'s parallel test execution.\n  Sometimes for running just a small number of tests its startup time is longer\n  than the time it saves (this will vary from system to system), so this can\n  be helpful if you find yourself waiting on test runners to start a lot.\n* You can use ``-k`` to select a subset of tests to run. This matches on substrings\n  of the test names. For example ``-kfoo`` will only run tests that have \"foo\" as\n  a substring of their name. You can also use composite expressions here.\n  e.g. ``-k'foo and not bar'`` will run anything containing foo that doesn't\n  also contain bar.  `More information on how to select tests to run can be found\n  in the pytest documentation <https://docs.pytest.org/en/latest/usage.html#specifying-tests-selecting-tests>`__.\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "Copyright (c) 2013, David R. MacIver\n\nAll code in this repository except where explicitly noted otherwise is released\nunder the Mozilla Public License v 2.0. You can obtain a copy at https://mozilla.org/MPL/2.0/.\n\nSome code in this repository comes from other projects. Where applicable, the\noriginal copyright and license are noted and any modifications made are released\ndual licensed with the original license.\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/HypothesisWorks/hypothesis/master/brand/dragonfly-rainbow.svg\" width=\"300\">\n</div>\n\n# Hypothesis\n\n* [Website](https://hypothesis.works/)\n* [Documentation](https://hypothesis.readthedocs.io/en/latest/)\n* [Source code](https://github.com/hypothesisWorks/hypothesis/)\n* [Contributing](https://github.com/HypothesisWorks/hypothesis/blob/master/CONTRIBUTING.rst)\n* [Community](https://hypothesis.readthedocs.io/en/latest/community.html)\n\nHypothesis is the property-based testing library for Python. With Hypothesis, you write tests which should pass for all inputs in whatever range you describe, and let Hypothesis randomly choose which of those inputs to check - including edge cases you might not have thought about. For example:\n\n```python\nfrom hypothesis import given, strategies as st\n\n\n@given(st.lists(st.integers()))\ndef test_matches_builtin(ls):\n    assert sorted(ls) == my_sort(ls)\n```\n\nThis randomized testing can catch bugs and edge cases that you didn't think of and wouldn't have found. In addition, when Hypothesis does find a bug, it doesn't just report any failing example — it reports the simplest possible one. This makes property-based tests a powerful tool for debugging, as well as testing.\n\nFor instance,\n\n```python\ndef my_sort(ls):\n    return sorted(set(ls))\n```\n\nfails with the simplest possible failing example:\n\n```\nFalsifying example: test_matches_builtin(ls=[0, 0])\n```\n\n### Installation\n\nTo install Hypothesis:\n\n```\npip install hypothesis\n```\n\nThere are also [optional extras available](https://hypothesis.readthedocs.io/en/latest/extras.html).\n"
  },
  {
    "path": "brand/README.md",
    "content": "# Logos and other pretty things\n\nHypothesis has a beautiful logo, thanks to the generous work of Libby Berrie in [issue #1519](https://github.com/HypothesisWorks/hypothesis/issues/1519).  The [CogWorks class of 2019](https://github.com/CogWorksBWSI) named the dragonfly \"Scout\", as a job description and after *To Kill a Mockingbird*.\n\nGeneral guidelines:\n\n- Prefer vector (`.svg`) formats to raster formats (`.png`) wherever possible.  However, some viewers don't handle the layers well - e.g. the left eye might be drawn in front of the head - in which case you might prefer `.png`.\n- We consider the rainbow version to be canonical.  The blue variant is provided for cases such as monochrome versions or printing with a limited palette.\n\nWith that in mind, you are welcome to use these logos to refer to Hypothesis - and if you're not sure whether a specific use is OK, please get in touch and ask!\n\nFor example, we often bring Hypothesis stickers to conferences but can't make it to everything.  If you want to print your own Hypothesis stickers, upload `sticker.png` to [StickerMule](https://www.stickermule.com/custom-stickers) and pick one of the die-cut vinyl options - that's how we get ours!\n\n![Hypothesis stickers suitable for your laptop](./stickers.jpg)\n\n## Colour palette in GIMP format\n\nA [colour palette in GIMP format](hypothesis.gpl) (`.gpl`) is also provided with the intent of making it easier to produce graphics and documents which reuse the colours in the Hypothesis Dragonfly logo by Libby Berrie.\n\nThe `hypothesis.gpl` file should be copied or imported to the appropriate location on your filesystem. For example:\n\n- `/usr/share/inkscape/palettes/` for Inkscape on Ubuntu 18.08\n- Edit -> Colors -> Import... then select the `hypothesis.gpl` file in Scribus on Ubuntu 18.08\n- Windows -> Dockable Dialogs -> Palettes -> Palettes Menu -> Add Palette -> Import from file... then select the `hypothesis.gpl` file in GIMP on Ubuntu 18.08\n\nOnce imported, the colour palette is then available for easy manipulation of colours within the user interface.\n\nInkscape:\n\n![Inkscape showing Hypothesis colour palette](inkscape.png)\n\nGIMP:\n\n![GIMP showing Hypothesis colour palette](gimp.png)\n"
  },
  {
    "path": "brand/hypothesis.gpl",
    "content": "GIMP Palette\nName: Hypothesis Palette\nColumns: 1\n# generated by @kathyreid <kathy@kathyreid.id.au>\n# from the Dragonfly logo created by @libbyberrie\n# the purpose of this file is to make it easy to import colours into\n#  Inkscape, GIMP, Scribus etc\n# Colours deliberately prefixed with `Hypothesis.xxx` to appear grouped in apps\n0   0   0    Black (#000000)\n255 255 255  White (#FFFFFF)\n165 100 250  Hypothesis.Violet (#A564FA)\n 98 183 255  Hypothesis.DuckEggBlue (#62B7FF)\n136 255 127  Hypothesis.AppleGreen (#88FF7F)\n255 252  54  Hypothesis.WarmYellow (#FFFC36)\n255 202 120  Hypothesis.Apricot (#FFCA78)\n255 128 128  Hypothesis.LightCoral (#FF8080)\n163 255 247  Hypothesis.Turquoise (#A3FFF7)\n163 233 255  Hypothesis.SkyBlue (#A3E9FF)\n128 211 231  Hypothesis.DarkSky (#80D3E7)\n101 195 213  Hypothesis.MediumTeal (#65C3D5)\n 92 201 236  Hypothesis.OceanBlue (#5CC9EC)\n 39 135 178  Hypothesis.DarkTeal (#2787B2)\n 87  83 139  Hypothesis.OceanPurple (#57538B)\n 68  66  95  Hypothesis.DarkOceanPurple (#44425F)\n"
  },
  {
    "path": "build.sh",
    "content": "#!/usr/bin/env bash\n\n# This script is here to bootstrap the Hypothesis build process into a working\n# version of Python, then hand over to the actual Hypothesis build runner (which\n# is written in Python instead of bash).\n\nif [ -n \"${CI:-}\" ] ; then echo \"::group::Build setup\" ; fi\n\nset -o xtrace\nset -o errexit\nset -o nounset\n\nROOT=\"$(git -C \"$(dirname \"$0\")\" rev-parse --show-toplevel)\"\n\nexport HYPOTHESIS_ROOT=\"$ROOT\"\n\nSCRIPTS=\"$ROOT/tooling/scripts\"\n\n# shellcheck source=tooling/scripts/common.sh\nsource \"$SCRIPTS/common.sh\"\n\nPYTHON_VERSION=\"3.14.3\"\n\nif [ -n \"${GITHUB_ACTIONS-}\" ] || [ -n \"${CODESPACES-}\" ] || [ -n \"${CLAUDECODE-}\" ] ; then\n    # We're on GitHub Actions, Codespaces, or Claude Code and already have a suitable Python\n    PYTHON=$(command -v python3 || command -v python)\nelse\n    # Otherwise, we install it from scratch\n    # NOTE: tooling keeps this version in sync with ci_version in tooling\n    \"$SCRIPTS/ensure-python.sh\" \"$PYTHON_VERSION\"\n    PYTHON=$(pythonloc \"$PYTHON_VERSION\")/bin/python\nfi\n\nTOOL_REQUIREMENTS=\"$ROOT/requirements/tools.txt\"\n\n# append PYTHON_VERSION to bust caches when we upgrade versions\nTOOL_HASH=$( (cat \"$TOOL_REQUIREMENTS\" && echo \"$PYTHON_VERSION\") | \"$PYTHON\" \"$SCRIPTS/tool-hash.py\")\n\nTOOL_VIRTUALENV=\"$VIRTUALENVS/build-$TOOL_HASH\"\nTOOL_PYTHON=\"$TOOL_VIRTUALENV/bin/python\"\n\nexport PYTHONPATH=\"$ROOT/tooling/src\"\n\nif ! \"$TOOL_PYTHON\" -m hypothesistooling check-installed ; then\n  rm -rf \"$TOOL_VIRTUALENV\"\n  if [ -n \"${CLAUDECODE-}\" ] ; then\n    # Claude Code: use venv (available) and skip pip upgrades (debian-managed)\n    \"$PYTHON\" -m venv \"$TOOL_VIRTUALENV\"\n  else\n    \"$PYTHON\" -m pip install --upgrade pip\n    \"$PYTHON\" -m pip install --upgrade virtualenv\n    \"$PYTHON\" -m virtualenv \"$TOOL_VIRTUALENV\"\n  fi\n  \"$TOOL_PYTHON\" -m pip install --no-warn-script-location -r requirements/tools.txt\nfi\n\nif [ -n \"${CI:-}\" ] ; then echo \"::endgroup::\" ; fi\n\n\"$TOOL_PYTHON\" -m hypothesistooling \"$@\"\n"
  },
  {
    "path": "guides/README.md",
    "content": "# Guides for Hypothesis Development\n\nThis is a general collection of useful documentation for people working on Hypothesis.\n\nIt is separate from the main documentation because it is not much use if you are merely *using* Hypothesis. It's purely for working on it, and aimed more at maintainers than casual contributors.\n"
  },
  {
    "path": "guides/api-style.rst",
    "content": "===============\nHouse API Style\n===============\n\nHere are some guidelines for how to write APIs so that they \"feel\" like\na Hypothesis API. This is particularly focused on writing new strategies, as\nthat's the major place where we add APIs, but also applies more generally.\n\nNote that it is not a guide to *code* style, only API design.\n\nThe Hypothesis style evolves over time, and earlier strategies in particular\nmay not be consistent with this style, and we've tried some experiments\nthat didn't work out, so this style guide is more normative than descriptive\nand existing APIs may not match it. Where relevant, backwards compatibility is\nmuch more important than conformance to the style.\n\nWe also encourage `third-party extensions <https://hypothesis.readthedocs.io/en/latest/strategies.html>`_\nto follow this style guide, for consistent and user-friendly testing APIs,\nor get in touch to discuss changing it if it doesn't fit their domain.\n\n~~~~~~~~~~~~~~~~~~\nGeneral Guidelines\n~~~~~~~~~~~~~~~~~~\n\n* When writing extras modules, consistency with Hypothesis trumps consistency\n  with the library you're integrating with.\n* *Absolutely no subclassing as part of the public API*\n* We should not strive too hard to be pythonic, but if an API seems weird to a\n  normal Python user we should see if we can come up with an API we like as\n  much but is less weird.\n* Code which adds a dependency on a third party package should be put in a\n  hypothesis.extra module.\n* Complexity should not be pushed onto the user. An easy to use API is more\n  important than a simple implementation.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~\nGuidelines for strategies\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* A strategy function should be somewhere between a recipe for how to build a\n  value and a range of valid values.\n* It should not include distribution hints. The arguments should only specify\n  how to produce a valid value, not statistical properties of values.\n* Strategies should try to paper over non-uniformity in the underlying types\n  as much as possible (e.g. ``hypothesis.extra.numpy`` has a number of\n  workarounds for numpy's odd behaviour around object arrays).\n* Strategies should usually default to allowing generation of any example they\n  can support.  The only exceptions should be cases where certain inputs would\n  trigger test failures which are almost never of interest: currently just\n  non-UTF8 characters in ``st.text()``, and Numpy array shapes with zero\n  dimensions or sides of length zero.  In each case opting in should be trivial.\n\n~~~~~~~~~~~~~~~~~\nArgument handling\n~~~~~~~~~~~~~~~~~\n\nWe have a reasonably distinctive style when it comes to handling arguments:\n\n* Arguments must be validated to the greatest extent possible. Hypothesis\n  should reject bad arguments with an InvalidArgument error, not fail with an\n  internal exception.\n* We make extensive use of default arguments. If an argument could reasonably\n  have a default, it should.\n* Exception to the above: strategies for collection types should *not* have a\n  default argument for element strategies.\n* Arguments which have a default value should also be keyword-only, with the\n  exception of ``min_value`` and ``max_value`` (see \"Argument Names\" below).\n* ``min_value`` and ``max_value`` should default to None for unbounded types\n  such as integers, and the minimal or maximal values for bounded types such\n  as datetimes.  ``floats()`` is an explicit exception to this rule due to\n  special handling for infinities and not-a-number.\n* Interacting arguments (e.g. arguments that must be in a particular order, or\n  where at most one is valid, or where one argument restricts the valid range\n  of the other) are fine, but when this happens the behaviour of defaults\n  should automatically be adjusted. e.g. if the normal default of an argument\n  would become invalid, the function should still do the right thing if that\n  default is used.\n* Where the actual default used depends on other arguments, the default parameter\n  should be None.\n* It's worth thinking about the order of arguments: the first one or two\n  arguments are likely to be passed positionally, so try to put values there\n  where this is useful and not too confusing.\n* When adding arguments to strategies, think carefully about whether the user\n  is likely to want that value to vary often. If so, make it a strategy instead\n  of a value. In particular if it's likely to be common that they would want to\n  write ``some_strategy.flatmap(lambda x: my_new_strategy(argument=x))`` then\n  it should be a strategy.\n* Arguments should not be \"a value or a strategy for generating that value\".\n  If you find yourself inclined to write something like that, instead make it\n  take a strategy. If a user wants to pass a value they can wrap it in a call\n  to ``just``.\n* If a combination of arguments make it impossible to generate anything,\n  ``raise InvalidArgument`` instead of ``return nothing()``.  Returning the\n  null strategy is conceptually nice, but can lead to silently dropping parts\n  from composed strategies and thus unexpectedly weak tests.\n\n~~~~~~~~~~~~~~\nFunction Names\n~~~~~~~~~~~~~~\n\nWe don't have any real consistency here. The rough approach we follow is:\n\n* Names are `snake_case` as is standard in Python.\n* Strategies for a particular type are typically named as a plural name for\n  that type. Where that type has some truncated form (e.g. int, str) we use a\n  longer form name.\n* Other strategies have no particular common naming convention.\n\n~~~~~~~~~~~~~~\nArgument Names\n~~~~~~~~~~~~~~\n\nWe should try to use the same argument names and orders across different\nstrategies wherever possible. In particular:\n\n* For collection types, the element strategy (or strategies) should always be\n  the first arguments. Where there is only one element strategy it should be\n  called ``elements`` (but e.g. ``dictionaries`` has element strategies named\n  ``keys`` and ``values`` and that's fine).\n* For ordered types, the first two arguments should be a lower and an upper\n  bound. They should be called ``min_value`` and ``max_value``.\n* Collection types should have a ``min_size`` and a ``max_size`` parameter that\n  controls the range of their size. ``min_size`` should default to zero and\n  ``max_size`` to ``None`` (even if internally it is bounded).\n\n\n~~~~~~~~~~~~~~~\nDeferred Errors\n~~~~~~~~~~~~~~~\n\nAs far as is reasonable, functions should raise errors when the test is run\n(typically by deferring them until you try to draw from the strategy),\nnot when they are called.\nThis mostly applies to strategy functions and some error conditions in\n``@given`` itself.\n\nGenerally speaking this should be taken care of automatically by use of the\n``@defines_strategy`` decorator.\n\nWe do not currently do this for the ``TypeError`` that you will get from\ncalling the function incorrectly (e.g. with invalid keyword arguments or\nmissing required arguments).\nIn principle we could, but it would result in much harder to read function\nsignatures, so we would be trading off one form of comprehensibility for\nanother, and so far that hasn't seemed to be worth it.\n\nThe main reasons for preferring this style are:\n\n* Errors at test import time tend to throw people and be correspondingly hard\n  for them to debug.\n  There's an expectation that errors in your test code result in failures in\n  your tests, and the fact that that test code happens to be defined in a\n  decorator doesn't seem to change that expectation for people.\n* Things like deprecation warnings etc. localize better when they happen\n  inside the test - test runners will often swallow them or put them in silly\n  places if they're at import time, but will attach any output that happens\n  in the test to the test itself.\n* There are a lot of cases where raising an error, deprecation warning, etc.\n  is *only* possible in a test - e.g. if you're using the inline style with\n  `data <https://hypothesis.readthedocs.io/en/latest/data.html#drawing-interactively-in-tests>`_,\n  or if you're using\n  `flatmap <https://hypothesis.readthedocs.io/en/latest/data.html#chaining-strategies-together>`_\n  or\n  `@composite <https://hypothesis.readthedocs.io/en/latest/data.html#composite-strategies>`_\n  then the strategy won't actually get evaluated until we run the test,\n  so that's the only place they can happen.\n  It's nice to be consistent, and it's weird if sometimes strategy errors result in\n  definition time errors and sometimes they result in test errors.\n\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nInferring strategies from specifications\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nFunctions which infer a strategy from some specification or schema are both\nconvenient for users, and offer a single source of truth about what inputs\nare allegedly valid and actually tested for correctness.\n\n* Such functions should be named \"``from_foo()``\" and the first argument should\n  be the thing from which a strategy is inferred - like ``st.from_type()``,\n  ``st.from_regex()``, ``extra.lark.from_lark()``, ``extra.numpy.from_dtype()``,\n  etc.  Any other arguments should be optional keyword-only parameters.\n* There should be a smooth path to customise *parts* of an inferred strategy,\n  i.e. not require the user to start from scratch if they need something a\n  little more specific.  ``from_dtype()`` does this well; ``from_type()`` supports\n  it by `pointing users to builds() instead <https://hypothesis.works/articles/types-and-properties/>`_.\n* Where practical, ensure that the ``repr`` of the returned strategy shows\n  how it was constructed - only using e.g. ``@st.composite`` if required.\n  For example, ``repr(from_type(int)) == \"integers()\"``.\n\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nA catalogue of current violations\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe following are places where we currently deviate from this style. Some of\nthese should be considered targets for deprecation and/or improvement.\n\n* ``hypothesis.extra.numpy`` has some arguments which can be either\n  strategies or values.\n* ``hypothesis.extra.numpy`` assumes arrays are fixed size and doesn't have\n  ``min_size`` and ``max_size`` arguments (but this is probably OK because of\n  more complicated shapes of array).\n* ``hypothesis.stateful`` is a great big subclassing based train wreck.\n"
  },
  {
    "path": "guides/documentation.rst",
    "content": "=====================================\nThe Hypothesis Documentation Handbook\n=====================================\n\nGood documentation can make the difference between good code and useful code -\nand Hypothesis is written to be used, as widely as possible.\n\nThis is a working document-in-progress with some tips for how we try to write\nour docs, with a little of the what and a bigger chunk of the how.\nIf you have ideas about how to improve these suggestions, meta issues or pull\nrequests are just as welcome as for docs or code :D\n\n----------------------------\nWhat docs should be written?\n----------------------------\n\nAll public APIs should be comprehensively described.  If the docs are\nconfusing to new users, incorrect or out of date, or simply incomplete - we\nconsider all of those to be bugs; if you see them please raise an issue and\nperhaps submit a pull request.\n\nThat's not much advice, but it's what we have so far.\n\n------------\nUsing Sphinx\n------------\n\nWe use `the Sphinx documentation system <http://sphinx-doc.org>`_ to\nconvert the .rst files into html with formatting and\ncross-references.  Without repeating the docs for Sphinx, here are some tips:\n\n- When documenting a Python object (function, class, module, etc.), you can\n  use autodoc to insert and interpret the docstring.\n\n- When referencing a function, you can insert a reference to a function as\n  (eg) ``:func:`hypothesis.given`\\``, which will appear as\n  ``hypothesis.given()`` with a hyperlink to the appropriate docs.  You can\n  show only the last part (unqualified name) by adding a tilde at the start,\n  like ``:func:`~hypothesis.given`\\ `` -> ``given()``.  Finally, you can give\n  it alternative link text in the usual way:\n  ``:func:`other text <hypothesis.given>`\\ `` -> ``other text``.\n\n- For the formatting and also hyperlinks, all cross-references should use the\n  Sphinx cross-referencing syntax rather than plain text.\n\n\n-----------------\nChangelog Entries\n-----------------\n\n`Hypothesis does continuous deployment <https://github.com/HypothesisWorks/hypothesis-python/issues/555>`_,\nwhere every pull request that touches ``./src`` results in a new release.\nThat means every contributor gets to write their changelog!\n\nA changelog entry should be written in a new ``RELEASE.rst`` file in\nthe `hypothesis-python` directory. The first line of the file specifies the component\nof the version number that will be updated, according to our\n`semantic versioning <https://semver.org/>`_ policy.\n\n- ``RELEASE_TYPE: major`` is for breaking changes, and will only be used by the\n  core team after extensive discussion.\n- ``RELEASE_TYPE: minor`` is for anything that adds to the public (ie documented)\n  API, changes an argument signature, or adds a new deprecation or health check.\n  Minor (or patch) releases **must not** cause errors in any code that runs\n  without errors on an earlier version of Hypothesis, using only the public API.\n  Silent errors *may* be converted to noisy errors, but generally we prefer\n  to issue a deprecation warning and use the new behaviour if possible.\n  This stability policy only applies to use of Hypothesis itself, not the\n  results of user-written tests that use Hypothesis.\n- ``RELEASE_TYPE: patch`` is for changes that are not visible in the public\n  interface, from improving a docstring to backwards-compatible improvements\n  in shrinking behaviour.\n\nThis first line will be removed from the final change log entry.\nThe remaining lines are the actual changelog text for this release,\nwhich should:\n\n- concisely describe what changed and why\n- use Sphinx cross-references to any functions or classes mentioned\n- if closing an issue, mention it with the ``:issue:`` role to generate a link\n- finish with a note of thanks from the maintainers:\n  \"Thanks to <your name> for this bug fix / feature / contribution\"\n  (depending on which it is).  If this is your first contribution,\n  don't forget to add yourself to AUTHORS.rst!\n"
  },
  {
    "path": "guides/internals.rst",
    "content": "===================================\nHow to Work on Hypothesis Internals\n===================================\n\nThis is a guide to how to work on Hypothesis internals,\nwith a particular focus on helping people who are new to it.\nRight now it is very rudimentary and is intended primarily for people who are\nlooking to get started writing shrink passes as part of our `current outreach\nprogram to get more people doing that <https://github.com/HypothesisWorks/hypothesis/issues/1093>`_,\nbut it will expand over time.\n\n------------------------\nBird's Eye View Concepts\n------------------------\n\nThe core engine of Hypothesis is called Conjecture.\n\nThe \"fundamental idea\" of Conjecture is that you can represent an arbitrary\nrandomized test case as the sequence of bytes read from the pseudo-random\nnumber generator (PRNG) that produced it.\nWhenever the test did something \"random\" it actually read the next bytes and\ndid what they told it to do.\nBut those bytes didn't *have* to come from a PRNG, and we can run the test\ngiven any byte sequence we like. By manipulating the choice of bytes, we can achieve\nmore interesting effects than pure randomness would allow us to do, while\nretaining the power and ease of use of random testing.\n\nThe greatest strength of this idea is that we have a single source of truth\nfor what an example should look like: Every byte sequence is one that *could*\nhave come from a PRNG, and thus is a valid thing to try for our test.\nThe only ways it can fail to be a valid test input are for it to be too short\nor for it to not satisfy one of the test's preconditions, and both are easily\ndetectable.\n\nThe idea of shrinking in particular is that once we have this representation,\nwe can shrink arbitrary test cases based on it. We try to produce a string that\nis *shortlex minimal*. What this means is that it has the shortest possible\nlength and among those strings of minimal length is lexicographically (i.e. the\nnormal order on strings - find the first byte at which they differ and use that\nto decide) smallest.\n\nIdeally we could think of the shrinker as a generic function that takes a\nstring satisfying some predicate and returns the shortlex minimal string that\nalso satisfies it.\n\nWe depart from this ideal in two ways:\n\n* we can only *approximate* such a minimal string. Finding the actual minimum is\n  intractable in general.\n* we are only interested in minimizing things where the predicate goes through\n  the Hypothesis API, which lets us track how the data is used and use that to\n  guide the process.\n\nWe then use a number of different transformations of the string to try and\nreduce our input. These vary from principled general transformations to shameless\nhacks that special case something we need to work well.\n\nOne such example of a hack is the handling of floating point numbers. There are\na couple of lexicographic shrinks that are always valid but only really make\nsense for our particular encoding of floats. We check if we're working\non something that is of the right size to be a float and apply those\ntransformations regardless of whether it is actually meant to be a float.\nWorst case scenario it's not a float and they don't work, and we've run a few\nextra test cases.\n\n--------------------------\nUseful Files to Know About\n--------------------------\n\nThe code associated with Conjecture lives in\n`src/hypothesis/internal/conjecture <https://github.com/HypothesisWorks/hypothesis/tree/master/hypothesis-python/src/hypothesis/internal/conjecture>`_.\nThere are a number of files in there,\nbut the most important ones are ``engine.py`` and ``data.py``.\n``data.py`` defines the core type that is used to represent test cases,\nand ``engine.py`` contains the main driver for deciding what test cases to run.\n\nThere is also ``minimizer.py``, which contains a general purpose lexicographic\nminimizer. This is responsible for taking some byte string and a predicate over\nbyte strings and producing a string of the same length which is lexicographically\nsmaller. Unlike the shrinker in general, this *is* supposed to work on arbitrary\npredicates and doesn't know anything about the testing API. We typically apply\nthis to subsets of the bytes for a test input with a predicate that knows how\nto integrate those subsets into a larger test. This is the part of the code\nthat means we can do things like replacing an integer with a smaller one.\n\n-------\nTesting\n-------\n\nFor general information about how to test Hypothesis, take a look at\nthe `testing guide <testing-hypothesis.rst>`_, but there are a couple\nof areas that it's worth specifically highlighting for making changes\nto the engine:\n\nThe first is `tests/conjecture/ <https://github.com/HypothesisWorks/hypothesis/tree/master/hypothesis-python/tests/conjecture>`_,\nwhich is a set of unit tests designed to put the engine into particular scenarios to exercise specific behaviours,\nwith a goal of achieving 100% coverage on it in isolation (though it currently does not quite achieve that for some specific edge cases.\nWe may fix and enforce this later).\n\nThe other set of tests that are worth knowing about are the quality tests,\nin `tests/quality <https://github.com/HypothesisWorks/hypothesis/tree/master/hypothesis-python/tests/quality>`_.\nThese assert specific hard to satisfy properties about the examples that Hypothesis finds -\neither their existence, or something about the final shrunk result.\n\n-----------------------\nEngine Design Specifics\n-----------------------\n\nThere are a couple of code patterns that are mostly peculiar to Conjecture that\nyou may not have encountered before and are worth being aware of.\n\n~~~~~~~~~~~~~~~~~~~~\nSearch State Objects\n~~~~~~~~~~~~~~~~~~~~\n\nThere are a number of cases where we find ourself with a user-provided function\n(where the \"user\" might still be something that is entirely our code) and we\nwant to pass a whole bunch of different examples to it in order to achieve some\nresult. Currently this includes each of the main engine, the Shrinker (in\n``engine.py``) and the minimizer, but there are likely to be more in future.\n\nWe typically organise such things in terms of an object that you create with\nthe function and possibly an initial argument that stores these on self and\nhas some ``run`` or similar method. They then run for a while, repeatedly\ncalling the function they were given.\n\nGenerally speaking they do not call the function directly, but instead wrap\ncalls to it. This allows them to implement a certain amount of decision caching,\ne.g. avoiding trying the same shrink twice, but also gives us a place where we\ncan update metadata about the search process.\n\nFor objects whose goal is some form of optimisation (Shrinker, Minimizer) one\nof the pieces of metadata they will typically track is a \"current target\". This\nis typically the best example they have seen so far. By wrapping every call to\nthe predicate, we ensure that we never miss an example even when we're passing\nthrough other things.\n\nFor objects whose goal is some broader form of search (currently only\n``ConjectureRunner``) this also allows them to keep track of *other* examples\nof interest. For example, as part of our multiple bug discovery,\n``ConjectureRunner`` keeps track of the smallest example of each distinct\nfailure that it has seen, and updates this automatically each time the test\nfunction is called. This means that if during shrinking we \"slip\" and find a\ndifferent bug than the one we started with, we will *not* shrink to that, but\nit will get remembered by the runner if it was either novel or better than our\ncurrent example.\n\n~~~~~~~~~~~\nWeird Loops\n~~~~~~~~~~~\n\nThe loops inside a lot of the engine look very strange and unidiomatic. For\nexample:\n\n.. code-block:: python\n\n        i = 0\n        while i < len(self.intervals):\n            u, v = self.intervals[i]\n            if not self.incorporate_new_buffer(\n                self.shrink_target.buffer[:u] + self.shrink_target.buffer[v:]\n            ):\n                i += 1\n\nThe more natural way to write this in Python would be:\n\n.. code-block:: python\n\n        for u, v in self.intervals:\n            self.incorporate_new_buffer(\n                self.shrink_target.buffer[:u] + self.shrink_target.buffer[v:]\n            )\n\nThis is not equivalent in this case, and would exhibit the wrong behaviour.\n\nEvery time ``incorporate_new_buffer`` succeeds, it changes the shape of the\ncurrent shrink target. This consequently changes the shape of intervals, both\nits particular values and its current length - on each loop iteration the loop\nmight stop either because ``i`` increases or because ``len(self.intervals)``\ndecreases.\n\nWe do not reset ``i`` to zero on success, as this would cause us to retry deleting\nthings that we have already tried. This *might* work, but is less likely to.\nIn the event that none of the earlier deletions succeed, this causes us to do\nretry the entire prefix uselessly, which can result in a pass taking O(n^2) time\nto do O(n) deletions.\n\nAn additional quirk is that we only increment ``i`` on failure. The reason for\nthis is that if we successfully deleted the current interval then the interval\nin position ``i`` has been replaced with something else, which is probably the\nnext thing we would have tried deleting if we hadn't succeeded (or something\nlike it), so we don't want to advance past it.\nThis is specific to deletion: If we are just replacing the contents of\nsomething then we expect it to still be in the same place, so there we increment\nunconditionally.\nExamples of this include ``zero_draws`` and ``minimize_individual_blocks``.\n\n------------\nThe Shrinker\n------------\n\nThe shrinking part of Hypothesis is organised into a single class called ``Shrinker``\nthat lives in ``hypothesis/internal/conjecture/shrinker.py``.\n\nIts job is to take an initial ``ConjectureData`` object and some predicate that\nit satisfies, and to try to produce a simpler ``ConjectureData`` object that\nalso satisfies that predicate.\n\nThe search process mostly happens in the ``shrink`` method, which tries various\nshrink passes in the ``greedy_shrink`` method and then reports on the outcome.\nFor details, you are strongly encouraged to read the source code.  It is very\nwell commented, and as the subject of active research often has newer techniques\nthan are documented here.\n\n~~~~~~~~~~~~~\nSearch Passes\n~~~~~~~~~~~~~\n\nSearch passes are methods on the ``Shrinker`` class. They are\ndesigned to take the current shrink target and try a number of things that might\nbe sensible shrinks of it.\n\nTypically the design of a search pass is that it should always try to run to\ncompletion rather than exiting as soon as it's found something good, but that\nit shouldn't retry things that are too like stuff it has already tried just\nbecause something worked. So for example in the above loop, we try deleting\neach interval (these roughly correspond to regions of the input that are\nresponsible for some particular value or small number of adjacent values).\nWhen we succeed, we keep going and try deleting more intervals, but we don't\ntry to delete any intervals before the current index.\n\nThe reason for this is that retrying things from the beginning might work but\nprobably won't. Thus if we restarted every time we made a change we would end\nup doing a lot of useless work. Additionally, they are *more* likely to work\nafter other shrink passes have run because frequently other changes are likely\nto unlock changes in the current pass that were previously impossible. e.g.\nwhen we reorder some examples we might make a big region deletable that\npreviously contained something critical to the relevant behaviour of the test\nbut is now just noise.\n\nBecause the shrinker runs in a big loop, if we've made progress the shrink pass\nwill always be run again (assuming we don't hit some limit that terminates the\nshrink early, but by making the shrinker better we try to ensure that that\nnever happens).\nThis means that we will always get an opportunity to start again later if we\nmade progress, and if we didn't make progress we've tried everything anyway.\n\n\n~~~~~~~~~~~~~~~~~~~~~~~\nExpensive Shrink Passes\n~~~~~~~~~~~~~~~~~~~~~~~\n\nWe have a bunch of search passes that are considered \"expensive\". Typically\nthis means \"quadratic or worse complexity\". When shrinking we initially don't\nrun these, and the first time that we get to the end of our main passes and\nhave failed to make the input any smaller, we then turn them on.\n\nThis allows the shrinker to switch from a good but slightly timid mode while its\ninput is large into a more aggressive DELETE ALL THE THINGS mode once that stops\nworking. By that point we've usually made our input small enough that quadratic\ncomplexity is acceptable.\n\nWe turn these on once and then they stay on. The reason for this is to avoid a\n\"flip-flopping\" scenario where an expensive pass unlocks one trivial change that\nthe cheap passes can find and then they get stuck again and have to do an extra\nuseless run through the passes to prove that.\n\n~~~~~~~~~~~~~~~~~~~~~~\nAdaptive Shrink Passes\n~~~~~~~~~~~~~~~~~~~~~~\n\nA useful trick that some of the shrink passes use is to try a thing and if it\ndoesn't work take a look at what the test function did to guess *why* it didn't\nwork and try to repair that.\n\nTwo example such passes are ``zero_examples`` and the various passes that try to\nminimize individual blocks lexicographically.\n\nWhat happens in ``zero_examples`` is that we try replacing the region corresponding\nto a draw with all zero bytes. If that doesn't work, we check if that was because\nof changing the size of the example (e.g. doing that with a list will make the\nlist much shorter) and messing up the byte stream after that point. If this\nwas what happened then we try again with a sequence of zeroes that corresponds\nto the size of the draw call in the version we tried that didn't work.\n\nThe logic for what we do with block minimization is in ``try_shrinking_blocks``.\nWhen it tries shrinking a block and it doesn't work, it checks if the sized\nchanged. If it does then it tries deleting the number of bytes that were lost\nimmediately after the shrunk block to see if it helps.\n\n\n--------------\nPlaying Around\n--------------\n\nI often find that it is informative to watch the shrink process in action using\nHypothesis's verbosity settings. This can give you an idea of what the format\nof your data is, and how the shrink process transforms it.\n\nIn particular, it is often useful to run a test with the flag ``-s`` to tell it\nnot to hide output and the environment variable ``HYPOTHESIS_VERBOSITY_LEVEL=debug``.\nThis will give you a very detailed log of what the testing process is running,\nalong with information about what passes in the shrinker rare running and how\nthey transform it.\n\n---------------\nGetting Started\n---------------\n\nThe best way of getting started on working on the engine is to work on the\nshrinker. This is because it has the most well defined problems, the best\ndocumented code among the engine, and it's generally fun to work on.\n\nIf you have not already done so, check out `Issue #1093 <https://github.com/HypothesisWorks/hypothesis/issues/1093>`_,\nwhich collates a number of other issues about shrink quality that are good starting\npoints for people.\n\nThe best place to get started thus is to take a look at those linked issues and\njump in and try things! Find one that you think sounds fun. Note that some\nof them suggest not doing these as your first foray into the shrinker, as some\nare harder than others.\n\n*Please* ask questions if you have any - either the main issue for general\npurpose questions or specific issues for questions about a particular problem -\nif you get stuck or if anything doesn't make sense. We're trying to make this\nprocess easier for everyone to work on, so asking us questions is actively\nhelpful to us and we will be very grateful to you for doing so.\n"
  },
  {
    "path": "guides/review.rst",
    "content": "===================================\nThe Hypothesis Code Review Handbook\n===================================\n\nThis document outlines the process for reviewing changes to Hypothesis. It's\npartly descriptive, partly prescriptive, and entirely prone to change in\nresponse to circumstance and need. We're still figuring this thing out!\n\n-----------------\nWhat Needs Review\n-----------------\n\nAll changes must be signed off by at least one person\nwith write access to the repo other than the author of the change.\n\n----------------\nHow Review Works\n----------------\n\nOnce the build is green and a reviewer has approved the change, anyone on the\nmaintainer team may merge the request.\n\nMore than one maintainer *may* review a change if they wish to, but it's\nnot required. Any maintainer may block a pull request by requesting changes.\n\nConsensus on a review is best but not required. If some reviewers have\napproved a pull request and some have requested changes, ideally you\nwould try to address all of the changes, but it is OK to dismiss dissenting\nreviews if you feel it appropriate.\n\nWe've not tested the case of differing opinions much in practice yet, so\nwe may grow firmer guidelines on what to do there over time.\n\n------------\nReview Goals\n------------\n\nAt a high level, the two things we're looking for in review are answers\nto the following questions:\n\n1. Is this change going to make users' lives worse?\n2. Is this change going to make the maintainers' lives worse?\n\nCode review is a collaborative process between the author and the\nreviewer to try to ensure that the answer to both of those questions\nis no.\n\nIdeally of course the change should also make one or both of the users'\nand our lives *better*, but it's OK for changes to be mostly neutral.\nThe author should be presumed to have a good reason for submitting the\nchange in the first place, so neutral is good enough!\n\n--------------\nSocial Factors\n--------------\n\n* Always thank external contributors. Thank maintainers too, ideally!\n* Remember that the `Code of Conduct <https://hypothesis.readthedocs.io/en/latest/community.html#code-of-conduct>`_\n  applies to pull requests and issues too. Feel free to throw your weight\n  around to enforce this if necessary.\n* Anyone, maintainer or not, is welcome to do a code review. Only official\n  maintainers have the ability to actually approve and merge a pull\n  request, but outside review is also welcome.\n\n------------\nRequirements\n------------\n\nThe rest of this document outlines specific things reviewers should\nfocus on in aid of this, broken up by sections according to their area\nof applicability.\n\nAll of these conditions must be satisfied for merge. Where the reviewer\nthinks this conflicts with the above higher level goals, they may make\nan exception if both the author and another maintainer agree.\n\n\n~~~~~~~~~~~~~\nOrthogonality\n~~~~~~~~~~~~~\n\nFor all minor or patch releases, we enforce a hard and fast rule that they\ncontain no more than one user-visible change. Major releases are allowed\nto bundle multiple changes together, but these should be structured as\nsmaller pull requests into some tracking branch.\n\nWe are currently very bad at this, so reviewers should feel empowered\nto be extra strict and provide a lot of push back on this.\n\nWhat counts as a user visible change is somewhat up to individual\njudgement, but you should err in the direction of assuming that\nif it might count then it does count.\n\nA good rule of thumb is that if the ``RELEASE.rst`` uses the words \"additionally\"\nor needs bullet points to be clear, it is likely too large.\n\nIdeally changes that are not user visible should also be self-contained\ninto their own releases, but a certain amount of leniency is permitted -\nit's certainly OK to do a moderate amount of refactoring while you're\nin the area, and if a pull request involves no release at all then the same\nlevel of orthogonality is not required (but is still desirable).\n\n~~~~~~~~~~~~~~~~~~~~~~\nClarity of Description\n~~~~~~~~~~~~~~~~~~~~~~\n\nThe ``RELEASE.rst`` should contain a description of the change that\nmakes clear:\n\n1. The motivation for the change\n2. The likely consequences of the change\n\nThis doesn't have to be an essay. If you're following the orthogonality\nrequirements a paragraph or two is likely sufficient.\n\nAny additional information that is useful to reviewers should be provided\nin the pull request comment. This can include e.g. background, why the\nparticular approach was taken, references to internals that are unlikely\nto be of interest to users.\n\n~~~~~~~~~~~~~~~~~~~~~\nFunctionality Changes\n~~~~~~~~~~~~~~~~~~~~~\n\nThis section applies to any changes in Hypothesis's behaviour, regardless\nof their nature. A good rule of thumb is that if it touches a file in\nsrc then it counts.\n\n1. The code should be clear in its intent and behaviour.\n2. Behaviour changes should come with appropriate tests to demonstrate\n   the new behaviour.\n3. Hypothesis must never be *flaky*. Flakiness here is\n   defined as anything where a test fails and this does not indicate\n   a bug in Hypothesis or in the way the user wrote the code or the test.\n4. The changelog (in ``RELEASE.rst``) should bump the minor or patch version\n   (see guides/documentation.rst for details), accurately describe the\n   changes, and shouldn't refer to internal-only APIs.  For complicated\n   markup, consider building the docs and manually checking the changelog\n   for formatting errors that didn't result in a compilation error.\n\n~~~~~~~~~~~\nAPI Changes\n~~~~~~~~~~~\n\nPublic API changes require the most careful scrutiny of all reviews,\nbecause they are the ones we are stuck with for the longest: Hypothesis\nfollows semantic versioning, and we don't release new major versions\nvery often.\n\nPublic API changes must satisfy the following:\n\n1. All public API changes must be well documented. If it's not documented,\n   it doesn't count as public API!\n2. Changes must be backwards compatible. Where this is not possible, they\n   must first introduce a deprecation warning, then once the major version\n   is bumped the deprecation warning and the functionality may be removed.\n3. If an API is deprecated, the deprecation warning must make it clear\n   how the user should modify their code to adapt to this change (\n   possibly by referring to documentation).\n   If the required code change could be automated, the deprecation should have either\n   `a codemod to fix it <https://github.com/HypothesisWorks/hypothesis/issues/2705>`__\n   or a tracking issue to write one (see \"asking for more work\" below).\n4. If it is likely that we will want to make backwards incompatible changes\n   to an API later, to whatever extent possible these should be made immediately\n   when it is introduced instead.\n5. APIs should give clear and helpful error messages in response to invalid inputs.\n   In particular error messages should always display\n   the value that triggered the error, and ideally be specific about the\n   relevant feature of it that caused this failure (e.g. the type).\n6. Incorrect usage should never \"fail silently\" - when a user accidentally\n   misuses an API this should result in an explicit error.\n7. Functionality should be limited to that which is easy to support in the\n   long-term. In particular functionality which is very tied to the\n   current Hypothesis internals should be avoided.\n8. `DRMacIver <https://github.com/DRMacIver>`_ or\n   `Zac-HD <https://github.com/Zac-HD>`_ must approve the changes\n   though other maintainers are welcome and likely to chip in to review as\n   well.\n9. We have a separate guide for `house API style <api-style.rst>`_ which should\n   be followed.\n\n~~~~~~~~~\nBug Fixes\n~~~~~~~~~\n\n1. All bug fixes must come with a test that demonstrates the bug on master and\n   which is fixed in this branch. An exception *may* be made here if the submitter\n   can convincingly argue that testing this would be prohibitively difficult.\n2. Where possible, a fix that makes it impossible for similar bugs to occur is\n   better.\n3. Where possible, a test that will catch both this bug and a more general class\n   of bug that contains it is better.\n\n~~~~~~~~~~~~~~~~\nSettings Changes\n~~~~~~~~~~~~~~~~\n\nNote: This section currently only applies to the Python version.\n\nIt is tempting to use the Hypothesis settings object as a dumping ground for\nanything and everything that you can think of to control Hypothesis. This\nrapidly gets confusing for users and should be carefully avoided.\n\nNew settings should:\n\n1. Be something that the user can meaningfully have an opinion on. Many of the\n   settings that have been added to Hypothesis are just cases where Hypothesis\n   is abdicating responsibility to do the right thing to the user.\n2. Make sense without reference to Hypothesis internals.\n3. Correspond to behaviour which can meaningfully differ between tests - either\n   between two different tests or between two different runs of the same test\n   (e.g. one use case is the profile system, where you might want to run Hypothesis\n   differently in CI and development). If you would never expect a test suite to\n   have more than one value for a setting across any of its runs, it should be\n   some sort of global configuration, not a setting.\n\nWhen deprecating a setting for later removal, we prefer to change the default\nvalue of the setting to a private singleton (``not_set``), and implement the\nfuture behaviour immediately.  Passing any other value triggers a deprecation\nwarning, but is otherwise a no-op (i.e. we still use the future behaviour).\n\nFor settings where this would be especially disruptive, we have also prefixed\nthat deprecation process with a process where we emit a warning, add a special\nvalue that can be passed to opt-in to the future behaviour, and then in the\nfollowing major release we deprecate *that*, make it an no-op, and make it an\nerror to pass any other value.\n\n~~~~~~~~~~~~~~\nEngine Changes\n~~~~~~~~~~~~~~\n\nEngine changes are anything that change a \"fundamental\" of how Hypothesis\nworks. A good rule of thumb is that an engine change is anything that touches\na file in ``hypothesis.internal.conjecture`` (Python version).\n\nAll such changes should:\n\n1. Be approved (or authored) by DRMacIver or Zac-HD.\n2. Be approved (or authored) by someone who *isn't* DRMacIver (a major problem\n   with this section of the code is that there is too much that only DRMacIver\n   understands properly and we want to fix this).\n3. If appropriate, come with a test in test_discovery_ability.py showing new\n   examples that were previously hard to discover.\n4. If appropriate, come with a test in test_shrink_quality.py showing how they\n   improve the shrinker.\n\n~~~~~~~~~~~~~~~~~~~~~~\nNon-Blocking Questions\n~~~~~~~~~~~~~~~~~~~~~~\n\nThese questions should *not* block merge, but may result in additional\nissues or changes being opened, either by the original author or by the\nreviewer.\n\n1. Is this change well covered by the review items and is there\n   anything that could usefully be added to the guidelines to improve\n   that?\n2. Were any of the review items confusing or annoying when reviewing this\n   change? Could they be improved?\n3. Are there any more general changes suggested by this, and do they have\n   appropriate issues and/or pull requests associated with them?\n\n~~~~~~~~~~~~~~~~~~~~\nAsking for more work\n~~~~~~~~~~~~~~~~~~~~\n\nReviewers should in general not request changes that expand the scope of\na pull request beyond its original intended goal. The primary design\nphilosophy of our work-flow is that making correct changes should be cheap,\nand scope creep on pull requests works against that - If you can't touch\nsomething without having to touch a number of related areas as well,\nchanging things becomes expensive again.\n\nThis of course doesn't cover things where additional work is required to\nensure the change is actually correct - for example, if you change public\nfunctionality you certainly need to update its documentation. That isn't\nscope creep, that's just the normal scope.\n\nIf a pull request suggests additional work then between the reviewer and the\nauthor people should ensure that there are relevant tracking issues for that\nwork (as per question 3 in \"Non-Blocking Questions\" above), but there is no\nobligation for either of them to actually do any of the work on those issues.\nBy default it is the reviewer who should open these issues, but the author\nis welcome to as well.\n\nThat being said, it's legitimate to expand the scope of a pull request in\nsome cases. For example:\n\n* If not doing so is likely to cause problems later. For example, because\n  of backwards compatibility requirements it might make sense to ask for some\n  additional functionality that is likely to be added later so that the arguments\n  to a function are in a more sensible order.\n* Cases where the added functionality feels extremely incomplete in some\n  way without an additional change. The litmus test here should be \"this will\n  almost never be useful because...\". This is still fairly subjective, but at\n  least one good use case where the change is a clear improvement over the status\n  quo is enough to indicate that this doesn't apply.\n\nIf it's unclear, the reviewer should feel free to suggest additional work\n(but if the author is someone new, please make sure that it's clear that this\nis a suggestion and not a requirement!), but the author of the pull request should\nfeel equally free to decline the suggestion.\n"
  },
  {
    "path": "guides/strategies-that-shrink.rst",
    "content": "===================================\nDesigning strategies to shrink well\n===================================\n\nReducing test cases to a minimal example is a great feature of Hypothesis,\nthe implementation of which depends on both the shrinking engine and the\nstructure of the strategy (or combination of strategies) which created the\nexample to reduce.\n\nThis document is organised into three parts:\n\n1. How to tell if you need to think about shrinking (you probably don't!)\n2. Designing for shrinking 'above' the Hypothesis public API\n3. Implementation tricks used in our internals, for interested contributors\n\nIt is written for people implementing complex third-party strategies (such\nas `hypothesis-networkx <https://pypi.org/project/hypothesis-networkx/>`__),\ncurrent or potential contributors to Hypothesis itself, and anyone interested\nin how this works under the hood.\n\n\n------------------------------------\nDo you need to design for shrinking?\n------------------------------------\nYou should only attempt to tune custom strategies for better shrinking\nbehaviour if more time would otherwise be spent reducing examples by hand\nor debugging more complex examples.  It *may* be worthwhile if:\n\n- Your custom strategy will be used by many people, so that spending\n  the same effort tuning the strategy has much larger benefits, or\n- You have personally spent time debugging failures which better example\n  shrinking could have avoided and think this might happen again.\n\nIf neither of these apply to you, relax!  Hypothesis' test-case reduction\nis among the best in the world, and our built-in strategies are carefully\ndesigned to work well with it as discussed below.\n\n\n------------------------------------\nShrinking for third-party strategies\n------------------------------------\n\nThat is, strategies built out of other strategies until you get down to\nHypothesis' public API.  These often but not always use ``@composite``.\n\n\nComposition of shrinking\n~~~~~~~~~~~~~~~~~~~~~~~~\nThe first and most important rule is that Hypothesis shrinks from the\n'bottom up'.  If any component of your strategy is replaced with a simpler\nexample, the end result should also become simpler.  We usually try to define\n\"simpler\" here to match a reasonable intuition about the strategy, and avoid\nweird edge cases when it's combined with another strategy or predicate.\n\n`Issue #1076 <https://github.com/HypothesisWorks/hypothesis/issues/1076>`_,\nwhere magnitude constraints were added to the ``complex_numbers`` strategy,\nmakes a nice case study.  We wanted to continue shrinking the real and\nimaginary parts like ``builds(complex, floats(), floats())``.\n\nIn a worst-case scenario, the performance of filtering could be arbitrarily\nbad, while a 'generate and scale' approach would mean that simple inputs\ncould lead to irrational outputs.  Instead, we choose an imaginary part\nbetween +/- max_magnitude, then calculate the resulting bounds on the real\npart and draw it from a strategy that will always be valid.  This ensures\nthat the imaginary part shrinks to zero first, as we think real-valued\ncomplex numbers are simpler than imaginary-valued complex numbers.\n\n\nLet generation be lucky\n~~~~~~~~~~~~~~~~~~~~~~~\nSometimes, it's worth searching for a particularly nasty value to try.\nThis trick should be used sparingly, and always behind a branch that the\nshrinker can decide not to take such as ``if draw(booleans()):``, but might\noccasionally worth trying.  Measure the results before you keep it!\n\n`Issue #69 <https://github.com/HypothesisWorks/hypothesis/issues/69>`_ provides\na nice case study: when generating tz-aware datetimes, we would like to generate\ninstants that are skipped or repeated due to a daylight-savings transition more\noften than by chance.  Of course, there may or may not be any such moments\nallowed by the bounds and tz strategy!\n\nEliding much of the detail, a key part is to find such a moment between two\nendpoints, when we can only check whether one or more exists.  The traditional\napproach would be to use a binary search, but this would be relatively expensive\nto shrink as we would pay the log-n cost on every attempted shrink.\n\nInstead of choosing the midpoint, we draw a *random* point between our known\nendpoints, and repeat this until we find a satisfactory moment.  This allows\nthe shrinker to delete all the intermediate draws - and appear lucky enough\nto find the moment we were looking for on the first guess!\n\n\nKeep things local\n~~~~~~~~~~~~~~~~~\nHypothesis' shrinking engine sees every example as a labelled tree of choices,\nwith possible reductions represented as operations on the tree.  An attempted\nshrink succeeds if the new tree can be converted into an example, and the\nresulting example triggers the same bug in the test function.\n\nThe most common way we see users breaking data locality is by drawing a size,\nthen drawing a collection of that size.  This is tempting because it's simple\nand it _works_, but it's often much slower than the alternatives.\n\n.. code:: python\n\n    # Both of these strategies can generate exactly the same kind of examples,\n    # but the second has better performance as well as style.\n    integers(0, 10).flatmap(lambda n: st.lists(..., min_size=n, max_size=n))\n    st.lists(..., min_size=1, max_size=10)\n\nAnother easy way to keep things local is to ensure that any ``.filter(...)``\nor ``assume(...)`` calls you use are as close as possible to the relevant part\nof the strategy.  That way, Hypothesis can retry just the part that failed\ninstead of the entire strategy, which might be much slower.\n\nFor efficient shrinking, local operations on the tree should correspond with\nvalid (and preferably local) shrinks to the final example.  For example:\n\n.. code:: python\n\n    # This form of loop is hard to shrink, because we'd have to reduce `n` and\n    # delete something in the loop simultaneously.  It's equivalent to the\n    # `.flatmap` example above.  We _do_ shrink this, but much more slowly.\n    n = draw(integers(0, 10))\n    for _ in range(n):\n        ...\n        draw(...)\n        ...\n\n    # In this form, the shrinker can see a repeated structure of labels\n    # and delete one loop iteration without touching anything else.\n    # We use a variant of this trick to generate collections internally!\n    while draw(integers(0, x)) > threshold:\n        ...\n        draw(...)\n        ...\n\nSimilarly, it's better to draw all the attributes or inputs you need for an\nobject at the same time, again so they can be modified or deleted together.\n\nThe exact behaviour of the shrinking is a topic of active research and\ndevelopment, so if you are interested in the details we recommend reading\nthe `internals guide <https://github.com/HypothesisWorks/hypothesis/blob/master/guides/internals.rst>`_\nand the well-commented source code in\n``hypothesis.internal.conjecture`` as well as David's ECOOP 2020 paper\n`Test-Case Reduction via Test-Case Generation: Insights From the Hypothesis Reducer\n<https://2020.ecoop.org/details/ecoop-2020-papers/13/Test-Case-Reduction-via-Test-Case-Generation-Insights-From-the-Hypothesis-Reducer>`__.\n\n\n-------------------------------------\nShrinking in the Hypothesis internals\n-------------------------------------\nThe last section is for current or prospective Hypothesis contributors only.\n\nThese tricks rely on implementation details that are not available to\nthird-party libraries or users, **and can change in any patch release**.\nOccasionally they are also indispensable to get good performance in underlying\nprimitives, so please contact us if the public API is not enough and we may\nbe able to work something out.\n\n\nWhat do internals get you?\n~~~~~~~~~~~~~~~~~~~~~~~~~~\nUsing the low-level, internal APIs complements, rather than changing, the\nprinciples above.  The bytestream-level view has some important advantages:\n\nBecause we operate at the level of bits, the relationship between a value and\nthe corresponding buffer is much more obvious.  If we're careful, that means\nwe can calculate the value we want and then write the corresponding buffer\nto recreate it when the test case is shrunk or replayed.\n\nA small step up from bits, we can also see the spans that indicate a subset\nof the buffer to consider for various transformations such as transposition\nor deletion.\n\nSometimes these features are the only way to maintain acceptable performance\nin very rare or even pathological cases - consider shrinking a complex number\nwith a single allowed magnitude - but it's almost certain that someone will\nneed the core strategies to do just that.\nHowever, using low-level APIs also comes at a cost - they are verbose and\ngenerally more difficult to use, and can violate key invariants of the engine\nif misused.\n\nInternally, our strategies mostly use the public API or something that looks\na lot like ``@composite``, so it's fairly easy to follow along.  There are\njust a few tricks enabled by those low-level advantages that we wanted to\nname and document, so we can recognise them discuss them and invent more...\n\n\nMake your own luck\n~~~~~~~~~~~~~~~~~~\nThis is the simplest trick that uses our ability to write choices to the\nbuffer.  We use it for ``sampled_from(...).filter(...)``, after trying an\ninitial draw with the usual rejection sampling technique, and added the\n``SearchStrategy.do_filtered_draw`` method so other strategies can opt-in\nas we design similar tricks for their structure.\n\nIt was originally designed for stateful testing, where \"lucky generation\"\nmight be inefficient if there are many rules but only a few allowed by their\npreconditions.  Here's how it works for stateful testing:\n\n1. Draw an index into the unfiltered list of rules.  Return the corresponding\n   rule if it's allowed - we got lucky!  (or someone set us up...)\n2. Create a list of allowed rules, and choose one from that shortlist instead.\n3. Find the index of the chosen rule *in the unfiltered list*, and write that\n   index to the buffer.  Finally, return the chosen rule.\n\nWhen the shrinker tries to delete the first two draws, the resulting buffer\nwill lead to the same rule being chosen at step *one* instead.  We've made\nour own luck!\n\nThis trick is especially useful when we want to avoid rejection sampling\n(the ``.filter`` method, ``assume``) for performance reasons, but also\nneed to give the shrinker the same low-level representation for each instance\nof a repeated choice.\n\n\nFlags \"shrink open\"\n~~~~~~~~~~~~~~~~~~~\nAn important insight from `Swarm Testing (PDF) <https://www.cs.utah.edu/~regehr/papers/swarm12.pdf>`__\nis that randomly disabling some features can actually reduce the expected time\nbefore finding a bug, because some bugs may be suppressed by otherwise common\nfeatures or attributes of the data.\n\nAs discussed on  `issue #1401 <https://github.com/HypothesisWorks/hypothesis/issues/1401>`__,\nthere are a few points to keep in mind when implementing shrinkable swarm testing:\n\n- You need swarm flags to \"shrink open\" so that once the shrinker has run to\n  completion, all flags are enabled. e.g. you could do this by generating a\n  set of banned flags.\n- You need to use rejection sampling rather than anything more clever, or at\n  least look like it to the shrinker.  (see e.g. *Make your own luck*, above)\n\nTaking Unicode as an example, we'd like to use our knowledge of Unicode\ncategories to generate more complex examples, but shrink the generated string\nwithout reference to categories.  While we haven't actually implemented this\nyet - it's pretty hairy - the simple version of the idea goes like this:\n\n1. Generate a set of banned categories.\n2. Use ``characters().filter(category_is_not_banned)``\n\nWhen shrinking, we start by removing categories from the banned set, after\nwhich characters in the string can be reduced as usual.  In a serious version,\nthe make-your-own-luck approach would be essential to make the filter\nreasonably efficient, but that's not a problem internally.\n\nIn more complicated structures, it would be nice to generate the flags on first\nuse rather than up front before we know if we need them.  The trick there is\nto write each flag to the buffer every time we check it, in such a way that if\nwe delete the first use the second turns into an initialisation.\n\n\nExplicit example boundaries\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThis is almost always handled implicitly, e.g. by ``cu.many``, but *sometimes*\nit can be useful to explicitly insert boundaries around draws that should be\ndeleted simultaneously using ``data.start_span``.  This is used to group\nthe value and sign of floating-point numbers, for example, which we split up\nin order to provide a more natural shrinking order.\n\nExplicit example management can also be useful to delineate variably-sized\ndraws, such as our internal helper ``cu.biased_coin``, which makes eliminating\ndead bytes much cheaper.  Finally, labelling otherwise indistinguishable draws\nmeans the shrinker can attempt to swap only the like values.\n"
  },
  {
    "path": "guides/testing-hypothesis.rst",
    "content": "==================\nTesting Hypothesis\n==================\n\nNote: This guide is currently entirely specific to the Python version of\nHypothesis.\n\nThis is a guide to the process of testing Hypothesis itself, both how to\nrun its tests and how to write new ones.\n\n--------------------------\nGeneral Testing Philosophy\n--------------------------\n\nThe test suite for Hypothesis is unusually powerful - as you might hope! -\nbut the secret is actually more about attitude than technology.\n\nThe key is that we treat any bug in Hypothesis as a bug in our test suite\ntoo - and think about the kinds of bugs that might not be caught, then write\ntests that would catch them.\n\nWe also use a variety of tools to check our code automatically, including\nformatting, import order, linting, and typing our API with Mypy.\nAll of this is checked in CI - which means that once the build is\ngreen, humans can all focus on meaningful review rather than nitpicking\noperator spacing.\n\nSimilarly, we require all code to have tests with 100% branch coverage - as\na starting point, not the final goal.\n\n- Requiring full coverage can't guarantee that we've written all the tests\n  worth writing (for example, maybe we left off a useful assertion about the\n  result), but less than full coverage guarantees that there's some code we're\n  not testing at all.\n- Tests beyond full coverage generally aim to demonstrate that a particular\n  feature works, or that some subtle failure case is not present - often\n  because when it was found and fixed, someone wrote a test to make sure it\n  couldn't come back!\n\nThe ``hypothesis-python/tests/`` directory has some notes in the README file on where various\nkinds of tests can be found or added.  Go there for the practical stuff, or\njust ask one of the maintainers for help on a pull request!\n\nFurther reading: How `SQLite is tested <https://sqlite.org/testing.html>`_,\n`how the Space Shuttle was tested <https://www.fastcompany.com/28121/they-write-right-stuff>`_,\n`how to misuse code coverage <http://www.exampler.com/testing-com/writings/coverage.pdf>`_\n(for inspiration, *not* implementation).\nDan Luu writes about `fuzz testing <https://danluu.com/testing/>`_ and\n`broken processes <https://danluu.com/wat/>`_, among other things.\n\n-------------\nRunning Tests\n-------------\n\nTests are run via ``build.sh``. See ``CONTRIBUTING.rst`` for more details.\n"
  },
  {
    "path": "hypothesis-python/LICENSE.txt",
    "content": "Copyright (c) 2013, David R. MacIver\n\nAll code in this repository except where explicitly noted otherwise is released\nunder the Mozilla Public License v 2.0. You can obtain a copy at https://mozilla.org/MPL/2.0/.\n\nSome code in this repository comes from other projects. Where applicable, the\noriginal copyright and license are noted and any modifications made are released\ndual licensed with the original license.\n\nMozilla Public License Version 2.0\n==================================\n\n1. Definitions\n--------------\n\n1.1. \"Contributor\"\n    means each individual or legal entity that creates, contributes to\n    the creation of, or owns Covered Software.\n\n1.2. \"Contributor Version\"\n    means the combination of the Contributions of others (if any) used\n    by a Contributor and that particular Contributor's Contribution.\n\n1.3. \"Contribution\"\n    means Covered Software of a particular Contributor.\n\n1.4. \"Covered Software\"\n    means Source Code Form to which the initial Contributor has attached\n    the notice in Exhibit A, the Executable Form of such Source Code\n    Form, and Modifications of such Source Code Form, in each case\n    including portions thereof.\n\n1.5. \"Incompatible With Secondary Licenses\"\n    means\n\n    (a) that the initial Contributor has attached the notice described\n        in Exhibit B to the Covered Software; or\n\n    (b) that the Covered Software was made available under the terms of\n        version 1.1 or earlier of the License, but not also under the\n        terms of a Secondary License.\n\n1.6. \"Executable Form\"\n    means any form of the work other than Source Code Form.\n\n1.7. \"Larger Work\"\n    means a work that combines Covered Software with other material, in\n    a separate file or files, that is not Covered Software.\n\n1.8. \"License\"\n    means this document.\n\n1.9. \"Licensable\"\n    means having the right to grant, to the maximum extent possible,\n    whether at the time of the initial grant or subsequently, any and\n    all of the rights conveyed by this License.\n\n1.10. \"Modifications\"\n    means any of the following:\n\n    (a) any file in Source Code Form that results from an addition to,\n        deletion from, or modification of the contents of Covered\n        Software; or\n\n    (b) any new file in Source Code Form that contains any Covered\n        Software.\n\n1.11. \"Patent Claims\" of a Contributor\n    means any patent claim(s), including without limitation, method,\n    process, and apparatus claims, in any patent Licensable by such\n    Contributor that would be infringed, but for the grant of the\n    License, by the making, using, selling, offering for sale, having\n    made, import, or transfer of either its Contributions or its\n    Contributor Version.\n\n1.12. \"Secondary License\"\n    means either the GNU General Public License, Version 2.0, the GNU\n    Lesser General Public License, Version 2.1, the GNU Affero General\n    Public License, Version 3.0, or any later versions of those\n    licenses.\n\n1.13. \"Source Code Form\"\n    means the form of the work preferred for making modifications.\n\n1.14. \"You\" (or \"Your\")\n    means an individual or a legal entity exercising rights under this\n    License. For legal entities, \"You\" includes any entity that\n    controls, is controlled by, or is under common control with You. For\n    purposes of this definition, \"control\" means (a) the power, direct\n    or indirect, to cause the direction or management of such entity,\n    whether by contract or otherwise, or (b) ownership of more than\n    fifty percent (50%) of the outstanding shares or beneficial\n    ownership of such entity.\n\n2. License Grants and Conditions\n--------------------------------\n\n2.1. Grants\n\nEach Contributor hereby grants You a world-wide, royalty-free,\nnon-exclusive license:\n\n(a) under intellectual property rights (other than patent or trademark)\n    Licensable by such Contributor to use, reproduce, make available,\n    modify, display, perform, distribute, and otherwise exploit its\n    Contributions, either on an unmodified basis, with Modifications, or\n    as part of a Larger Work; and\n\n(b) under Patent Claims of such Contributor to make, use, sell, offer\n    for sale, have made, import, and otherwise transfer either its\n    Contributions or its Contributor Version.\n\n2.2. Effective Date\n\nThe licenses granted in Section 2.1 with respect to any Contribution\nbecome effective for each Contribution on the date the Contributor first\ndistributes such Contribution.\n\n2.3. Limitations on Grant Scope\n\nThe licenses granted in this Section 2 are the only rights granted under\nthis License. No additional rights or licenses will be implied from the\ndistribution or licensing of Covered Software under this License.\nNotwithstanding Section 2.1(b) above, no patent license is granted by a\nContributor:\n\n(a) for any code that a Contributor has removed from Covered Software;\n    or\n\n(b) for infringements caused by: (i) Your and any other third party's\n    modifications of Covered Software, or (ii) the combination of its\n    Contributions with other software (except as part of its Contributor\n    Version); or\n\n(c) under Patent Claims infringed by Covered Software in the absence of\n    its Contributions.\n\nThis License does not grant any rights in the trademarks, service marks,\nor logos of any Contributor (except as may be necessary to comply with\nthe notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\nNo Contributor makes additional grants as a result of Your choice to\ndistribute the Covered Software under a subsequent version of this\nLicense (see Section 10.2) or under the terms of a Secondary License (if\npermitted under the terms of Section 3.3).\n\n2.5. Representation\n\nEach Contributor represents that the Contributor believes its\nContributions are its original creation(s) or it has sufficient rights\nto grant the rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\nThis License is not intended to limit any rights You have under\napplicable copyright doctrines of fair use, fair dealing, or other\nequivalents.\n\n2.7. Conditions\n\nSections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted\nin Section 2.1.\n\n3. Responsibilities\n-------------------\n\n3.1. Distribution of Source Form\n\nAll distribution of Covered Software in Source Code Form, including any\nModifications that You create or to which You contribute, must be under\nthe terms of this License. You must inform recipients that the Source\nCode Form of the Covered Software is governed by the terms of this\nLicense, and how they can obtain a copy of this License. You may not\nattempt to alter or restrict the recipients' rights in the Source Code\nForm.\n\n3.2. Distribution of Executable Form\n\nIf You distribute Covered Software in Executable Form then:\n\n(a) such Covered Software must also be made available in Source Code\n    Form, as described in Section 3.1, and You must inform recipients of\n    the Executable Form how they can obtain a copy of such Source Code\n    Form by reasonable means in a timely manner, at a charge no more\n    than the cost of distribution to the recipient; and\n\n(b) You may distribute such Executable Form under the terms of this\n    License, or sublicense it under different terms, provided that the\n    license for the Executable Form does not attempt to limit or alter\n    the recipients' rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\nYou may create and distribute a Larger Work under terms of Your choice,\nprovided that You also comply with the requirements of this License for\nthe Covered Software. If the Larger Work is a combination of Covered\nSoftware with a work governed by one or more Secondary Licenses, and the\nCovered Software is not Incompatible With Secondary Licenses, this\nLicense permits You to additionally distribute such Covered Software\nunder the terms of such Secondary License(s), so that the recipient of\nthe Larger Work may, at their option, further distribute the Covered\nSoftware under the terms of either this License or such Secondary\nLicense(s).\n\n3.4. Notices\n\nYou may not remove or alter the substance of any license notices\n(including copyright notices, patent notices, disclaimers of warranty,\nor limitations of liability) contained within the Source Code Form of\nthe Covered Software, except that You may alter any license notices to\nthe extent required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\nYou may choose to offer, and to charge a fee for, warranty, support,\nindemnity or liability obligations to one or more recipients of Covered\nSoftware. However, You may do so only on Your own behalf, and not on\nbehalf of any Contributor. You must make it absolutely clear that any\nsuch warranty, support, indemnity, or liability obligation is offered by\nYou alone, and You hereby agree to indemnify every Contributor for any\nliability incurred by such Contributor as a result of warranty, support,\nindemnity or liability terms You offer. You may include additional\ndisclaimers of warranty and limitations of liability specific to any\njurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n---------------------------------------------------\n\nIf it is impossible for You to comply with any of the terms of this\nLicense with respect to some or all of the Covered Software due to\nstatute, judicial order, or regulation then You must: (a) comply with\nthe terms of this License to the maximum extent possible; and (b)\ndescribe the limitations and the code they affect. Such description must\nbe placed in a text file included with all distributions of the Covered\nSoftware under this License. Except to the extent prohibited by statute\nor regulation, such description must be sufficiently detailed for a\nrecipient of ordinary skill to be able to understand it.\n\n5. Termination\n--------------\n\n5.1. The rights granted under this License will terminate automatically\nif You fail to comply with any of its terms. However, if You become\ncompliant, then the rights granted under this License from a particular\nContributor are reinstated (a) provisionally, unless and until such\nContributor explicitly and finally terminates Your grants, and (b) on an\nongoing basis, if such Contributor fails to notify You of the\nnon-compliance by some reasonable means prior to 60 days after You have\ncome back into compliance. Moreover, Your grants from a particular\nContributor are reinstated on an ongoing basis if such Contributor\nnotifies You of the non-compliance by some reasonable means, this is the\nfirst time You have received notice of non-compliance with this License\nfrom such Contributor, and You become compliant prior to 30 days after\nYour receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\ninfringement claim (excluding declaratory judgment actions,\ncounter-claims, and cross-claims) alleging that a Contributor Version\ndirectly or indirectly infringes any patent, then the rights granted to\nYou by any and all Contributors for the Covered Software under Section\n2.1 of this License shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all\nend user license agreements (excluding distributors and resellers) which\nhave been validly granted by You or Your distributors under this License\nprior to termination shall survive termination.\n\n************************************************************************\n*                                                                      *\n*  6. Disclaimer of Warranty                                           *\n*  -------------------------                                           *\n*                                                                      *\n*  Covered Software is provided under this License on an \"as is\"       *\n*  basis, without warranty of any kind, either expressed, implied, or  *\n*  statutory, including, without limitation, warranties that the       *\n*  Covered Software is free of defects, merchantable, fit for a        *\n*  particular purpose or non-infringing. The entire risk as to the     *\n*  quality and performance of the Covered Software is with You.        *\n*  Should any Covered Software prove defective in any respect, You     *\n*  (not any Contributor) assume the cost of any necessary servicing,   *\n*  repair, or correction. This disclaimer of warranty constitutes an   *\n*  essential part of this License. No use of any Covered Software is   *\n*  authorized under this License except under this disclaimer.         *\n*                                                                      *\n************************************************************************\n\n************************************************************************\n*                                                                      *\n*  7. Limitation of Liability                                          *\n*  --------------------------                                          *\n*                                                                      *\n*  Under no circumstances and under no legal theory, whether tort      *\n*  (including negligence), contract, or otherwise, shall any           *\n*  Contributor, or anyone who distributes Covered Software as          *\n*  permitted above, be liable to You for any direct, indirect,         *\n*  special, incidental, or consequential damages of any character      *\n*  including, without limitation, damages for lost profits, loss of    *\n*  goodwill, work stoppage, computer failure or malfunction, or any    *\n*  and all other commercial damages or losses, even if such party      *\n*  shall have been informed of the possibility of such damages. This   *\n*  limitation of liability shall not apply to liability for death or   *\n*  personal injury resulting from such party's negligence to the       *\n*  extent applicable law prohibits such limitation. Some               *\n*  jurisdictions do not allow the exclusion or limitation of           *\n*  incidental or consequential damages, so this exclusion and          *\n*  limitation may not apply to You.                                    *\n*                                                                      *\n************************************************************************\n\n8. Litigation\n-------------\n\nAny litigation relating to this License may be brought only in the\ncourts of a jurisdiction where the defendant maintains its principal\nplace of business and such litigation shall be governed by laws of that\njurisdiction, without reference to its conflict-of-law provisions.\nNothing in this Section shall prevent a party's ability to bring\ncross-claims or counter-claims.\n\n9. Miscellaneous\n----------------\n\nThis License represents the complete agreement concerning the subject\nmatter hereof. If any provision of this License is held to be\nunenforceable, such provision shall be reformed only to the extent\nnecessary to make it enforceable. Any law or regulation which provides\nthat the language of a contract shall be construed against the drafter\nshall not be used to construe this License against a Contributor.\n\n10. Versions of the License\n---------------------------\n\n10.1. New Versions\n\nMozilla Foundation is the license steward. Except as provided in Section\n10.3, no one other than the license steward has the right to modify or\npublish new versions of this License. Each version will be given a\ndistinguishing version number.\n\n10.2. Effect of New Versions\n\nYou may distribute the Covered Software under the terms of the version\nof the License under which You originally received the Covered Software,\nor under the terms of any subsequent version published by the license\nsteward.\n\n10.3. Modified Versions\n\nIf you create software not governed by this License, and you want to\ncreate a new license for such software, you may create and use a\nmodified version of this License if you rename the license and remove\nany references to the name of the license steward (except to note that\nsuch modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary\nLicenses\n\nIf You choose to distribute Source Code Form that is Incompatible With\nSecondary Licenses under the terms of this version of the License, the\nnotice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n-------------------------------------------\n\n  This Source Code Form is subject to the terms of the Mozilla Public\n  License, v. 2.0. If a copy of the MPL was not distributed with this\n  file, You can obtain one at https://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular\nfile, then You may include the notice in a location (such as a LICENSE\nfile in a relevant directory) where a recipient would be likely to look\nfor such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - \"Incompatible With Secondary Licenses\" Notice\n---------------------------------------------------------\n\n  This Source Code Form is \"Incompatible With Secondary Licenses\", as\n  defined by the Mozilla Public License, v. 2.0.\n"
  },
  {
    "path": "hypothesis-python/README.md",
    "content": "The Hypothesis python readme has moved to [the main readme](../README.md)!\n"
  },
  {
    "path": "hypothesis-python/RELEASE-sample.rst",
    "content": "RELEASE_TYPE: patch\n\nThis patch improves import-detection in :doc:`the Ghostwriter <ghostwriter>`\n(:issue:`3884`), particularly for :func:`~hypothesis.strategies.from_type`\nand strategies from ``hypothesis.extra.*``.\n\nThanks to <contributor's name or handle> for this <contribution/fix/feature>!\n\n---\n\nIn the example above, \"patch\" on the first line should be replaced by\n\"minor\" if changes are visible in the public API, or \"major\" if there are\nbreaking changes.  Note that only maintainers should ever make a major\nrelease.\n\nThe remaining lines are the actual changelog text for this release,\nwhich should:\n\n- concisely describe what changed _in the public API_, and why.\n  Internal-only changes can be documented as e.g. \"This release improves\n  an internal invariant.\" (the complete changelog for version 6.99.11)\n- use ``double backticks`` for verbatim code,\n- use Sphinx cross-references to any functions or classes mentioned:\n  - :pypi:`package` for links to external packages.\n  - :func:`package.function` for link to functions, where the link text will\n    be ``package.function``, or :func:`~package.function` to show ``function``.\n  - :class:`package.class` for link to classes (abbreviated as above).\n  - :issue:`issue-number` for referencing issues.\n  - Similarly, :pull:`pr-number` can be used for PRs, but it's usually\n    preferred to refer to version numbers with :v:`6.98.9`,\n    as they are meaningful to end users.\n  - :doc:`link text <chapter#anchor>` for documentation references.\n  - `link text <https://hypothesis.readthedocs.io/en/latest/chapter.html#anchor>`__\n    is the same link, for general web addresses.\n- finish with a note of thanks from the maintainers. If this is your first\n  contribution, don't forget to add yourself to AUTHORS.rst!\n\nAfter the PR is merged, the contents of this file (except the first line)\nare automatically added to ``docs/changelog.rst``. More examples can be found\nin that file.\n"
  },
  {
    "path": "hypothesis-python/benchmark/README.md",
    "content": "This directory contains plotting code for our shrinker benchmarking. The code for collecting the data is in `conftest.py`. This directory handles plotting the results.\n\nThe plotting script (but not collecting benchmark data) requires additional dependencies: `pip install scipy vl-convert-python`.\n\nTo run a benchmark:\n\n- `pytest tests/ -n auto --hypothesis-benchmark-shrinks new --hypothesis-benchmark-output data.json` (starting on the newer version)\n- `pytest tests/ -n auto --hypothesis-benchmark-shrinks old --hypothesis-benchmark-output data.json` (after switching to the old version)\n  - Use the same `data.json` path, the benchmark will append data. You can append `-k ...` for both commands to subset the benchmark.\n- `python benchmark/graph.py data.json shrinking.png`\n\nThis hooks any `minimal()` calls any reports the number of shrinks. Default (and currently unchangeable) number of iterations is 5 per test.\n"
  },
  {
    "path": "hypothesis-python/benchmark/graph.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport json\nimport math\nimport statistics\nfrom pathlib import Path\n\nimport click\n\n\ndef plot_vega(vega_spec, data, *, to, parameters=None):\n    import vl_convert\n\n    parameters = parameters or {}\n\n    spec = json.loads(vega_spec.read_text())\n    spec[\"data\"].insert(0, {\"name\": \"source\", \"values\": data})\n    if \"signals\" not in spec:\n        spec[\"signals\"] = []\n\n    for key, value in parameters.items():\n        spec[\"signals\"].append({\"name\": key, \"value\": value})\n\n    with open(to, \"wb\") as f:\n        # default ppi is 72, which is somewhat blurry.\n        f.write(vl_convert.vega_to_png(spec, ppi=200))\n\n\ndef _mean_difference_ci(n1, n2, *, confidence):\n    from scipy import stats\n\n    var1 = statistics.variance(n1)\n    var2 = statistics.variance(n2)\n    df = len(n1) + len(n2) - 2\n    # this assumes equal variances between the populations of n1 and n2. This\n    # is not necessarily true (new might be more consistent than old), but it's\n    # good enough.\n    pooled_std = math.sqrt(((len(n1) - 1) * var1 + (len(n2) - 1) * var2) / df)\n    se = pooled_std * math.sqrt(1 / len(n1) + 1 / len(n2))\n    t_crit = stats.t.ppf((1 + confidence) / 2, df)\n    return t_crit * se\n\n\ndef _process_benchmark_data(data):\n    assert set(data) == {\"old\", \"new\"}\n    old_calls = data[\"old\"][\"calls\"]\n    new_calls = data[\"new\"][\"calls\"]\n    assert set(old_calls) == set(new_calls), set(old_calls).symmetric_difference(\n        set(new_calls)\n    )\n\n    graph_data = []\n\n    def _diff_times(old, new):\n        if old == 0 and new == 0:\n            return 0\n        if old == 0:\n            # there aren't any great options here, but 0 is more reasonable than inf.\n            return 0\n        v = (old - new) / old\n        if 0 < v < 1:\n            v = (1 / (1 - v)) - 1\n        return v\n\n    sums = {\"old\": 0, \"new\": 0}\n    for node_id in old_calls:\n        old = old_calls[node_id]\n        new = new_calls[node_id]\n        if (\n            set(old) | set(new) == {0}\n            or len(old) != len(new)\n            or len(old) == len(new) == 0\n        ):\n            print(f\"skipping {node_id}\")\n            continue\n\n        sums[\"old\"] += statistics.mean(old)\n        sums[\"new\"] += statistics.mean(new)\n        diffs = [n_old - n_new for n_old, n_new in zip(old, new, strict=True)]\n        diffs_times = [\n            _diff_times(n_old, n_new) for n_old, n_new in zip(old, new, strict=True)\n        ]\n        ci_shrink = (\n            _mean_difference_ci(old, new, confidence=0.95) if len(old) > 1 else 0\n        )\n\n        graph_data.append(\n            {\n                \"node_id\": node_id,\n                \"absolute\": statistics.mean(diffs),\n                \"absolute_ci_lower\": ci_shrink,\n                \"absolute_ci_upper\": ci_shrink,\n                \"nx\": statistics.mean(diffs_times),\n                \"nx_ci_lower\": 0,\n                \"nx_ci_upper\": 0,\n            }\n        )\n\n    graph_data = sorted(graph_data, key=lambda d: d[\"absolute\"])\n    return graph_data, sums\n\n\n@click.command()\n@click.argument(\"data\", type=click.Path(exists=True, path_type=Path))\n@click.argument(\"out\", type=click.Path(path_type=Path))\ndef plot(data, out):\n    data = json.loads(data.read_text())\n    data, sums = _process_benchmark_data(data)\n    plot_vega(\n        Path(__file__).parent / \"spec.json\",\n        data=data,\n        to=out,\n        parameters={\n            \"title\": \"Shrinking benchmark (calls)\",\n            \"sum_old\": sums[\"old\"],\n            \"sum_new\": sums[\"new\"],\n            \"absolute_axis_title\": (\"shrink call change (old - new, larger is good)\"),\n        },\n    )\n\n\nif __name__ == \"__main__\":\n    plot()\n"
  },
  {
    "path": "hypothesis-python/benchmark/spec.json",
    "content": "{\n    \"$schema\": \"https://vega.github.io/schema/vega/v5.json\",\n    \"width\": 1600,\n    \"height\": 800,\n    \"padding\": 5,\n    \"background\": \"#ffffff\",\n    \"title\": {\n      \"text\": {\"signal\": \"title\"},\n      \"fontSize\": 18\n    },\n    \"data\": [\n      {\n        \"name\": \"example\",\n        \"values\": [\n          {\"node_id\": \"test_node_1\", \"absolute\": 100, \"absolute_ci_lower\": 10, \"absolute_ci_upper\": 15, \"nx\": 0.5, \"nx_ci_lower\": 0.05, \"nx_ci_upper\": 0.07},\n          {\"node_id\": \"test_node_2\", \"absolute\": -50, \"absolute_ci_lower\": 5, \"absolute_ci_upper\": 8, \"nx\": -0.2, \"nx_ci_lower\": 0.02, \"nx_ci_upper\": 0.03},\n          {\"node_id\": \"test_node_3\", \"absolute\": 150, \"absolute_ci_lower\": 15, \"absolute_ci_upper\": 20, \"nx\": 0.6, \"nx_ci_lower\": 0.04, \"nx_ci_upper\": 0.09},\n          {\"node_id\": \"test_node_4\", \"absolute\": -120, \"absolute_ci_lower\": 10, \"absolute_ci_upper\": 12, \"nx\": -0.4, \"nx_ci_lower\": 0.03, \"nx_ci_upper\": 0.05},\n          {\"node_id\": \"test_node_5\", \"absolute\": 80, \"absolute_ci_lower\": 8, \"absolute_ci_upper\": 10, \"nx\": 0.3, \"nx_ci_lower\": 0.02, \"nx_ci_upper\": 0.04}\n        ]\n      },\n      {\n        \"name\": \"shrink_stats\",\n        \"source\": \"source\",\n        \"transform\": [\n          {\n            \"type\": \"aggregate\",\n            \"fields\": [\"absolute\", \"absolute\", \"nx\", \"nx\"],\n            \"ops\": [\"mean\", \"sum\", \"mean\", \"sum\"],\n            \"as\": [\"mean_shrink\", \"sum_shrink\", \"mean_nx\", \"sum_nx\"]\n          }\n        ]\n      },\n      {\n        \"name\": \"shrink_domain\",\n        \"source\": \"source\",\n        \"transform\": [\n          {\n            \"type\": \"aggregate\",\n            \"fields\": [\"absolute\", \"absolute\", \"absolute_ci_lower\", \"absolute_ci_upper\"],\n            \"ops\": [\"min\", \"max\", \"min\", \"max\"],\n            \"as\": [\"min_value\", \"max_value\", \"min_ci\", \"max_ci\"]\n          },\n          {\n            \"type\": \"formula\",\n            \"expr\": \"datum.min_value - datum.min_ci\",\n            \"as\": \"domain_min\"\n          },\n          {\n            \"type\": \"formula\",\n            \"expr\": \"datum.max_value + datum.max_ci\",\n            \"as\": \"domain_max\"\n          }\n        ]\n      },\n      {\n        \"name\": \"nx_domain\",\n        \"source\": \"source\",\n        \"transform\": [\n          {\n            \"type\": \"aggregate\",\n            \"fields\": [\"nx\", \"nx\", \"nx_ci_lower\", \"nx_ci_upper\"],\n            \"ops\": [\"min\", \"max\", \"min\", \"max\"],\n            \"as\": [\"min_value\", \"max_value\", \"min_ci\", \"max_ci\"]\n          },\n          {\n            \"type\": \"formula\",\n            \"expr\": \"datum.min_value - datum.min_ci\",\n            \"as\": \"domain_min\"\n          },\n          {\n            \"type\": \"formula\",\n            \"expr\": \"datum.max_value + datum.max_ci\",\n            \"as\": \"domain_max\"\n          }\n        ]\n      }\n    ],\n    \"scales\": [\n      {\n        \"name\": \"x\",\n        \"type\": \"band\",\n        \"domain\": {\"data\": \"source\", \"field\": \"node_id\"},\n        \"range\": \"width\",\n        \"padding\": 0.2\n      },\n      {\n        \"name\": \"y\",\n        \"type\": \"linear\",\n        \"domain\": {\"data\": \"shrink_domain\", \"fields\": [\"domain_min\", \"domain_max\"]},\n        \"range\": \"height\",\n        \"nice\": true,\n        \"zero\": true\n      },\n      {\n        \"name\": \"y2\",\n        \"type\": \"linear\",\n        \"domain\": {\"data\": \"nx_domain\", \"fields\": [\"domain_min\", \"domain_max\"]},\n        \"range\": \"height\",\n        \"nice\": true,\n        \"zero\": true\n      },\n      {\n        \"name\": \"color\",\n        \"type\": \"ordinal\",\n        \"domain\": [\"shrink call change\", \"n× change\"],\n        \"range\": [\"#4285F4\", \"#DB4437\"]\n      }\n    ],\n    \"axes\": [\n      {\n        \"orient\": \"bottom\",\n        \"scale\": \"x\",\n        \"labelAngle\": -90,\n        \"labelAlign\": \"right\",\n        \"labelBaseline\": \"middle\",\n        \"labelLimit\": 300\n      },\n      {\n        \"orient\": \"left\",\n        \"scale\": \"y\",\n        \"title\": {\"signal\": \"absolute_axis_title\"},\n        \"titleColor\": \"#4285F4\",\n        \"tickColor\": \"#4285F4\",\n        \"labelColor\": \"#4285F4\",\n        \"grid\": true,\n        \"gridColor\": \"#e0e0e0\",\n        \"gridOpacity\": 0.5,\n        \"titleFontSize\": 15,\n        \"tickCount\": 25\n      },\n      {\n        \"orient\": \"right\",\n        \"scale\": \"y2\",\n        \"title\": \"n× change\",\n        \"titleColor\": \"#DB4437\",\n        \"tickColor\": \"#DB4437\",\n        \"labelColor\": \"#DB4437\",\n        \"titleFontSize\": 15,\n        \"tickCount\": 25\n      }\n    ],\n    \"marks\": [\n      {\n        \"type\": \"rule\",\n        \"encode\": {\n          \"enter\": {\n            \"y\": {\"scale\": \"y\", \"value\": 0},\n            \"x\": {\"value\": 0},\n            \"x2\": {\"field\": {\"group\": \"width\"}},\n            \"stroke\": {\"value\": \"#4285F4\"},\n            \"strokeWidth\": {\"value\": 1},\n            \"strokeOpacity\": {\"value\": 0.7}\n          }\n        }\n      },\n      {\n        \"type\": \"rule\",\n        \"encode\": {\n          \"enter\": {\n            \"y\": {\"scale\": \"y2\", \"value\": 0},\n            \"x\": {\"value\": 0},\n            \"x2\": {\"field\": {\"group\": \"width\"}},\n            \"stroke\": {\"value\": \"#DB4437\"},\n            \"strokeWidth\": {\"value\": 1},\n            \"strokeOpacity\": {\"value\": 0.7}\n          }\n        }\n      },\n      {\n        \"type\": \"rule\",\n        \"from\": {\"data\": \"source\"},\n        \"encode\": {\n          \"enter\": {\n            \"x\": {\"scale\": \"x\", \"field\": \"node_id\", \"band\": 0.5},\n            \"y\": {\"scale\": \"y\", \"field\": \"absolute\", \"offset\": {\"signal\": \"-datum.absolute_ci_lower * height / (domain('y')[1] - domain('y')[0])\"}},\n            \"y2\": {\"scale\": \"y\", \"field\": \"absolute\", \"offset\": {\"signal\": \"datum.absolute_ci_upper * height / (domain('y')[1] - domain('y')[0])\"}},\n            \"stroke\": {\"value\": \"#4285F4\"},\n            \"strokeOpacity\": {\"value\": 0.5}\n          }\n        }\n      },\n      {\n        \"type\": \"rect\",\n        \"from\": {\"data\": \"source\"},\n        \"encode\": {\n          \"enter\": {\n            \"x\": {\"scale\": \"x\", \"field\": \"node_id\", \"band\": 0.5, \"offset\": -5},\n            \"width\": {\"value\": 10},\n            \"y\": {\"scale\": \"y\", \"field\": \"absolute\", \"offset\": {\"signal\": \"-datum.absolute_ci_lower * height / (domain('y')[1] - domain('y')[0])\"}},\n            \"height\": {\"value\": 1},\n            \"fill\": {\"value\": \"#4285F4\"},\n            \"fillOpacity\": {\"value\": 0.5}\n          }\n        }\n      },\n      {\n        \"type\": \"rect\",\n        \"from\": {\"data\": \"source\"},\n        \"encode\": {\n          \"enter\": {\n            \"x\": {\"scale\": \"x\", \"field\": \"node_id\", \"band\": 0.5, \"offset\": -5},\n            \"width\": {\"value\": 10},\n            \"y\": {\"scale\": \"y\", \"field\": \"absolute\", \"offset\": {\"signal\": \"datum.absolute_ci_upper * height / (domain('y')[1] - domain('y')[0])\"}},\n            \"height\": {\"value\": 1},\n            \"fill\": {\"value\": \"#4285F4\"},\n            \"fillOpacity\": {\"value\": 0.5}\n          }\n        }\n      },\n      {\n        \"type\": \"symbol\",\n        \"from\": {\"data\": \"source\"},\n        \"encode\": {\n          \"enter\": {\n            \"x\": {\"scale\": \"x\", \"field\": \"node_id\", \"band\": 0.5},\n            \"y\": {\"scale\": \"y\", \"field\": \"absolute\"},\n            \"fill\": {\"value\": \"#4285F4\"},\n            \"size\": {\"value\": 100},\n            \"opacity\": {\"value\": 0.35}\n          }\n        }\n      },\n      {\n        \"type\": \"symbol\",\n        \"from\": {\"data\": \"source\"},\n        \"encode\": {\n          \"enter\": {\n            \"x\": {\"scale\": \"x\", \"field\": \"node_id\", \"band\": 0.5},\n            \"y\": {\"scale\": \"y\", \"field\": \"absolute\"},\n            \"fill\": {\"value\": \"#4285F4\"},\n            \"size\": {\"value\": 38},\n            \"opacity\": {\"value\": 0.85}\n          }\n        }\n      },\n      {\n        \"type\": \"rule\",\n        \"from\": {\"data\": \"source\"},\n        \"encode\": {\n          \"enter\": {\n            \"x\": {\"scale\": \"x\", \"field\": \"node_id\", \"band\": 0.5},\n            \"y\": {\"scale\": \"y2\", \"field\": \"nx\", \"offset\": {\"signal\": \"-datum.nx_ci_lower * height / (domain('y2')[1] - domain('y2')[0])\"}},\n            \"y2\": {\"scale\": \"y2\", \"field\": \"nx\", \"offset\": {\"signal\": \"datum.nx_ci_upper * height / (domain('y2')[1] - domain('y2')[0])\"}},\n            \"stroke\": {\"value\": \"#DB4437\"},\n            \"strokeOpacity\": {\"value\": 0.5}\n          }\n        }\n      },\n      {\n        \"type\": \"rect\",\n        \"from\": {\"data\": \"source\"},\n        \"encode\": {\n          \"enter\": {\n            \"x\": {\"scale\": \"x\", \"field\": \"node_id\", \"band\": 0.5, \"offset\": -5},\n            \"width\": {\"value\": 10},\n            \"y\": {\"scale\": \"y2\", \"field\": \"nx\", \"offset\": {\"signal\": \"-datum.nx_ci_lower * height / (domain('y2')[1] - domain('y2')[0])\"}},\n            \"height\": {\"value\": 1},\n            \"fill\": {\"value\": \"#DB4437\"},\n            \"fillOpacity\": {\"value\": 0.5}\n          }\n        }\n      },\n      {\n        \"type\": \"rect\",\n        \"from\": {\"data\": \"source\"},\n        \"encode\": {\n          \"enter\": {\n            \"x\": {\"scale\": \"x\", \"field\": \"node_id\", \"band\": 0.5, \"offset\": -5},\n            \"width\": {\"value\": 10},\n            \"y\": {\"scale\": \"y2\", \"field\": \"nx\", \"offset\": {\"signal\": \"datum.nx_ci_upper * height / (domain('y2')[1] - domain('y2')[0])\"}},\n            \"height\": {\"value\": 1},\n            \"fill\": {\"value\": \"#DB4437\"},\n            \"fillOpacity\": {\"value\": 0.5}\n          }\n        }\n      },\n      {\n        \"type\": \"symbol\",\n        \"from\": {\"data\": \"source\"},\n        \"encode\": {\n          \"enter\": {\n            \"x\": {\"scale\": \"x\", \"field\": \"node_id\", \"band\": 0.5},\n            \"y\": {\"scale\": \"y2\", \"field\": \"nx\"},\n            \"fill\": {\"value\": \"#DB4437\"},\n            \"size\": {\"value\": 100},\n            \"opacity\": {\"value\": 0.35}\n          }\n        }\n      },\n      {\n        \"type\": \"symbol\",\n        \"from\": {\"data\": \"source\"},\n        \"encode\": {\n          \"enter\": {\n            \"x\": {\"scale\": \"x\", \"field\": \"node_id\", \"band\": 0.5},\n            \"y\": {\"scale\": \"y2\", \"field\": \"nx\"},\n            \"fill\": {\"value\": \"#DB4437\"},\n            \"size\": {\"value\": 38},\n            \"opacity\": {\"value\": 0.85}\n          }\n        }\n      },\n      {\n        \"type\": \"group\",\n        \"encode\": {\n          \"enter\": {\n            \"x\": {\"value\": 1630},\n            \"y\": {\"value\": 20},\n            \"width\": {\"value\": 140},\n            \"height\": {\"value\": 130},\n            \"cornerRadius\": {\"value\": 5},\n            \"fill\": {\"value\": \"#f0f0f0\"},\n            \"stroke\": {\"value\": \"#cccccc\"}\n          }\n        },\n        \"marks\": [\n          {\n            \"type\": \"text\",\n            \"from\": {\"data\": \"shrink_stats\"},\n            \"encode\": {\n              \"enter\": {\n                \"x\": {\"value\": 10},\n                \"y\": {\"value\": 20},\n                \"text\": {\"signal\": \"'Mean: ' + format(datum.mean_shrink, ',.1f')\"},\n                \"fontSize\": {\"value\": 14},\n                \"fill\": {\"value\": \"#4285F4\"}\n              }\n            }\n          },\n          {\n            \"type\": \"text\",\n            \"from\": {\"data\": \"shrink_stats\"},\n            \"encode\": {\n              \"enter\": {\n                \"x\": {\"value\": 10},\n                \"y\": {\"value\": 40},\n                \"text\": {\"signal\": \"'Sum: ' + format(datum.sum_shrink, ',d')\"},\n                \"fontSize\": {\"value\": 14},\n                \"fill\": {\"value\": \"#4285F4\"}\n              }\n            }\n          },\n          {\n            \"type\": \"text\",\n            \"from\": {\"data\": \"shrink_stats\"},\n            \"encode\": {\n              \"enter\": {\n                \"x\": {\"value\": 10},\n                \"y\": {\"value\": 60},\n                \"text\": {\"signal\": \"'Mean: ' + format(datum.mean_nx, ',.1f')\"},\n                \"fontSize\": {\"value\": 14},\n                \"fill\": {\"value\": \"#DB4437\"}\n              }\n            }\n          },\n          {\n            \"type\": \"text\",\n            \"encode\": {\n              \"enter\": {\n                \"x\": {\"value\": 10},\n                \"y\": {\"value\": 80},\n                \"text\": {\"signal\": \"'sum(old): ' + format(sum_old, ',.1f')\"},\n                \"fontSize\": {\"value\": 14},\n                \"fill\": {\"value\": \"#505050\"}\n              }\n            }\n          },\n          {\n            \"type\": \"text\",\n            \"encode\": {\n              \"enter\": {\n                \"x\": {\"value\": 10},\n                \"y\": {\"value\": 100},\n                \"text\": {\"signal\": \"'sum(new): ' + format(sum_new, ',.1f')\"},\n                \"fontSize\": {\"value\": 14},\n                \"fill\": {\"value\": \"#505050\"}\n              }\n            }\n          },\n          {\n            \"type\": \"text\",\n            \"encode\": {\n              \"enter\": {\n                \"x\": {\"value\": 10},\n                \"y\": {\"value\": 120},\n                \"text\": {\"signal\": \"'old / new: ' + format(sum_old / sum_new, ',.2f')\"},\n                \"fontSize\": {\"value\": 14},\n                \"fill\": {\"value\": \"#505050\"}\n              }\n            }\n          }\n        ]\n      }\n    ]\n  }\n"
  },
  {
    "path": "hypothesis-python/docs/_ext/hypothesis_linkcheck.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport sphinx\nfrom sphinx.application import Sphinx\nfrom sphinx.builders.linkcheck import HyperlinkAvailabilityChecker\n\n# We want to customize the linkcheck behavior so that references from intersphinx\n# mappings are not checked. We use these liberally and don't want to spend CI time\n# checking their validity. If it's in an inventory, sphinx should guarantee\n# it's valid, sans very weird things happening.\n#\n# Sphinx splits the link check logic across a CheckExternalLinksBuilder builder\n# and a HyperlinkCollector post_transform (and a HyperlinkAvailabilityChecker\n# helper class). There are various points in each where we could add this\n# ignore-intersphinx hook.\n#\n# Monkey-patching HyperlinkAvailabilityChecker isn't great, but is the best way\n# I found to go about this.\n\n# set by on_builder_inited\ninventories = {}\n\n\ndef is_intersphinx_link(uri):\n    for inventory in inventories.values():\n        uris = {uri for _name, _version, uri, _display_name in inventory.values()}\n        if uri in uris:\n            return True\n    return False\n\n\nclass HypothesisLinkChecker(HyperlinkAvailabilityChecker):\n    def is_ignored_uri(self, uri: str) -> bool:\n        if is_intersphinx_link(uri):\n            return True\n        return super().is_ignored_uri(uri)\n\n\nsphinx.builders.linkcheck.HyperlinkAvailabilityChecker = HypothesisLinkChecker\n\n\n# Hook the builder to get access to the intersphinx inventory. app.env is not\n# available in setup()\ndef on_builder_inited(app: Sphinx) -> None:\n    global inventories\n    inventories = getattr(app.env, \"intersphinx_inventory\", {})\n\n\ndef setup(app: Sphinx):\n    app.connect(\"builder-inited\", on_builder_inited)\n"
  },
  {
    "path": "hypothesis-python/docs/_ext/hypothesis_redirects.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n# vendored from https://github.com/documatt/sphinx-reredirects under the MIT\n# license, with thanks\n\n# ruff: noqa: G004\n\nimport re\nfrom collections.abc import Mapping, Sequence\nfrom fnmatch import fnmatch\nfrom pathlib import Path\nfrom string import Template\nfrom urllib.parse import urlparse\n\nfrom sphinx.application import Sphinx\nfrom sphinx.builders.linkcheck import CheckExternalLinksBuilder, Hyperlink\nfrom sphinx.util import logging\nfrom sphinx.util.osutil import SEP\n\nOPTION_REDIRECTS = \"redirects\"\nOPTION_REDIRECTS_DEFAULT: dict[str, str] = {}\n\nOPTION_TEMPLATE_FILE = \"redirect_html_template_file\"\nOPTION_TEMPLATE_FILE_DEFAULT = None\n\nREDIRECT_FILE_DEFAULT_TEMPLATE = (\n    '<html><head><meta http-equiv=\"refresh\" content=\"0; url=${to_uri}\"></head></html>'\n)\n\nlogger = logging.getLogger(__name__)\n\nwildcard_pattern = re.compile(r\"[\\*\\?\\[\\]]\")\n\n\ndef setup(app: Sphinx) -> dict:\n    \"\"\"\n    Extension setup, called by Sphinx\n    \"\"\"\n    app.connect(\"html-collect-pages\", init)\n    app.connect(\"builder-inited\", collect_redirects_for_linkcheck)\n    app.add_config_value(OPTION_REDIRECTS, OPTION_REDIRECTS_DEFAULT, \"env\")\n    app.add_config_value(OPTION_TEMPLATE_FILE, OPTION_TEMPLATE_FILE_DEFAULT, \"env\")\n    return {\"parallel_read_safe\": True}\n\n\ndef init(app: Sphinx) -> Sequence | None:\n    if not app.config[OPTION_REDIRECTS]:\n        logger.debug(\"No redirects configured\")\n        return []\n\n    rr = Reredirects(app)\n    to_be_redirected = rr.grab_redirects()\n    rr.create_redirects(to_be_redirected)\n\n    # html-collect-pages requires to return iterable of pages to write,\n    # we have no additional pages to write\n    return []\n\n\nclass Reredirects:\n    def __init__(self, app: Sphinx) -> None:\n        self.app = app\n        self.redirects_option: dict[str, str] = getattr(app.config, OPTION_REDIRECTS)\n        self.template_file_option: str = getattr(app.config, OPTION_TEMPLATE_FILE)\n\n    def grab_redirects(self) -> Mapping[str, str]:\n        \"\"\"Inspect redirects option in conf.py and returns dict mapping\n        docname to target (with expanded placeholder).\"\"\"\n        # docname-target dict\n        to_be_redirected = {}\n\n        # For each source-target redirect pair in conf.py\n        for source, target in self.redirects_option.items():\n            # no wildcard, append source as-is\n            if not self._contains_wildcard(source):\n                to_be_redirected[source] = target\n                continue\n\n            assert self.app.env\n\n            # wildcarded source, expand to docnames\n            expanded_docs = [\n                doc for doc in self.app.env.found_docs if fnmatch(doc, source)\n            ]\n\n            if not expanded_docs:\n                logger.warning(f\"No documents match to '{source}' redirect.\")\n                continue\n\n            for doc in expanded_docs:\n                new_target = self._apply_placeholders(doc, target)\n                to_be_redirected[doc] = new_target\n\n        return to_be_redirected\n\n    def docname_out_path(self, docname: str, suffix: str) -> Sequence[str]:\n        \"\"\"\n        For a Sphinx docname (the path to a source document without suffix),\n        returns path to outfile that would be created by the used builder.\n        \"\"\"\n        # Return as-is, if the docname already has been passed with a suffix\n        if docname.endswith(suffix):\n            return [docname]\n\n        # Remove any trailing slashes, except for \"/\"\" index\n        if len(docname) > 1 and docname.endswith(SEP):\n            docname = docname.rstrip(SEP)\n\n        # Figure out whether we have dirhtml builder\n        out_uri = self.app.builder.get_target_uri(docname=docname)  # type: ignore\n\n        if not out_uri.endswith(suffix):\n            # If dirhtml builder is used, need to append \"index\"\n            return [out_uri, \"index\"]\n\n        # Otherwise, convert e.g. 'source' to 'source.html'\n        return [out_uri]\n\n    def create_redirects(self, to_be_redirected: Mapping[str, str]) -> None:\n        \"\"\"Create actual redirect file for each pair in passed mapping of\n        docnames to targets.\"\"\"\n\n        # Corresponds to value of `html_file_suffix`, but takes into account\n        # modifications done by the builder class\n        try:\n            suffix = self.app.builder.out_suffix  # type: ignore\n        except Exception:\n            suffix = \".html\"\n\n        for docname, target in to_be_redirected.items():\n            out = self.docname_out_path(docname, suffix)\n            redirect_file_abs = Path(self.app.outdir).joinpath(*out).with_suffix(suffix)\n\n            redirect_file_rel = redirect_file_abs.relative_to(self.app.outdir)\n\n            if redirect_file_abs.exists():\n                logger.info(\n                    f\"Overwriting '{redirect_file_rel}' with redirect to '{target}'.\"\n                )\n            else:\n                logger.info(f\"Creating redirect '{redirect_file_rel}' to '{target}'.\")\n\n            self._create_redirect_file(redirect_file_abs, target)\n\n    @staticmethod\n    def _contains_wildcard(text: str) -> bool:\n        \"\"\"Tells whether passed argument contains wildcard characters.\"\"\"\n        return bool(wildcard_pattern.search(text))\n\n    @staticmethod\n    def _apply_placeholders(source: str, target: str) -> str:\n        \"\"\"Expand \"source\" placeholder in target and return it\"\"\"\n        return Template(target).substitute({\"source\": source})\n\n    def _create_redirect_file(self, at_path: Path, to_uri: str) -> None:\n        \"\"\"Actually create a redirect file according to redirect template\"\"\"\n\n        content = self._render_redirect_template(to_uri)\n\n        # create any missing parent folders\n        at_path.parent.mkdir(parents=True, exist_ok=True)\n\n        at_path.write_text(content, encoding=\"utf-8\")\n\n    def _render_redirect_template(self, to_uri: str) -> str:\n        # HTML used as redirect file content\n        redirect_template = REDIRECT_FILE_DEFAULT_TEMPLATE\n        if self.template_file_option:\n            redirect_file_abs = Path(self.app.srcdir, self.template_file_option)\n            redirect_template = redirect_file_abs.read_text(encoding=\"utf-8\")\n\n        return Template(redirect_template).substitute({\"to_uri\": to_uri})\n\n\ndef collect_redirects_for_linkcheck(app):\n    # Ignore when not invoked with linkcheck builder\n    if not isinstance(app.builder, CheckExternalLinksBuilder):\n        return\n\n    redirects = Reredirects(app).grab_redirects()\n\n    for docname, target in redirects.items():\n        # Give a Sphinx or extensions change to modify original target URL\n        if new_target := app.emit_firstresult(\"linkcheck-process-uri\", target):\n            target = new_target\n\n        if urlparse(target).scheme not in (\"http\", \"https\"):\n            # Checking redirects to other pages of the same documentation is not\n            # supported for now.\n            continue\n\n        # Add target external URL to hyperlinks which linkcheck builder will check\n        docpath = app.env.doc2path(docname)\n        hyperlink = Hyperlink(uri=target, docname=docname, docpath=docpath, lineno=-1)\n        app.builder.hyperlinks[target] = hyperlink\n"
  },
  {
    "path": "hypothesis-python/docs/_static/better-signatures.css",
    "content": "/* dl gets used both for defining each top-level `.. autofunc` on a page (where we want vertical margsin)\n   and is wrapped around multiline signatures (where we don't).\n   If a dl is being used inside a .sig, that's a multiline signature; remove its margins. */\n.sig > dl {\n  margin-block-start: 0rem;\n  margin-block-end: 0rem;\n}\n\n/* with thanks to https://github.com/pradyunsg/furo/discussions/749 */\n.sig:not(.sig-inline) {\n  padding-left: 0.5em;\n  text-indent: 0;\n}\n"
  },
  {
    "path": "hypothesis-python/docs/_static/dark-fix.css",
    "content": "/*\nSee https://github.com/HypothesisWorks/hypothesis/issues/4588 and\nhttps://github.com/pradyunsg/furo/discussions/909. Once this is fixed in furo,\nwe can remove this.\n*/\n\nbody[data-theme=\"dark\"] .tooltip .tooltip-content {\n    background-color: var(--color-background-primary);\n}\n\nbody[data-theme=\"dark\"] .tooltip .arrow {\n    background: var(--color-background-primary);\n}\n"
  },
  {
    "path": "hypothesis-python/docs/_static/no-scroll.css",
    "content": "/* disable autoscroll-to-target behavior\n   https://github.com/pradyunsg/furo/discussions/384#discussioncomment-2249243 */\nhtml {\n    scroll-behavior: auto;\n}\n"
  },
  {
    "path": "hypothesis-python/docs/_static/wrap-in-tables.css",
    "content": "/* override table width restrictions */\n/* thanks to https://github.com/readthedocs/sphinx_rtd_theme/issues/117#issuecomment-153083280 */\n@media screen and (min-width: 767px) {\n\n    .wy-table-responsive table td {\n        /* !important prevents the common CSS stylesheets from\n            overriding this as on RTD they are loaded after this stylesheet */\n        white-space: normal !important;\n    }\n\n    .wy-table-responsive {\n        overflow: visible !important;\n    }\n\n}\n"
  },
  {
    "path": "hypothesis-python/docs/changelog.rst",
    "content": "=========\nChangelog\n=========\n\nThis is a record of all past Hypothesis releases and what went into them,\nin reverse chronological order. All previous releases are still available\n:pypi:`on PyPI <hypothesis>`.\n\n\nHypothesis 6.x\n==============\n\n.. only:: has_release_file\n\n    --------------------\n    Current pull request\n    --------------------\n\n    .. include:: ../RELEASE.rst\n\n.. _v6.151.9:\n\n--------------------\n6.151.9 - 2026-02-16\n--------------------\n\nRemove some old unused code.\n\n.. _v6.151.8:\n\n--------------------\n6.151.8 - 2026-02-16\n--------------------\n\nThis patch fixes a crash when :obj:`sys.modules` contains unhashable values,\nsuch as :class:`~types.SimpleNamespace` objects (:issue:`4660`).\n\n.. _v6.151.7:\n\n--------------------\n6.151.7 - 2026-02-16\n--------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.151.6:\n\n--------------------\n6.151.6 - 2026-02-11\n--------------------\n\nThis patch fixes several duplicate word typos in comments and documentation.\n\n.. _v6.151.5:\n\n--------------------\n6.151.5 - 2026-02-03\n--------------------\n\nThis patch teaches our pytest plugin to :ref:` find interesting constants <v6.131.1>`\nwhen pytest is collecting tests, to avoid arbitrarily attributing the latency\nto whichever test function happened to be executed first (:issue:`4627`).\n\n.. _v6.151.4:\n\n--------------------\n6.151.4 - 2026-01-29\n--------------------\n\nThis patch adjusts how we compute the stopping threshold introduced in :version:`6.151.3`, while still maintaining 99% confidence that <1% of test cases pass.\n\n.. _v6.151.3:\n\n--------------------\n6.151.3 - 2026-01-28\n--------------------\n\nThis patch makes Hypothesis more tolerant of slow-to-satisfy ``assume()`` calls.\nPreviously, Hypothesis would give up after ``max_examples * 10`` attempts; now it\nuses a statistical test to stop only when 99% confident that <1% of examples\nwould pass (:issue:`4623`).\n\nThanks to @ajdavis for this improvement!\n\n.. _v6.151.2:\n\n--------------------\n6.151.2 - 2026-01-26\n--------------------\n\nFormat our code with the latest version of :pypi:`black`.\n\n.. _v6.151.1:\n\n--------------------\n6.151.1 - 2026-01-26\n--------------------\n\nImprove internal categorization of test cases when an :ref:`alternative backend <alternative-backends>` raises |BackendCannotProceed|.\n\n.. _v6.151.0:\n\n--------------------\n6.151.0 - 2026-01-25\n--------------------\n\nAdd 2025.12 to the list of recognized Array API versions in\n``hypothesis.extra.array_api``.\n\n.. _v6.150.3:\n\n--------------------\n6.150.3 - 2026-01-23\n--------------------\n\nHypothesis now generates powers of 2 more often when using |st.integers|.\n\n.. _v6.150.2:\n\n--------------------\n6.150.2 - 2026-01-13\n--------------------\n\nUpdate some internal type hints.\n\n.. _v6.150.1:\n\n--------------------\n6.150.1 - 2026-01-12\n--------------------\n\nThis patch fixes a bug where |st.recursive| would fail in cases where the\n``extend=`` function does not reference it's argument - which was assumed\nby the recent ``min_leaves=`` feature, because the strategy can't actually\nrecurse otherwise.  (:issue:`4638`)\n\nNow, the historical behavior is working-but-deprecated, or an error if you\nexplicitly pass ``min_leaves=``.\n\n.. _v6.150.0:\n\n--------------------\n6.150.0 - 2026-01-06\n--------------------\n\nThis release adds a ``min_leaves`` argument to :func:`~hypothesis.strategies.recursive`,\nwhich ensures that generated recursive structures have at least the specified number\nof leaf nodes (:issue:`4205`).\n\n.. _v6.149.1:\n\n--------------------\n6.149.1 - 2026-01-05\n--------------------\n\nAdd type hints to an internal class.\n\n.. _v6.149.0:\n\n--------------------\n6.149.0 - 2026-01-05\n--------------------\n\nThis release extends the explain-phase ``# or any other generated value`` comments\nto sub-arguments within :func:`~hypothesis.strategies.builds`,\n:func:`~hypothesis.strategies.tuples`, and :func:`~hypothesis.strategies.fixed_dictionaries`.\n\nPreviously, these comments only appeared on top-level test arguments. Now, when\nthe explain phase determines that a sub-argument can vary freely without affecting\nthe test failure, you'll see comments like::\n\n    Falsifying example: test_foo(\n        obj=MyClass(\n            x=0,  # or any other generated value\n            y=True,\n        ),\n        data=(\n            '',  # or any other generated value\n            42,\n        ),\n    )\n\nThis makes it easier to understand which parts of complex inputs actually matter\nfor reproducing a failure.\n\n.. _v6.148.13:\n\n---------------------\n6.148.13 - 2026-01-05\n---------------------\n\nClean up an internal helper.\n\n.. _v6.148.12:\n\n---------------------\n6.148.12 - 2026-01-04\n---------------------\n\nThis patch fixes :func:`~hypothesis.strategies.from_type` to properly handle\nparameterized type aliases created with Python 3.12+'s :pep:`695` ``type``\nstatement. For example, ``st.from_type(A[int])`` where ``type A[T] = list[T]``\nnow correctly resolves to ``lists(integers())`` instead of raising a\n``TypeError`` (:issue:`4628`).\n\n.. _v6.148.11:\n\n---------------------\n6.148.11 - 2026-01-03\n---------------------\n\nHypothesis now prints a |Verbosity.verbose| log when we switch away from an :ref:`alternative backend <alternative-backends>`.\n\n.. _v6.148.10:\n\n---------------------\n6.148.10 - 2026-01-03\n---------------------\n\nFixes :ref:`Ghostwriter <ghostwriter>` output for :pypi:`numpy` >= 2.4.0. Also adds support |st.from_type| for :pypi:`numpy` 2.5.0 nightly (which has not yet been released).\n\n.. _v6.148.9:\n\n--------------------\n6.148.9 - 2026-01-01\n--------------------\n\n|.example| no longer emits |NonInteractiveExampleWarning| when running a python file directly. This means that e.g. ``python my_sandbox.py`` during exploratory work with |.example| will no longer raise warnings.\n\n.. _v6.148.8:\n\n--------------------\n6.148.8 - 2025-12-23\n--------------------\n\nAdd ``__dict__`` and ``__proto__`` to the list of constant strings Hypothesis sometimes generates.\n\n.. _v6.148.7:\n\n--------------------\n6.148.7 - 2025-12-05\n--------------------\n\nWhen multiple explicit |@example| decorators fail with the same error,\nHypothesis now shows only the simplest failing example (by shortlex order)\nwith a note about how many other examples also failed (:issue:`4520`).\n\nTo see all failing examples, use |Verbosity.verbose| or higher.\n\n.. _v6.148.6:\n\n--------------------\n6.148.6 - 2025-12-04\n--------------------\n\nFix a bug where we persisted symbolics from solver-based :ref:`alternative backends <alternative-backends>` in |event|.\n\n.. _v6.148.5:\n\n--------------------\n6.148.5 - 2025-12-01\n--------------------\n\nThis patch improves the error message for :class:`~hypothesis.errors.FlakyStrategyDefinition`\nwhen the precondition for a rule is flaky (:issue:`4206`).\n\n.. _v6.148.4:\n\n--------------------\n6.148.4 - 2025-12-01\n--------------------\n\nThis patch improves the type annotations for :func:`~hypothesis.extra.numpy.basic_indices`.\nThe return type now accurately reflects the ``allow_ellipsis`` and ``allow_newaxis``\nparameters, excluding ``EllipsisType`` or ``None`` from the union when those index\ntypes are disabled (:issue:`4607`).\n\nAdditionally, :func:`~hypothesis.assume` now has overloaded type annotations:\n``assume(True)`` returns ``Literal[True]``, while ``assume(False)`` and\n``assume(None)`` return ``NoReturn``.\n\n.. _v6.148.3:\n\n--------------------\n6.148.3 - 2025-11-27\n--------------------\n\nClean up some internal code.\n\n.. _v6.148.2:\n\n--------------------\n6.148.2 - 2025-11-18\n--------------------\n\nDocument |fuzz_one_input|.\n\n.. _v6.148.1:\n\n--------------------\n6.148.1 - 2025-11-16\n--------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.148.0:\n\n--------------------\n6.148.0 - 2025-11-15\n--------------------\n\nCalling :func:`~hypothesis.settings.register_profile` from within a test\ndecorated with :func:`@settings <hypothesis.settings>` is now deprecated,\nto avoid confusion about which settings are used as the baseline for the\nnew profile.\n\n.. _v6.147.0:\n\n--------------------\n6.147.0 - 2025-11-06\n--------------------\n\nThis release drops support for :pypi:`nose`, which ceased development 9 years ago and does not support Python 3.10 or newer.\n\nHypothesis still supports :pypi:`nose2`. While we do not test ``nose2`` in our CI, we will fix any bugs that get reported.\n\n.. _v6.146.0:\n\n--------------------\n6.146.0 - 2025-11-05\n--------------------\n\n|@settings| now accepts equivalent string representations for |settings.verbosity|, |settings.phases|, and |settings.suppress_health_check|. For example:\n\n.. code-block:: python\n\n  # these two are now equivalent...\n  settings(verbosity=Verbosity.verbose)\n  settings(verbosity=\"verbose\")\n\n  # ...as are these two...\n  settings(phases=[Phase.explicit])\n  settings(phases=[\"explicit\"])\n\n  # ...and these two.\n  settings(suppress_health_check=[HealthCheck.filter_too_much])\n  settings(suppress_health_check=[\"filter_too_much\"])\n\nThis release also changes the canonical value of |Verbosity|, |Phase|, and |HealthCheck| members to a string instead of an integer. For example, ``Phase.reuse.value == \"explicit\"`` as of this release, where previously ``Phase.reuse.value == 1``.\n\nInstantiating |Verbosity|, |Phase|, or |HealthCheck| with an integer, such as ``Verbosity(0)``, is now deprecated.\n\n.. _v6.145.1:\n\n--------------------\n6.145.1 - 2025-11-03\n--------------------\n\nRefactor some internal logic around strategy definitions.\n\n.. _v6.145.0:\n\n--------------------\n6.145.0 - 2025-11-03\n--------------------\n\nHypothesis previously required :pypi:`attrs` as a dependency. This release removes that dependency, so that the only required dependency of Hypothesis is :pypi:`sortedcontainers`.\n\nAll attrs-specific features of Hypothesis, such as using |st.from_type| with attrs classes, will continue to behave as before.\n\n.. _v6.144.1:\n\n--------------------\n6.144.1 - 2025-11-03\n--------------------\n\nTweak how Hypothesis hides internal tracebacks to fix an error under rare conditions (:issue:`3822`).\n\n.. _v6.144.0:\n\n--------------------\n6.144.0 - 2025-11-02\n--------------------\n\nThis release adds support for :class:`~fractions.Fraction` objects as ``min_value``\nand ``max_value`` bounds in :func:`~hypothesis.strategies.decimals`, if they can\nbe exactly represented as decimals in the target precision (:issue:`4466`).\n\nBounding :func:`~hypothesis.strategies.decimals` with *other* values that cannot\nbe exactly represented is now deprecated; previously the bounds could be off by one.\n\n.. _v6.143.1:\n\n--------------------\n6.143.1 - 2025-11-02\n--------------------\n\n:func:`~hypothesis.strategies.from_type` now correctly handles :pypi:`annotated-types`\nannotations on :class:`typing.TypedDict` fields which are also marked as being\n:obj:`~typing.ReadOnly`, :obj:`~typing.Required`, or :obj:`~typing.NotRequired`\n(:issue:`4474`).\n\n.. _v6.143.0:\n\n--------------------\n6.143.0 - 2025-11-01\n--------------------\n\nThe extras for |hypothesis-numpy| and |hypothesis-pandas| now support automatically inferring a strategy for ``dtype=\"O\"``. Previously, Hypothesis required an explicit elements strategy to be passed, for example ``nps.arrays(\"O\", shape=(1,), elements=st.just(object()))``. Now, Hypothesis automatically infers ``elements=st.from_type(object)``.\n\nThanks to Shaun Read for identifying and fixing this!\n\n.. _v6.142.5:\n\n--------------------\n6.142.5 - 2025-10-31\n--------------------\n\nThis patch fixes :func:`~hypothesis.extra.ghostwriter.binary_operation` to\ninclude imports for :mod:`hypothesis.extra.numpy` strategies such as\n:func:`~hypothesis.extra.numpy.arrays`, :func:`~hypothesis.extra.numpy.scalar_dtypes`,\nand :func:`~hypothesis.extra.numpy.array_shapes` when ghostwriting tests for\nfunctions with numpy array parameters (:issue:`4576`).\n\n.. _v6.142.4:\n\n--------------------\n6.142.4 - 2025-10-25\n--------------------\n\nImprove the accuracy of test timing reports, by tracking the start time of each test case closer to when the test is executed.\n\n.. _v6.142.3:\n\n--------------------\n6.142.3 - 2025-10-22\n--------------------\n\nFix a recursion error when :ref:`observability <observability>` is enabled and a test generates an object with a recursive reference, like ``a = []; a.append(a)``.\n\n.. _v6.142.2:\n\n--------------------\n6.142.2 - 2025-10-20\n--------------------\n\nRemove a case where Hypothesis would interact with the global |random.Random| instance if Hypothesis internals were used directly.\n\n.. _v6.142.1:\n\n--------------------\n6.142.1 - 2025-10-16\n--------------------\n\nSimplify some internal typing logic after dropping Python 3.9.\n\n.. _v6.142.0:\n\n--------------------\n6.142.0 - 2025-10-16\n--------------------\n\nThis release drops support for Python 3.9, `which reached end of life in\nOctober 2025 <https://devguide.python.org/versions/>`__.\n\n.. _v6.141.1:\n\n--------------------\n6.141.1 - 2025-10-15\n--------------------\n\nFixes an error when using :ref:`the Ghostwriter <ghostwriter>` with annotations that include :obj:`python:typing.ForwardRef` on Python 3.14 (:issue:`4565`).\n\n.. _v6.141.0:\n\n--------------------\n6.141.0 - 2025-10-15\n--------------------\n\nThe |django.from_field| and |django.from_form| strategies from our :ref:`Django extra <hypothesis-django>` now support :obj:`~django:django.db.models.FileField`.\n\nThanks to Arjoonn Sharma for this fix!\n\n.. _v6.140.4:\n\n--------------------\n6.140.4 - 2025-10-14\n--------------------\n\nClean up internal ``@overload`` type annotations.\n\n.. _v6.140.3:\n\n--------------------\n6.140.3 - 2025-10-04\n--------------------\n\nFixes our bundled |run_conformance_test| not respecting |PrimitiveProvider.avoid_realization|.\n\n.. _v6.140.2:\n\n--------------------\n6.140.2 - 2025-09-23\n--------------------\n\nThe automatic switch to the CI :class:`settings profile <hypothesis.settings>` now works under :pypi:`tox` (for ``tox >= 4.30.0``).\n\n.. _v6.140.1:\n\n--------------------\n6.140.1 - 2025-09-22\n--------------------\n\nThis patch re-enables the warning for incompatible :func:`~hypothesis.strategies.shared`\nstrategies that was first enabled in :v:`6.133.0` but disabled in :v:`6.135.15`.\n\n.. _v6.140.0:\n\n--------------------\n6.140.0 - 2025-09-22\n--------------------\n\n|st.characters| now validates that the elements of the ``exclude_characters`` and ``include_characters`` arguments are single characters, which was always assumed internally. For example, ``exclude_characters=[\"a\", \"b\"]`` is valid while ``exclude_characters=[\"ab\"]`` will now raise an error up-front.\n\n.. _v6.139.3:\n\n--------------------\n6.139.3 - 2025-09-22\n--------------------\n\nAdd ``phase`` to the :ref:`hypothesis-specific metadata <observability-hypothesis-metadata>` in :ref:`observability <observability>`.\n\n.. _v6.139.2:\n\n--------------------\n6.139.2 - 2025-09-18\n--------------------\n\nInternal refactoring for new lint rules.\n\n.. _v6.139.1:\n\n--------------------\n6.139.1 - 2025-09-16\n--------------------\n\nFixed another typo in error message around function-scoped fixtures.\n\n.. _v6.139.0:\n\n--------------------\n6.139.0 - 2025-09-16\n--------------------\n\nAdd |settings.get_current_profile_name|, which returns the name of the current settings profile.\n\n.. _v6.138.17:\n\n---------------------\n6.138.17 - 2025-09-15\n---------------------\n\nFixed typo in error message around function-scoped fixtures.\n\n.. _v6.138.16:\n\n---------------------\n6.138.16 - 2025-09-13\n---------------------\n\nImproved error message for |DeadlineExceeded|.\n\n.. _v6.138.15:\n\n---------------------\n6.138.15 - 2025-09-08\n---------------------\n\nRefactor some stateful testing internals for easier use by third-party libraries.\n\n.. _v6.138.14:\n\n---------------------\n6.138.14 - 2025-09-02\n---------------------\n\nPatch files written by hypothesis now use a deterministic ordering when multiple |@example| decorators are present.\n\n.. _v6.138.13:\n\n---------------------\n6.138.13 - 2025-09-01\n---------------------\n\nFix a typo affecting pretty-printing of lambdas with complex default\narguments.\n\n.. _v6.138.12:\n\n---------------------\n6.138.12 - 2025-09-01\n---------------------\n\nImprove automatic detection of the :ref:`CI profile <builtin-profiles>` on various vendor-specific CI systems.\n\n.. _v6.138.11:\n\n---------------------\n6.138.11 - 2025-09-01\n---------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.138.10:\n\n---------------------\n6.138.10 - 2025-08-31\n---------------------\n\nInternal refactor to simplify |SearchStrategy|.\n\n.. _v6.138.9:\n\n--------------------\n6.138.9 - 2025-08-31\n--------------------\n\nThis patch further improves stringification of lambdas, by\nnever returning a lambda source unless it is confirmed to\ncompile to the same code object. This stricter check makes\nit possible to widen the search for a matching source block,\nso that it can often be found even if the file has been\nedited.\n\n.. _v6.138.8:\n\n--------------------\n6.138.8 - 2025-08-29\n--------------------\n\nFixes a race condition under threading when using |st.deferred|.\n\n.. _v6.138.7:\n\n--------------------\n6.138.7 - 2025-08-28\n--------------------\n\nImproves upon the cache eviction problem workaround\nof :v:`6.135.12`.\n\n.. _v6.138.6:\n\n--------------------\n6.138.6 - 2025-08-27\n--------------------\n\nDocumentation tweaks.\n\n.. _v6.138.5:\n\n--------------------\n6.138.5 - 2025-08-27\n--------------------\n\nFixes a race condition under threading for strategies which trigger our filter-rewriting rules, like ``st.integers().filter(lambda x: abs(x) > 100)``.\n\n.. _v6.138.4:\n\n--------------------\n6.138.4 - 2025-08-27\n--------------------\n\nOne of our shrinking passes for reducing failing inputs targets failures which require two numbers to add to the same value. This pass previously only worked for positive numbers. This patch fixes that, so it also works for negative numbers.\n\n.. _v6.138.3:\n\n--------------------\n6.138.3 - 2025-08-24\n--------------------\n\nThis patch slightly improves the cache-hit rate for\n|st.dictionaries| and certain unique |st.lists|.\n\n.. _v6.138.2:\n\n--------------------\n6.138.2 - 2025-08-16\n--------------------\n\nThe type annotations for |st.register_type_strategy| now indicate that it accepts registering types created with |TypeAliasType| (aka ``type MyType = int``).\n\n.. _v6.138.1:\n\n--------------------\n6.138.1 - 2025-08-15\n--------------------\n\nInternal refactoring and cleanup. As a result, ``hypothesis[cli]`` and ``hypothesis[ghostwriter]`` now require ``black>=20.8b0`` instead of the previous ``black>=19.10b0``.\n\n.. _v6.138.0:\n\n--------------------\n6.138.0 - 2025-08-13\n--------------------\n\nOn Python 3.14, |memoryview| is newly generic. This release adds the ability for |st.from_type| to resolve generic |memoryview| types on 3.14, like ``st.from_type(memoryview[CustomBufferClass])`` . ``CustomBufferClass`` must implement ``__buffer__``, as expected by |memoryview|.\n\n.. _v6.137.3:\n\n--------------------\n6.137.3 - 2025-08-11\n--------------------\n\nThis patch makes the stringification of lambdas, and as\na result certain automatic filter rewriting operations,\nmore robust. This fixes :issue:`4498`, where a lambda\nwas mistakenly identified as the identity operator due\nto :func:`inspect.getsource` only returning the first\nline of the lambda definition.\n\nAs a result, the ``repr`` of strategies filtered or\nmapped by lambda functions may change slightly.\n\n.. _v6.137.2:\n\n--------------------\n6.137.2 - 2025-08-11\n--------------------\n\nAdd support for Python 3.14, `which is currently in release candidate 1 <https://devguide.python.org/versions/>`_.\n\n.. _v6.137.1:\n\n--------------------\n6.137.1 - 2025-08-05\n--------------------\n\nFixes a bug with solver-based :ref:`alternative backends <alternative-backends>` (like `crosshair <https://github.com/pschanely/CrossHair>`_) where symbolic values passed to |event| would not be realized to concrete values at the end of the test case.\n\n.. _v6.137.0:\n\n--------------------\n6.137.0 - 2025-08-05\n--------------------\n\nAdd the |add_observability_callback|, |remove_observability_callback|, |with_observability_callback|, and |observability_enabled| methods to the :ref:`observability <observability>` interface. The previous |TESTCASE_CALLBACKS| is deprecated.\n\nThis release also adds better threading support to observability callbacks. An observability callback will now only be called for observations generated by the same thread.\n\n.. _v6.136.9:\n\n--------------------\n6.136.9 - 2025-08-04\n--------------------\n\nFix a threading race condition in |st.one_of| initialization.\n\n.. _v6.136.8:\n\n--------------------\n6.136.8 - 2025-08-04\n--------------------\n\nImprove the error messages and documentation for |HealthCheck|. Among others, the messaging is now more clear that health checks are proactive warnings, not correctness errors.\n\n.. _v6.136.7:\n\n--------------------\n6.136.7 - 2025-08-01\n--------------------\n\nImprove detection of sys.monitoring to avoid errors on GraalPy.\n\n.. _v6.136.6:\n\n--------------------\n6.136.6 - 2025-07-28\n--------------------\n\nWhen a test is executed concurrently from multiple threads, |HealthCheck.too_slow| is now disabled, since the Python runtime may decide to switch away from a thread for arbitrarily long and Hypothesis cannot track execution time per-thread.\n\n.. _v6.136.5:\n\n--------------------\n6.136.5 - 2025-07-28\n--------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.136.4:\n\n--------------------\n6.136.4 - 2025-07-25\n--------------------\n\n|HealthCheck.differing_executors| is no longer raised if a test is executed by different executors from different threads. |HealthCheck.differing_executors| will still be raised if a test is executed by different executors in the same thread.\n\n.. _v6.136.3:\n\n--------------------\n6.136.3 - 2025-07-23\n--------------------\n\nWhen a test is executed concurrently from multiple threads, |DeadlineExceeded| is now disabled, since the Python runtime may decide to switch away from a thread for longer than |settings.deadline|, and Hypothesis cannot track execution time per-thread. See :issue:`4478`.\n\n.. _v6.136.2:\n\n--------------------\n6.136.2 - 2025-07-21\n--------------------\n\n|@precondition| now errors if used without |@rule| or |@invariant|. Doing so has no effect and is indicative of a user error (:issue:`4413`).\n\n.. _v6.136.1:\n\n--------------------\n6.136.1 - 2025-07-20\n--------------------\n\nFix |PrimitiveProvider.on_observation| being called with observations it wasn't responsible for generating if the test failed.\n\n.. _v6.136.0:\n\n--------------------\n6.136.0 - 2025-07-19\n--------------------\n\nWhen a failure found by an :ref:`alternative backend <alternative-backends>` does not reproduce under the Hypothesis backend, we now raise |FlakyBackendFailure| instead of an internal ``FlakyReplay`` exception.\n\n.. _v6.135.33:\n\n---------------------\n6.135.33 - 2025-07-18\n---------------------\n\nSpeculative fix for a thread-safety issue in calculating strategy labels.\n\n.. _v6.135.32:\n\n---------------------\n6.135.32 - 2025-07-15\n---------------------\n\nImprove the thread-safety of strategy validation.\n\nBefore this release, Hypothesis did not require that ``super().__init__()`` be called in ``SearchStrategy`` subclasses. Subclassing ``SearchStrategy`` is not supported or part of the public API, but if you are subclassing it anyway, you will need to make sure to call ``super().__init__()`` after this release.\n\n.. _v6.135.31:\n\n---------------------\n6.135.31 - 2025-07-15\n---------------------\n\nFix a remaining thread-safety issue with the deprecation warning for use of the global random instance (see :ref:`v6.135.24 <v6.135.24>`).\n\n.. _v6.135.30:\n\n---------------------\n6.135.30 - 2025-07-14\n---------------------\n\nFix a remaining thread-safety issue with the recursion limit warning Hypothesis issues when an outside caller sets ``sys.setrecursionlimit`` (see :ref:`v6.135.23 <v6.135.23>`).\n\n.. _v6.135.29:\n\n---------------------\n6.135.29 - 2025-07-12\n---------------------\n\nOptimize performance of |st.sampled_from| and internal selection of :ref:`stateful testing <stateful>` rules.\n\n.. _v6.135.28:\n\n---------------------\n6.135.28 - 2025-07-12\n---------------------\n\nOptimize the memory and speed of an internal datastructure for compactly storing integers.\n\n.. _v6.135.27:\n\n---------------------\n6.135.27 - 2025-07-12\n---------------------\n\nImprove thread-safety for stateful |@initialize| rules.\n\n.. _v6.135.26:\n\n---------------------\n6.135.26 - 2025-07-05\n---------------------\n\nFix a \"dictionary changed size during iteration\" error that could occur under with |register_random| under multiple threads.\n\n.. _v6.135.25:\n\n---------------------\n6.135.25 - 2025-07-05\n---------------------\n\nImprove thread safety of our :mod:`sys.monitoring` usage (by the |Phase.shrink| and |Phase.explain| phases), as well as the internal computation of strategy labels.\n\n.. _v6.135.24:\n\n---------------------\n6.135.24 - 2025-07-03\n---------------------\n\nMakes the deprecation warning for using the global random instance thread-safe, as part of our work towards thread safety (:issue:`4451`).\n\n.. _v6.135.23:\n\n---------------------\n6.135.23 - 2025-07-02\n---------------------\n\nIn order to de-flake ``RecursionError`` failures, Hypothesis sets a deterministic limit on ``sys.setrecursionlimit``. This patch makes the setting of this limit aware of uses by Hypothesis from multiple threads, so it does not produce spurious warnings in multithreaded environments.\n\n.. _v6.135.22:\n\n---------------------\n6.135.22 - 2025-07-02\n---------------------\n\nImproves the thread safety of caching strategy definitions, as well as usage of strategy transformations like |.map| and |.filter|.\n\n.. _v6.135.21:\n\n---------------------\n6.135.21 - 2025-07-02\n---------------------\n\nFix the thread safety of |@rule| definitions in |RuleBasedStateMachine|.\n\n.. _v6.135.20:\n\n---------------------\n6.135.20 - 2025-06-30\n---------------------\n\nFixes ``reproduction_decorator`` being missing under :ref:`hypothesis-specific metadata <observability-hypothesis-metadata>` in many :ref:`observability <observability>` observations, when it should have been present.\n\n.. _v6.135.19:\n\n---------------------\n6.135.19 - 2025-06-30\n---------------------\n\nImprove threading compatibility of an internal helper for managing deterministic rng seeding.\n\n.. _v6.135.18:\n\n---------------------\n6.135.18 - 2025-06-30\n---------------------\n\nRemove an internal assertion which could trigger if (1) a lambda was present in the source code of a test, (2) and the source code file was edited on disk between the start of the python process and when Hypothesis runs the property.\n\n.. _v6.135.17:\n\n---------------------\n6.135.17 - 2025-06-30\n---------------------\n\nRefactor some internals related to the shrinker for better compatibility with free-threading (:issue:`4451`).\n\n.. _v6.135.16:\n\n---------------------\n6.135.16 - 2025-06-26\n---------------------\n\nFixes an error when the ``_pytest`` module is present in ``sys.modules``, but *not* the ``_pytest.outcomes`` or ``_pytest.fixtures`` modules. This can happen with code that imports just ``_pytest``, without importing ``pytest``.\n\n.. _v6.135.15:\n\n---------------------\n6.135.15 - 2025-06-25\n---------------------\n\nTemporarily disable the warning when |st.shared| strategies with the same ``key`` draw from different base strategies, due to false alarms. Once we fix the false alarms in a future release, the warning will be re-enabled.\n\n.. _v6.135.14:\n\n---------------------\n6.135.14 - 2025-06-20\n---------------------\n\nSpeed up usages of |st.sampled_from| by deferring evaluation of its repr, and truncating its repr for large collections (over 512 elements). This is especially noticeable when using |st.sampled_from| with large collections. The repr of |st.sampled_from| strategies involving sequence classes with custom reprs may change as a result of this release.\n\n.. _v6.135.13:\n\n---------------------\n6.135.13 - 2025-06-20\n---------------------\n\nFixes a substantial performance regression in stateful tests from computing string representations, present since :ref:`version 6.131.20 <v6.131.20>`.\n\n.. _v6.135.12:\n\n---------------------\n6.135.12 - 2025-06-19\n---------------------\n\nFix a rare race condition in internal cache eviction logic.\n\n.. _v6.135.11:\n\n---------------------\n6.135.11 - 2025-06-17\n---------------------\n\nThis patch fixes an error when importing :ref:`our django extra <hypothesis-django>` (via ``hypothesis.extra.django``) if ``django.contrib.auth`` was not in ``INSTALLED_APPS`` (:issue:`3716`).\n\nThanks to Chris Wesseling for this fix!\n\n.. _v6.135.10:\n\n---------------------\n6.135.10 - 2025-06-15\n---------------------\n\nFix a rare race condition in |ExampleDatabase.fetch|, where we might have read from a non-existent directory.\n\n.. _v6.135.9:\n\n--------------------\n6.135.9 - 2025-06-13\n--------------------\n\nRefactor some internal code related to patches to make it easier to test.\n\n.. _v6.135.8:\n\n--------------------\n6.135.8 - 2025-06-13\n--------------------\n\nAdd type hints to internal code for patching.\n\n.. _v6.135.7:\n\n--------------------\n6.135.7 - 2025-06-12\n--------------------\n\nFixes a race condition in |ExampleDatabase.add_listener| for |DirectoryBasedExampleDatabase| after version :ref:`6.135.1 <v6.135.1>` where the listener might have tried to read a file that doesn't exist.\n\n.. _v6.135.6:\n\n--------------------\n6.135.6 - 2025-06-11\n--------------------\n\nThis patch corrects the f-string formatting of a few array-related error messages.\n\n.. _v6.135.5:\n\n--------------------\n6.135.5 - 2025-06-10\n--------------------\n\nImprove the error message when applying |@given| to a :pypi:`pytest` fixture with pytest 8.4.0.\n\n.. _v6.135.4:\n\n--------------------\n6.135.4 - 2025-06-09\n--------------------\n\nFurther improve the performance of the constants-collection feature introduced in :ref:`version 6.131.1 <v6.131.1>`, by ignoring large files and files with many constants.\n\n.. _v6.135.3:\n\n--------------------\n6.135.3 - 2025-06-08\n--------------------\n\nThis release adds the experimental and unstable |OBSERVABILITY_CHOICES| option for :ref:`observability <observability>`. If set, the choice sequence is included in ``metadata.choice_nodes``, and choice sequence spans are included in ``metadata.choice_spans``.\n\nThese are relatively low-level implementation detail of Hypothesis, and are exposed in observability for users building tools or research on top of Hypothesis. See |PrimitiveProvider| for more details about the choice sequence and choice spans.\n\nWe are actively working towards a better interface for this. Feel free to use |OBSERVABILITY_CHOICES| to experiment, but don't rely on it yet!\n\n.. _v6.135.2:\n\n--------------------\n6.135.2 - 2025-06-08\n--------------------\n\nThis patch restores compatibility when using `the legacy Python 3.9 LL(1)\nparser <https://docs.python.org/3/whatsnew/3.9.html#new-parser>`__ yet\nagain, because the fix in :ref:`version 6.131.33 <v6.131.33>` was too\nbrittle.\n\nThanks to Marco Ricci for this fix!\n\n.. _v6.135.1:\n\n--------------------\n6.135.1 - 2025-06-05\n--------------------\n\n|DirectoryBasedExampleDatabase| now removes empty directories after |ExampleDatabase.delete| is called.\n\n.. _v6.135.0:\n\n--------------------\n6.135.0 - 2025-06-03\n--------------------\n\nThis release adds :func:`~hypothesis.internal.conjecture.provider_conformance.run_conformance_test`, for use in testing implementations of :ref:`alternative backends <alternative-backends>`.\n\n.. _v6.134.0:\n\n--------------------\n6.134.0 - 2025-06-03\n--------------------\n\nThis patch adds :class:`hypothesis.extra.django.SimpleTestCase` (:issue:`4117`)\n\nThanks to Chris Wesseling for this contribution!\n\n.. _v6.133.2:\n\n--------------------\n6.133.2 - 2025-06-03\n--------------------\n\nInternal changes to support `hypofuzz <https://hypofuzz.com>`__.\n\n.. _v6.133.1:\n\n--------------------\n6.133.1 - 2025-06-03\n--------------------\n\nThe ``to_json`` hook used internally when writing :ref:`observability <observability>` reports is now supported on nested dataclasses (in addition to outermost dataclasses).\n\n.. _v6.133.0:\n\n--------------------\n6.133.0 - 2025-06-02\n--------------------\n\nWarn when :func:`~hypothesis.strategies.shared` strategies with the same ``key``\ndraw from different base strategies. This could lead to subtle failures or\nlower-than-expected example coverage.\n\n.. _v6.132.0:\n\n--------------------\n6.132.0 - 2025-05-31\n--------------------\n\nAdd |PrimitiveProvider.on_observation| to the internal :ref:`alternative backends <alternative-backends-internals>` interface.\n\n.. _v6.131.33:\n\n---------------------\n6.131.33 - 2025-05-31\n---------------------\n\nThis patch restores compatibility when using `the legacy Python 3.9 LL(1)\nparser <https://docs.python.org/3/whatsnew/3.9.html#new-parser>`__, which\nwas accidentally broken since :ref:`version 6.130.13 <v6.130.13>`.\n\nThanks to Marco Ricci for this fix!\n\n.. _v6.131.32:\n\n---------------------\n6.131.32 - 2025-05-30\n---------------------\n\n:ref:`fuzz_one_input <fuzz_one_input>` now writes :ref:`observability reports <observability>` if observability is enabled, bringing it in line with the behavior of other standard ways to invoke a Hypothesis test.\n\n.. _v6.131.31:\n\n---------------------\n6.131.31 - 2025-05-30\n---------------------\n\nImprove documentation of |@example|.\n\n.. _v6.131.30:\n\n---------------------\n6.131.30 - 2025-05-27\n---------------------\n\nThis patch resolves a Pandas FutureWarning (:issue:`4400`) caused by indexing with an integer key.\n\n.. _v6.131.29:\n\n---------------------\n6.131.29 - 2025-05-27\n---------------------\n\nThe observations passed to |TESTCASE_CALLBACKS| are now dataclasses, rather than dictionaries. The content written to ``.hypothesis/observed`` under ``HYPOTHESIS_EXPERIMENTAL_OBSERVABILITY`` remains the same.\n\n.. _v6.131.28:\n\n---------------------\n6.131.28 - 2025-05-25\n---------------------\n\nAdd documentation to some internal APIs.\n\n.. _v6.131.27:\n\n---------------------\n6.131.27 - 2025-05-24\n---------------------\n\nAdd ``PrimitiveProvider.replay_choices`` to the :ref:`alternative backends <alternative-backends>` interface, to support warm-starting e.g. :pypi:`hypothesis-crosshair` from :pypi:`hypofuzz`.\n\n.. _v6.131.26:\n\n---------------------\n6.131.26 - 2025-05-24\n---------------------\n\nImprove |ExampleDatabase| documentation.\n\n.. _v6.131.25:\n\n---------------------\n6.131.25 - 2025-05-23\n---------------------\n\nAdd some internal type hints.\n\n.. _v6.131.24:\n\n---------------------\n6.131.24 - 2025-05-23\n---------------------\n\nImprove |@settings| documentation.\n\n.. _v6.131.23:\n\n---------------------\n6.131.23 - 2025-05-23\n---------------------\n\nThis patch adds ``GITLAB_CI`` to the environment variables checked when enabling the default CI |settings| profile.\n\nThanks to Genevieve Mendoza for this contribution!\n\n.. _v6.131.22:\n\n---------------------\n6.131.22 - 2025-05-22\n---------------------\n\nInclude |note| and |Phase.explain| output in the \"representation\" field of :ref:`observability reports <observability>` for failing examples, to more closely match the output produced by Hypothesis.\n\n.. _v6.131.21:\n\n---------------------\n6.131.21 - 2025-05-21\n---------------------\n\n|BackgroundWriteDatabase| instances now defer creating and starting a thread until first use.\n\n.. _v6.131.20:\n\n---------------------\n6.131.20 - 2025-05-20\n---------------------\n\nImprove the string representation of |st.characters| in some cases.\n\n.. _v6.131.19:\n\n---------------------\n6.131.19 - 2025-05-19\n---------------------\n\nCap the length of bytestrings collected as part of the constants-collection feature introduced in :ref:`version 6.131.1 <v6.131.1>`, as long bytestrings are unlikely to be useful.\n\n.. _v6.131.18:\n\n---------------------\n6.131.18 - 2025-05-17\n---------------------\n\nAll |ExampleDatabase| implementations in Hypothesis now implement ``__eq__``.\n\n.. _v6.131.17:\n\n---------------------\n6.131.17 - 2025-05-14\n---------------------\n\nFurther improve the performance of the new features introduced in :ref:`version 6.131.1 <v6.131.1>`, by improving unions of large sets.\n\n.. _v6.131.16:\n\n---------------------\n6.131.16 - 2025-05-13\n---------------------\n\nImprove performance of an internal method to count possible choices.\n\n.. _v6.131.15:\n\n---------------------\n6.131.15 - 2025-05-07\n---------------------\n\nImproves output when assigning values to multiple target bundles\nin a stateful rule (:issue:`4361`).\n\n.. _v6.131.14:\n\n---------------------\n6.131.14 - 2025-05-07\n---------------------\n\nInternal optimization to reduce redundant choice sequence spans.\n\n.. _v6.131.13:\n\n---------------------\n6.131.13 - 2025-05-07\n---------------------\n\nAdd a ``for_failure: bool = False`` parameter to ``provider.realize`` in :ref:`alternative backends <alternative-backends>`, so that symbolic-based backends can increase their timeouts when realizing failures, which are more important than regular examples.\n\n.. _v6.131.12:\n\n---------------------\n6.131.12 - 2025-05-06\n---------------------\n\nImprove type hints for the single-argument form of |st.one_of|. ``st.one_of(strategies)`` now matches the type of ``st.one_of(*strategies)``. For instance, ``st.one_of([st.integers(), st.none()])`` now has the correct type of ``SearchStrategy[int | None]`` instead of ``SearchStrategy[Any]``.\n\n.. _v6.131.11:\n\n---------------------\n6.131.11 - 2025-05-06\n---------------------\n\nFix incorrectly reporting :ref:`alternative backends <alternative-backends>` as unsound in some cases.\n\n.. _v6.131.10:\n\n---------------------\n6.131.10 - 2025-05-06\n---------------------\n\nRemove more false-positive locations from |Phase.explain| output, and add a new ``metadata.reproduction_decorator`` field in :ref:`observability reports <observability>` for failing examples.\n\n.. _v6.131.9:\n\n--------------------\n6.131.9 - 2025-04-25\n--------------------\n\nFix a ``BytesWarning`` after :ref:`version 6.131.1 <v6.131.1>` if the source code used the same value in both a normal and binary string.\n\n.. _v6.131.8:\n\n--------------------\n6.131.8 - 2025-04-23\n--------------------\n\n|DirectoryBasedExampleDatabase| will now fall back to (potentially non-atomic)\ncopies rather than renames, if the temporary directory used for atomic\nwrite-and-rename is on a different filesystem to the configured database\nlocation (:issue:`4335`).\n\n.. _v6.131.7:\n\n--------------------\n6.131.7 - 2025-04-22\n--------------------\n\nFurther improve the performance of the new features introduced in :ref:`version 6.131.1 <v6.131.1>`.\n\n.. _v6.131.6:\n\n--------------------\n6.131.6 - 2025-04-19\n--------------------\n\nThis patch makes the new features introduced in :ref:`version 6.131.1 <v6.131.1>` much\nfaster, and fixes an internal ``RecursionError`` when working with deeply-nested code.\n\n.. _v6.131.5:\n\n--------------------\n6.131.5 - 2025-04-18\n--------------------\n\nFix a rare case where database entries were kept after they were no longer needed when using |Phase.target|.\n\n.. _v6.131.4:\n\n--------------------\n6.131.4 - 2025-04-18\n--------------------\n\nInternal refactoring of the |@settings| object, with no user-visible change.\n\n.. _v6.131.3:\n\n--------------------\n6.131.3 - 2025-04-18\n--------------------\n\nFixes a rare internal error where new code from :ref:`version 6.131.1 <v6.131.1>`\ncould fail if :py:data:`sys.modules` is simultaneously modified, e.g. as a side\neffect of imports executed from another thread.  Our :ref:`thread-safety-policy`\ndoes not promise that this is supported, but we're happy to take reasonable\nfixes.\n\nThanks to Tony Li for reporting and fixing this issue.\n\n.. _v6.131.2:\n\n--------------------\n6.131.2 - 2025-04-17\n--------------------\n\nThe pub-sub change listening interface of the :ref:`Hypothesis database <database>` now correctly fires events for |DirectoryBasedExampleDatabase| if the directory was created after the listener was added.\n\nAlso disables on emscripten the constants-extraction feature introduced in :ref:`v6.131.1`, where it caused substantial slowdown.\n\n.. _v6.131.1:\n\n--------------------\n6.131.1 - 2025-04-17\n--------------------\n\nHypothesis now looks for constant values in the source code of your program, and sometimes uses them while generating examples. This lets Hypothesis generate interesting inputs that are specific to your program.\n\n.. _v6.131.0:\n\n--------------------\n6.131.0 - 2025-04-10\n--------------------\n\nAdd |is_hypothesis_test|, for third-party libraries which want to determine whether a test has been defined with Hypothesis.\n\n.. _v6.130.13:\n\n---------------------\n6.130.13 - 2025-04-09\n---------------------\n\nRefactor some internals.\n\n.. _v6.130.12:\n\n---------------------\n6.130.12 - 2025-04-09\n---------------------\n\nLays some groundwork for future work on collecting interesting literals from the code being tested, for increased bug-finding power (:issue:`3127`). There is no user-visible change (yet!)\n\n.. _v6.130.11:\n\n---------------------\n6.130.11 - 2025-04-08\n---------------------\n\nFix the caching behavior of |st.sampled_from|, which in rare cases led to failing an internal assertion (:issue:`4339`).\n\n.. _v6.130.10:\n\n---------------------\n6.130.10 - 2025-04-07\n---------------------\n\nThis patch deprecates creating a database using the abstract ``ExampleDatabase()`` class. Use one of the following instead:\n\n* Replace ``ExampleDatabase(\":memory:\")`` with |InMemoryExampleDatabase|.\n* Replace ``ExampleDatabase(\"/path/to/dir\")`` with |DirectoryBasedExampleDatabase|.\n* Replace ``ExampleDatabase()`` with either |InMemoryExampleDatabase| or |DirectoryBasedExampleDatabase|, depending on your needs. Previously, Hypothesis interpreted ``ExampleDatabase()`` as a |DirectoryBasedExampleDatabase| in the default ``.hypothesis`` directory, with a fallback to |InMemoryExampleDatabase| if that location was not available.\n\n.. _v6.130.9:\n\n--------------------\n6.130.9 - 2025-04-06\n--------------------\n\nWhen reporting the always-failing, never-passing lines from the |Phase.explain| phase, we now sort the reported lines so that local code shows up first, then third-party library code, then standard library code.\n\n.. _v6.130.8:\n\n--------------------\n6.130.8 - 2025-04-02\n--------------------\n\nImproves the documentation of |settings.Verbosity| objects.\n\n.. _v6.130.7:\n\n--------------------\n6.130.7 - 2025-04-02\n--------------------\n\nRename internal variables for clarity.\n\n.. _v6.130.6:\n\n--------------------\n6.130.6 - 2025-03-31\n--------------------\n\nUpdate the documentation link in |HealthCheck| error messages to their new location in the documentation.\n\n.. _v6.130.5:\n\n--------------------\n6.130.5 - 2025-03-28\n--------------------\n\nImprove our internal type hints.\n\n.. _v6.130.4:\n\n--------------------\n6.130.4 - 2025-03-25\n--------------------\n\nImprove an additional interaction between the :pypi:`hypothesis-crosshair`\n:ref:`backend <alternative-backends>` and :ref:`our observability tools <observability>`.\n\n.. _v6.130.3:\n\n--------------------\n6.130.3 - 2025-03-24\n--------------------\n\nThis patch improves the interaction between the :pypi:`hypothesis-crosshair`\n:ref:`backend <alternative-backends>` and :ref:`our observability tools <observability>`.\n\n.. _v6.130.2:\n\n--------------------\n6.130.2 - 2025-03-22\n--------------------\n\nFix an issue with realizing symbolic values provided by :ref:`alternative backends <alternative-backends>` when Hypothesis encounters an internal error in its engine.\n\n.. _v6.130.1:\n\n--------------------\n6.130.1 - 2025-03-22\n--------------------\n\nImprove the documentation for some strategies, including |st.composite| and |st.data|.\n\n.. _v6.130.0:\n\n--------------------\n6.130.0 - 2025-03-21\n--------------------\n\nNesting :func:`@given <hypothesis.given>` inside of :func:`@given <hypothesis.given>` is now a |HealthCheck| failure. Nesting :func:`@given <hypothesis.given>` results in quadratic generation and shrinking behavior, and can usually be more cleanly expressed by replacing the inner function with a :func:`~hypothesis.strategies.data` parameter on the outer given. For more details, see :obj:`~hypothesis.HealthCheck.nested_given`. (:issue:`4167`)\n\n.. _v6.129.5:\n\n--------------------\n6.129.5 - 2025-03-21\n--------------------\n\nFixes an internal error when certain :ref:`alternative backends <alternative-backends>` find a failure on their very first generated example.\n\n.. _v6.129.4:\n\n--------------------\n6.129.4 - 2025-03-18\n--------------------\n\n:func:`~hypothesis.strategies.nothing` is now typed as ``SearchStrategy[Never]``, because no value can ever be drawn from it. This may help type checkers statically determine that some code is not reachable.\n\n.. _v6.129.3:\n\n--------------------\n6.129.3 - 2025-03-16\n--------------------\n\nThis patch improves the string representation of :func:`~hypothesis.strategies.fixed_dictionaries`.\n\n.. _v6.129.2:\n\n--------------------\n6.129.2 - 2025-03-14\n--------------------\n\nImprove how the shrinker checks for unnecessary work, leading to 10% less time spent shrinking on average, with no reduction in quality.\n\n.. _v6.129.1:\n\n--------------------\n6.129.1 - 2025-03-13\n--------------------\n\n:func:`~hypothesis.strategies.randoms` no longer produces ``1.0``, matching\nthe exclusive upper bound of :obj:`random.Random.random` (:issue:`4297`).\n\n.. _v6.129.0:\n\n--------------------\n6.129.0 - 2025-03-11\n--------------------\n\nThis release adds a ``\"hypothesis-urandom\"`` :ref:`backend <alternative-backends>`, which draws randomness from ``/dev/urandom`` instead of Python's PRNG. This is useful for users of `Antithesis <https://antithesis.com/>`_ who also have Hypothesis tests, allowing Antithesis mutation of ``/dev/urandom`` to drive Hypothesis generation. We expect it to be strictly slower than the default backend for everyone else.\n\nIt can be enabled with ``@settings(backend=\"hypothesis-urandom\")``.\n\n.. _v6.128.3:\n\n--------------------\n6.128.3 - 2025-03-11\n--------------------\n\nFor strategies which draw make recursive draws, including :func:`~hypothesis.strategies.recursive` and :func:`~hypothesis.strategies.deferred`, we now generate examples with duplicated subtrees more often. This tends to uncover interesting behavior in tests.\n\nFor instance, we might now generate a tree like this more often (though the details depend on the strategy):\n\n.. code-block:: none\n\n                 ┌─────┐\n          ┌──────┤  a  ├──────┐\n          │      └─────┘      │\n       ┌──┴──┐             ┌──┴──┐\n       │  b  │             │  a  │\n       └──┬──┘             └──┬──┘\n     ┌────┴────┐         ┌────┴────┐\n  ┌──┴──┐   ┌──┴──┐   ┌──┴──┐   ┌──┴──┐\n  │  c  │   │  d  │   │  b  │   │ ... │\n  └─────┘   └─────┘   └──┬──┘   └─────┘\n                    ┌────┴────┐\n                 ┌──┴──┐   ┌──┴──┐\n                 │  c  │   │  d  │\n                 └─────┘   └─────┘\n\n.. _v6.128.2:\n\n--------------------\n6.128.2 - 2025-03-10\n--------------------\n\nImproves input validation for several strategies in our :ref:`pandas extra\n<hypothesis-pandas>`, so that they raise a helpful ``InvalidArgument`` rather\nthan ``OverflowError``.\n\nDiscovered by our recent :ref:`string generation upgrade <v6.128.0>`.\n\n.. _v6.128.1:\n\n--------------------\n6.128.1 - 2025-03-09\n--------------------\n\nRename a few internal classes for clarity.\n\n.. _v6.128.0:\n\n--------------------\n6.128.0 - 2025-03-09\n--------------------\n\n:func:`~hypothesis.strategies.text` now occasionally generates from a preselected list of strings which are likely to find bugs. These include ligatures, right-to-left and top-to-bottom text, emojis, emoji modifiers, strings like ``\"Infinity\"``, ``\"None\"``, and ``\"FALSE\"``, and other interesting things. This is especially useful when testing the full unicode range, where the search space is too large for uniform sampling to be very effective.\n\nOf course, examples generated this way shrink just like they normally would. It was always possible for Hypothesis to generate these strings; it is just more likely after this change. From the outside, it is as if Hypothesis generated the example completely randomly.\n\nMany thanks to the `Big List of Naughty Strings <https://github.com/minimaxir/big-list-of-naughty-strings>`_, `Text Rendering Hates You <https://faultlore.com/blah/text-hates-you/>`_, and `Text Editing Hates You Too <https://lord.io/text-editing-hates-you-too/>`_ for forming the basis of this list.\n\n.. _v6.127.9:\n\n--------------------\n6.127.9 - 2025-03-06\n--------------------\n\nWe now provide a better string representation for :func:`~hypothesis.strategies.one_of` strategies, by flattening consecutive ``|`` combinations. For instance:\n\n.. code-block:: pycon\n\n    >>> st.integers() | st.text() | st.booleans()\n    # previously: one_of(one_of(integers(), text()), booleans())\n    one_of(integers(), text(), booleans())\n\nExplicit calls to :func:`~hypothesis.strategies.one_of` remain unflattened, in order to make tracking down complicated :func:`~hypothesis.strategies.one_of` constructions easier:\n\n.. code-block:: pycon\n\n    >>> st.one_of(st.integers(), st.one_of(st.text(), st.booleans()))\n    one_of(integers(), one_of(text(), booleans()))\n\nWe print ``one_of`` in reprs (rather than ``integers() | text() | ...``) for consistency with reprs containing ``.filter`` or ``.map`` calls, which uses the full ``one_of`` to avoid ambiguity.\n\n.. _v6.127.8:\n\n--------------------\n6.127.8 - 2025-03-06\n--------------------\n\nThis patch improves shrinking behavior for values from :func:`~hypothesis.strategies.text` and :func:`~hypothesis.strategies.binary` which contain duplicate elements, like ``\"zzzabc\"``. It also improves shrinking for  bugs which require the same character to be drawn from two different :func:`~hypothesis.strategies.text` strategies to trigger.\n\n.. _v6.127.7:\n\n--------------------\n6.127.7 - 2025-03-05\n--------------------\n\nFix a type-hinting regression from :ref:`version 6.125.1 <v6.125.1>`, where we would no longer guarantee the type of the argument to ``.filter`` predicates (:issue:`4269`).\n\n.. code-block:: python\n\n  # x was previously Unknown, but is now correctly guaranteed to be int\n  st.integers().filter(lambda x: x > 0)\n\n.. _v6.127.6:\n\n--------------------\n6.127.6 - 2025-03-04\n--------------------\n\nThis patch tweaks the performance of |Phase.target|, avoiding aborting some test cases when it would be better to finish generating them.\n\n.. _v6.127.5:\n\n--------------------\n6.127.5 - 2025-03-03\n--------------------\n\nThis patch fixes a bug where :func:`~hypothesis.strategies.from_type` would error on certain types involving :class:`~python:typing.Protocol` (:issue:`4194`).\n\n.. _v6.127.4:\n\n--------------------\n6.127.4 - 2025-03-02\n--------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.127.3:\n\n--------------------\n6.127.3 - 2025-02-28\n--------------------\n\nImprove shrinking of non-standard NaN float values (:issue:`4277`).\n\n.. _v6.127.2:\n\n--------------------\n6.127.2 - 2025-02-24\n--------------------\n\nAdjust type hints for the pub-sub database implementation in :ref:`version 6.126.0 <v6.126.0>`, and remove a remnant debug print in its implementation.\n\n.. _v6.127.1:\n\n--------------------\n6.127.1 - 2025-02-23\n--------------------\n\nImprove the clarity of printing counterexamples in :ref:`stateful testing <stateful>`, by avoiding confusing :class:`~hypothesis.stateful.Bundle` references with equivalent values drawn from a regular strategy.\n\nFor example, we now print:\n\n.. code-block:: python\n\n  a_0 = state.add_to_bundle(a=0)\n  state.unrelated(value=0)\n\ninstead of\n\n.. code-block:: python\n\n  a_0 = state.add_to_bundle(a=0)\n  state.unrelated(value=a_0)\n\nif the ``unrelated`` rule draws from a regular strategy such as :func:`~hypothesis.strategies.integers` instead of the ``a`` bundle.\n\n.. _v6.127.0:\n\n--------------------\n6.127.0 - 2025-02-23\n--------------------\n\nThis releases adds support for type aliases created with the :py:keyword:`type` statement (new in python 3.12) to :func:`~hypothesis.strategies.from_type` and :func:`~hypothesis.strategies.register_type_strategy`.\n\n.. _v6.126.0:\n\n--------------------\n6.126.0 - 2025-02-18\n--------------------\n\nThe :ref:`Hypothesis database <database>` now supports a pub-sub interface to efficiently listen for changes in the database, via ``.add_listener`` and ``.remove_listener``. While all databases that ship with Hypothesis support this interface, implementing it is not required for custom database subclasses. Hypothesis will warn when trying to listen on a database without support.\n\nThis feature is currently only used downstream in `hypofuzz <https://github.com/zac-hd/hypofuzz>`_.\n\n.. _v6.125.3:\n\n--------------------\n6.125.3 - 2025-02-11\n--------------------\n\nImproves sharing of some internal cache behavior.\n\n.. _v6.125.2:\n\n--------------------\n6.125.2 - 2025-02-06\n--------------------\n\nOptimize performance (improves speed by ~5%) and clarify the wording in an error message.\n\n.. _v6.125.1:\n\n--------------------\n6.125.1 - 2025-02-03\n--------------------\n\nFixes a bug since around :ref:`version 6.124.4 <v6.124.4>` where we might have generated ``-0.0`` for ``st.floats(min_value=0.0)``, which is unsound.\n\n.. _v6.125.0:\n\n--------------------\n6.125.0 - 2025-02-03\n--------------------\n\nAdd 2024.12 to the list of recognized Array API versions in\n``hypothesis.extra.array_api``.\n\n.. _v6.124.9:\n\n--------------------\n6.124.9 - 2025-02-01\n--------------------\n\nRegistration of experimental :ref:`alternative-backends` is now done via ``hypothesis.internal.conjecture.providers.AVAILABLE_PROVIDERS`` instead of ``hypothesis.internal.conjecture.data.AVAILABLE_PROVIDERS``.\n\n.. _v6.124.8:\n\n--------------------\n6.124.8 - 2025-02-01\n--------------------\n\nRefactor some internals for better type hinting.\n\n.. _v6.124.7:\n\n--------------------\n6.124.7 - 2025-01-25\n--------------------\n\nInternal renamings.\n\n.. _v6.124.6:\n\n--------------------\n6.124.6 - 2025-01-25\n--------------------\n\nMore work on internal type hints.\n\n.. _v6.124.5:\n\n--------------------\n6.124.5 - 2025-01-25\n--------------------\n\nInternal refactoring to make some stateful internals easier to access.\n\n.. _v6.124.4:\n\n--------------------\n6.124.4 - 2025-01-25\n--------------------\n\nRefactoring of our internal input generation. This shouldn't lead to any changes in the distribution of test inputs. If you notice any, please open an issue!\n\n.. _v6.124.3:\n\n--------------------\n6.124.3 - 2025-01-24\n--------------------\n\nSome Hypothesis internals now use the number of choices as a yardstick of input size, rather than the entropy consumed by those choices. We don't expect this to cause significant behavioral changes.\n\n.. _v6.124.2:\n\n--------------------\n6.124.2 - 2025-01-21\n--------------------\n\nImproves our internal caching logic for test cases.\n\n.. _v6.124.1:\n\n--------------------\n6.124.1 - 2025-01-18\n--------------------\n\n:ref:`fuzz_one_input <fuzz_one_input>` is now implemented using an :ref:`alternative backend <alternative-backends>`. This brings the interpretation of the fuzzer-provided bytestring closer to the fuzzer mutations, allowing the mutations to work more reliably. We hope to use this backend functionality to improve fuzzing integration (e.g. `atheris issue #20 <https://github.com/google/atheris/issues/20>`__) in the future!\n\n.. _v6.124.0:\n\n--------------------\n6.124.0 - 2025-01-16\n--------------------\n\nThe :ref:`Hypothesis example database <database>` now uses a new internal format to store examples. This new format is not compatible with the previous format, so stored entries will not carry over.\n\nThe database is best thought of as a cache that may be invalidated at times. Instead of relying on it for correctness, we recommend using :obj:`@example <hypothesis.example>` to specify explicit examples. When using databases across environments (such as connecting a :class:`~hypothesis.database.GitHubArtifactDatabase` database in CI to your local environment), we recommend using the same version of Hypothesis for each where possible, for maximum reproducibility.\n\n.. _v6.123.17:\n\n---------------------\n6.123.17 - 2025-01-13\n---------------------\n\nThis patch improves certain corner cases for reporting of flaky errors\n(:issue:`4183` and :issue:`4228`).\n\n.. _v6.123.16:\n\n---------------------\n6.123.16 - 2025-01-13\n---------------------\n\nImproves an edge case in one of our integer and float shrinking passes.\n\n.. _v6.123.15:\n\n---------------------\n6.123.15 - 2025-01-11\n---------------------\n\nImproves one of our shrinking passes for integers which require a constant relative difference to trigger the bug.\n\n.. _v6.123.14:\n\n---------------------\n6.123.14 - 2025-01-11\n---------------------\n\nAvoid realizing symbolic values from :ref:`alternative-backends` when |Verbosity| is ``verbose`` or higher.\n\n.. _v6.123.13:\n\n---------------------\n6.123.13 - 2025-01-09\n---------------------\n\nMore internal code refactoring.\n\n.. _v6.123.12:\n\n---------------------\n6.123.12 - 2025-01-09\n---------------------\n\n:class:`~hypothesis.database.DirectoryBasedExampleDatabase` now creates files representing database entries atomically, avoiding a very brief intermediary state where a file could be created but not yet written to.\n\n.. _v6.123.11:\n\n---------------------\n6.123.11 - 2025-01-09\n---------------------\n\nInternal code refactoring.\n\n.. _v6.123.10:\n\n---------------------\n6.123.10 - 2025-01-09\n---------------------\n\nFixes a bug caused by :ref:`alternative backends <alternative-backends>` raising ``hypothesis.errors.BackendCannotProceed`` in certain cases.\n\n.. _v6.123.9:\n\n--------------------\n6.123.9 - 2025-01-08\n--------------------\n\nAdd internal type hints to our pretty printer.\n\n.. _v6.123.8:\n\n--------------------\n6.123.8 - 2025-01-08\n--------------------\n\nThe shrinker contains a pass aimed at integers which are required to sum to a value. This patch extends that pass to floats as well.\n\n.. _v6.123.7:\n\n--------------------\n6.123.7 - 2025-01-07\n--------------------\n\nInternal type hint additions and refactorings.\n\n.. _v6.123.6:\n\n--------------------\n6.123.6 - 2025-01-07\n--------------------\n\n:func:`@reproduce_failure() <hypothesis.reproduce_failure>` now uses a newer internal interface to represent failures. As a reminder, this representation is not intended to be stable across versions or with respect to changes in the test.\n\n.. _v6.123.5:\n\n--------------------\n6.123.5 - 2025-01-07\n--------------------\n\nInternal code refactoring for the typed choice sequence (:issue:`3921`). May have some neutral effect on shrinking.\n\n.. _v6.123.4:\n\n--------------------\n6.123.4 - 2025-01-06\n--------------------\n\nThis patch improves shrinking involving long strings or byte sequences whose value is not relevant to the failure.\n\n.. _v6.123.3:\n\n--------------------\n6.123.3 - 2025-01-06\n--------------------\n\nThis release further improves shrinking of strategies using :func:`~hypothesis.strategies.one_of`,\nallowing the shrinker to more reliably move between branches of the strategy.\n\n.. _v6.123.2:\n\n--------------------\n6.123.2 - 2024-12-27\n--------------------\n\nThe shrinker now uses the typed choice sequence (:issue:`3921`) when ordering failing examples. As a result, Hypothesis may now report a different minimal failing example for some tests. We expect most cases to remain unchanged.\n\n.. _v6.123.1:\n\n--------------------\n6.123.1 - 2024-12-24\n--------------------\n\nOur pytest plugin now emits a warning if you set Pytest's ``norecursedirs``\nconfig option in such a way that the ``.hypothesis`` directory would be\nsearched for tests.  This reliably indicates that you've made a mistake\nwhich slows down test collection, usually assuming that your configuration\nextends the set of ignored patterns when it actually replaces them.\n(:issue:`4200`)\n\n.. _v6.123.0:\n\n--------------------\n6.123.0 - 2024-12-23\n--------------------\n\n:func:`~hypothesis.strategies.from_type` can now handle constructors with\nrequired positional-only arguments if they have type annotations.  Previously,\nwe only passed arguments by keyword.\n\n.. _v6.122.7:\n\n--------------------\n6.122.7 - 2024-12-23\n--------------------\n\nThis patch lays some groundwork for migrating our internal representation to the typed choice sequence (:issue:`3921`)\n\n.. _v6.122.6:\n\n--------------------\n6.122.6 - 2024-12-21\n--------------------\n\nThis patch cleans up some internal code around clamping floats.\n\n.. _v6.122.5:\n\n--------------------\n6.122.5 - 2024-12-20\n--------------------\n\nThis release improves shrinking in some cases, especially for strategies using :func:`~hypothesis.strategies.one_of`.\nThis will typically improve shrinking speed and may in some cases improve the end result.\n\n.. _v6.122.4:\n\n--------------------\n6.122.4 - 2024-12-19\n--------------------\n\nThis patch improves generation performance for the provisional :func:`~hypothesis.provisional.domains` strategy, including its derivative strategies :func:`~hypothesis.provisional.urls` and :func:`~hypothesis.strategies.emails`.\n\n.. _v6.122.3:\n\n--------------------\n6.122.3 - 2024-12-08\n--------------------\n\nThis patch improves our error and warning messages.\n\n- Add a warning for ``st.text(\"ascii\")`` - you probably meant ``st.text(st.characters(codec=\"ascii\"))``. Similarly for ``\"utf-8\"``.\n- Recommend remedies in the error message of ``Unsatisfiable``.\n- When ``@given`` errors because it was given an extra keyword argument, and the keyword matches a setting name like ``max_examples``, recommend ``@settings(max_examples=...)`` instead.\n\n.. _v6.122.2:\n\n--------------------\n6.122.2 - 2024-12-08\n--------------------\n\nThis patch updates some outdated external links in our documentation.\n\n.. _v6.122.1:\n\n--------------------\n6.122.1 - 2024-12-01\n--------------------\n\nFix :func:`~hypothesis.strategies.from_type`\non :class:`collections.abc.Callable` returning ``None``.\n\n.. _v6.122.0:\n\n--------------------\n6.122.0 - 2024-11-29\n--------------------\n\nThis release adds ``.span_start()`` and ``.span_end()`` methods\nto our internal ``PrimitiveProvider`` interface, for use by\n:ref:`alternative-backends`.\n\n.. _v6.121.2:\n\n--------------------\n6.121.2 - 2024-11-29\n--------------------\n\nThis patch updates our autoformatting tools, improving our code style without any API changes.\n\n.. _v6.121.1:\n\n--------------------\n6.121.1 - 2024-11-29\n--------------------\n\nThis release brings back the old representation of :class:`hypothesis.stateful.Bundle`, reverting most changes of `PR #4124 <https://github.com/HypothesisWorks/hypothesis/pull/4124>`_.\n\n.. _v6.121.0:\n\n--------------------\n6.121.0 - 2024-11-28\n--------------------\n\nThis release adds :class:`~hypothesis.database.BackgroundWriteDatabase`, a new database backend which defers writes on the wrapped database to a background thread. This allows for low-overhead writes in performance-critical environments like :ref:`fuzz_one_input <fuzz_one_input>`.\n\n.. _v6.120.0:\n\n--------------------\n6.120.0 - 2024-11-27\n--------------------\n\n* This release changes our input distribution for low ``max_examples``. Previously, we capped the size of inputs when generating at least the first 10 inputs, with the reasoning that early inputs to a property should be small. However, this meant properties with ``max_examples=10`` would consistent entirely of small inputs. This patch removes the hard lower bound so that inputs to these properties are more representative of the input space.\n* When a user requests an interactive input via ``strategy.example``, we generate and cache a batch of 100 inputs, returning the first one. This can be expensive for large strategies or when only a few examples are needed. This release improves the speed of ``strategy.example`` by lowering the batch size to 10.\n\n.. _v6.119.4:\n\n--------------------\n6.119.4 - 2024-11-22\n--------------------\n\nThis patch fixes a bug since :ref:`v6.99.13` where only interactively-generated values (via ``data.draw``) would be reported in the ``arguments`` field of our :ref:`observability output <observability>`. Now, all values are reported.\n\n.. _v6.119.3:\n\n--------------------\n6.119.3 - 2024-11-17\n--------------------\n\nHypothesis collects coverage information during the |Phase.shrink| and |Phase.explain| phases in order to show a more informative error message. On 3.12+, this uses :mod:`sys.monitoring`. This patch improves the performance of coverage collection on 3.12+ by disabling events we don't need.\n\n.. _v6.119.2:\n\n--------------------\n6.119.2 - 2024-11-17\n--------------------\n\nThis patch refactors some internals to prepare for future work using our IR (:issue:`3921`).\n\n.. _v6.119.1:\n\n--------------------\n6.119.1 - 2024-11-15\n--------------------\n\nThis patch migrates some more internals (around generating novel inputs) to the IR layer (:issue:`3921`).\n\n.. _v6.119.0:\n\n--------------------\n6.119.0 - 2024-11-15\n--------------------\n\nThis release improves Hypothesis' handling of ExceptionGroup - it's now able to detect marker detections if they're inside a  group and attempts to resolve them. Note that this handling is still a work in progress and might not handle edge cases optimally. Please open issues if you encounter any problems or unexpected behavior with it.\n\n.. _v6.118.9:\n\n--------------------\n6.118.9 - 2024-11-15\n--------------------\n\nInternal refactorings in preparation for upcoming changes.\n\n.. _v6.118.8:\n\n--------------------\n6.118.8 - 2024-11-12\n--------------------\n\nInternal renamings.\n\n.. _v6.118.7:\n\n--------------------\n6.118.7 - 2024-11-10\n--------------------\n\nThis patch removes some ``# type: ignore`` comments following a :pypi:`mypy` update.\n\n.. _v6.118.6:\n\n--------------------\n6.118.6 - 2024-11-10\n--------------------\n\nWhen Hypothesis replays examples from its test database that it knows were previously fully shrunk it will no longer try to shrink them again.\n\nThis should significantly speed up development workflows for slow tests, as the shrinking could contribute a significant delay when rerunning the tests.\n\nIn some rare cases this may cause minor reductions in example quality. This was considered an acceptable tradeoff for the improved test runtime.\n\n.. _v6.118.5:\n\n--------------------\n6.118.5 - 2024-11-10\n--------------------\n\nThis patch avoids computing some string representations we won't need,\ngiving a small speedup (part of :issue:`4139`).\n\n.. _v6.118.4:\n\n--------------------\n6.118.4 - 2024-11-10\n--------------------\n\nThis patch migrates the optimisation algorithm for :ref:`targeted property-based testing <targeted>` to our IR layer (:issue:`3921`). This should result in moderately different (and hopefully improved) exploration behavior in tests which use :func:`hypothesis.target`.\n\n.. _v6.118.3:\n\n--------------------\n6.118.3 - 2024-11-10\n--------------------\n\nThis patch adds more type hints to internal Hypothesis code.\n\n.. _v6.118.2:\n\n--------------------\n6.118.2 - 2024-11-09\n--------------------\n\nThis patch migrates the |Phase.explain| phase to our IR layer (:issue:`3921`). This should improve both its speed and precision.\n\n.. _v6.118.1:\n\n--------------------\n6.118.1 - 2024-11-09\n--------------------\n\nThis patch updates some internals around how we determine an input is too large to finish generating.\n\n.. _v6.118.0:\n\n--------------------\n6.118.0 - 2024-11-08\n--------------------\n\nThe :func:`~hypothesis.provisional.urls` strategy no longer generates\nURLs where the port number is 0.\n\nThis change is motivated by the idea that the generated URLs should, at least in\ntheory, be possible to fetch. The port number 0 is special; if a server binds to\nport 0, the kernel will allocate an unused, and non-zero, port instead. That\nmeans that it's not possible for a server to actually be listening on port 0.\nThis motivation is briefly described in the documentation for\n:func:`~hypothesis.provisional.urls`.\n\nThanks to @gmacon for fixing :issue:`4157`!\n\n.. _v6.117.0:\n\n--------------------\n6.117.0 - 2024-11-07\n--------------------\n\nThis changes the behaviour of settings profiles so that if you reregister the currently loaded profile it will automatically reload it. Previously you would have had to load it again.\n\nIn particular this means that if you register a \"ci\" profile, it will automatically be used when Hypothesis detects you are running on CI.\n\n.. _v6.116.0:\n\n--------------------\n6.116.0 - 2024-11-01\n--------------------\n\nHypothesis now detects if it is running on a CI server and provides better default settings for running on CI in this case.\n\n.. _v6.115.6:\n\n--------------------\n6.115.6 - 2024-10-30\n--------------------\n\nThis patch changes the priority order of pretty printing logic so that a user\nprovided pretty printing method will always be used in preference to e.g.\nprinting it like a dataclass.\n\n.. _v6.115.5:\n\n--------------------\n6.115.5 - 2024-10-23\n--------------------\n\nThis patch restores diversity to the outputs of\n:func:`from_type(type) <hypothesis.strategies.from_type>` (:issue:`4144`).\n\n.. _v6.115.4:\n\n--------------------\n6.115.4 - 2024-10-23\n--------------------\n\nThis release improves pretty printing of nested classes to include the outer class name in their printed representation.\n\n.. _v6.115.3:\n\n--------------------\n6.115.3 - 2024-10-16\n--------------------\n\nThis patch fixes a regression from :ref:`version 6.115.2 <v6.115.2>` where generating values from :func:`~hypothesis.strategies.integers` with certain values for ``min_value`` and ``max_value`` would error.\n\n.. _v6.115.2:\n\n--------------------\n6.115.2 - 2024-10-14\n--------------------\n\nThis release improves integer shrinking by folding the endpoint upweighting for :func:`~hypothesis.strategies.integers` into the ``weights`` parameter of our IR (:issue:`3921`).\n\nIf you maintain an alternative backend as part of our (for now explicitly unstable) :ref:`alternative-backends`, this release changes the type of the ``weights`` parameter to ``draw_integer`` and may be a breaking change for you.\n\n.. _v6.115.1:\n\n--------------------\n6.115.1 - 2024-10-14\n--------------------\n\nThis patch improves the performance of :func:`~hypothesis.strategies.from_type` with\n`pydantic.types.condate <https://docs.pydantic.dev/latest/api/types/#pydantic.types.condate>`__\n(:issue:`4000`).\n\n.. _v6.115.0:\n\n--------------------\n6.115.0 - 2024-10-12\n--------------------\n\nThis improves the formatting of dataclasses and attrs classes when printing\nfalsifying examples.\n\n.. _v6.114.1:\n\n--------------------\n6.114.1 - 2024-10-10\n--------------------\n\nThis patch upgrades remaining type annotations to Python 3.9 syntax.\n\n.. _v6.114.0:\n\n--------------------\n6.114.0 - 2024-10-09\n--------------------\n\nThis release drops support for Python 3.8, `which reached end of life on\n2024-10-07 <https://devguide.python.org/versions/>`__.\n\n.. _v6.113.0:\n\n--------------------\n6.113.0 - 2024-10-09\n--------------------\n\nThis release adds ``hypothesis.errors.BackendCannotProceed``, an unstable API\nfor use by :ref:`alternative-backends`.\n\n.. _v6.112.5:\n\n--------------------\n6.112.5 - 2024-10-08\n--------------------\n\nThis release fixes a regression where :class:`hypothesis.stateful.Bundle` did not work properly with |.flatmap| functionality (:issue:`4128`).\n\n.. _v6.112.4:\n\n--------------------\n6.112.4 - 2024-10-06\n--------------------\n\nThis patch tweaks the paths in ``@example(...)`` patches, so that\nboth ``git apply`` and ``patch`` will work by default.\n\n.. _v6.112.3:\n\n--------------------\n6.112.3 - 2024-10-05\n--------------------\n\nThis release refactors internals of :class:`hypothesis.stateful.Bundle` to have a more consistent representation internally.\n\n.. _v6.112.2:\n\n--------------------\n6.112.2 - 2024-09-29\n--------------------\n\nThis patch fixes an internal error when the ``__context__``\nattribute of a raised exception leads to a cycle (:issue:`4115`).\n\n.. _v6.112.1:\n\n--------------------\n6.112.1 - 2024-09-13\n--------------------\n\nThis patch removes a now-incorrect internal assertion about numpy's typing after recent numpy changes (currently only in numpy's nightly release).\n\n.. _v6.112.0:\n\n--------------------\n6.112.0 - 2024-09-05\n--------------------\n\nThis release adds support for variable-width bytes in our IR layer (:issue:`3921`), which should mean improved performance anywhere you use :func:`~hypothesis.strategies.binary`. If you maintain an alternative backend as part of our (for now explicitly unstable) :ref:`alternative-backends`, this release changes the ``draw_*`` interface and may be a breaking change for you.\n\n.. _v6.111.2:\n\n--------------------\n6.111.2 - 2024-08-24\n--------------------\n\nThis patch contains some internal code cleanup.  There is no user-visible change.\n\n.. _v6.111.1:\n\n--------------------\n6.111.1 - 2024-08-15\n--------------------\n\nThis patch improves shrinking in cases involving 'slips' from one strategy to another. Highly composite strategies are the most likely to benefit from this change.\n\nThis patch also reduces the range of :class:`python:datetime.datetime` generated by :func:`~hypothesis.extra.django.from_model` in order to avoid https://code.djangoproject.com/ticket/35683.\n\n.. _v6.111.0:\n\n--------------------\n6.111.0 - 2024-08-11\n--------------------\n\n:ref:`alternative-backends` can now implement ``.observe_test_case()``\nand ``observe_information_message()`` methods, to record backend-specific\nmetadata and messages in our :ref:`observability output <observability>`\n(:issue:`3845` and `hypothesis-crosshair#22\n<https://github.com/pschanely/hypothesis-crosshair/issues/22>`__).\n\n.. _v6.110.2:\n\n--------------------\n6.110.2 - 2024-08-11\n--------------------\n\nSupport ``__default__`` field of :obj:`~python:typing.TypeVar`\nand support the same from :pypi:`typing-extensions`\nin :func:`~hypothesis.strategies.from_type`.\n\n.. _v6.110.1:\n\n--------------------\n6.110.1 - 2024-08-08\n--------------------\n\nAdd better error message for :obj:`~python:typing.TypeIs` types\nin :func:`~hypothesis.strategies.from_type`.\n\n.. _v6.110.0:\n\n--------------------\n6.110.0 - 2024-08-07\n--------------------\n\nSupport :obj:`~python:typing.LiteralString`\nin :func:`~hypothesis.strategies.from_type`.\n\n.. _v6.109.1:\n\n--------------------\n6.109.1 - 2024-08-07\n--------------------\n\nThis patch makes progress towards adding type hints to our internal conjecture engine (:issue:`3074`).\n\n.. _v6.109.0:\n\n--------------------\n6.109.0 - 2024-08-07\n--------------------\n\nThis release allows using :obj:`~python:typing.Annotated`\nand :obj:`!ReadOnly` types\nfor :obj:`~python:typing.TypedDict` value types\nwith :func:`~hypothesis.strategies.from_type`.\n\n.. _v6.108.10:\n\n---------------------\n6.108.10 - 2024-08-06\n---------------------\n\nThis patch fixes compatibility with :pypi:`attrs==24.1.0 <attrs>`\non the nightly build of CPython, 3.14.0 pre-alpha (:issue:`4067`).\n\n.. _v6.108.9:\n\n--------------------\n6.108.9 - 2024-08-05\n--------------------\n\nThis patch removes an assertion which was in fact possible in rare circumstances involving a small number of very large draws.\n\n.. _v6.108.8:\n\n--------------------\n6.108.8 - 2024-08-04\n--------------------\n\nThis patch improves our example generation performance by adjusting our internal cache implementation.\n\n.. _v6.108.7:\n\n--------------------\n6.108.7 - 2024-08-04\n--------------------\n\nThis patch improves our pretty-printer for unusual numbers.\n\n- Signalling NaNs are now represented by using the :mod:`struct` module\n  to show the exact value by converting from a hexadecimal integer\n\n- CPython `limits integer-to-string conversions\n  <https://docs.python.org/3/library/stdtypes.html#integer-string-conversion-length-limitation>`__\n  to mitigate DDOS attacks.  We now use hexadecimal for very large\n  integers, and include underscore separators for integers with ten\n  or more digits.\n\n.. _v6.108.6:\n\n--------------------\n6.108.6 - 2024-08-04\n--------------------\n\nThis patch improves generation speed in some cases by avoiding pretty-printing overhead for non-failing examples.\n\n.. _v6.108.5:\n\n--------------------\n6.108.5 - 2024-07-28\n--------------------\n\nThis patch fixes a rare internal error when using :func:`~hypothesis.strategies.integers` with a high number of examples and certain ``{min, max}_value`` parameters (:pull:`4059`).\n\n.. _v6.108.4:\n\n--------------------\n6.108.4 - 2024-07-22\n--------------------\n\nThis patch addresses the issue of hypothesis potentially accessing\nmocked ``time.perf_counter`` during test execution (:issue:`4051`).\n\n.. _v6.108.3:\n\n--------------------\n6.108.3 - 2024-07-22\n--------------------\n\nMinor internal-only cleanups to some error-handling and reporting code.\n\n.. _v6.108.2:\n\n--------------------\n6.108.2 - 2024-07-15\n--------------------\n\nThis patch disables :func:`hypothesis.target` on alternative\nbackends where it would not work.\n\n.. _v6.108.1:\n\n--------------------\n6.108.1 - 2024-07-14\n--------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.108.0:\n\n--------------------\n6.108.0 - 2024-07-13\n--------------------\n\nThis patch changes most ``Flaky`` errors to use an :class:`ExceptionGroup`, which\nmakes the representation of these errors easier to understand.\n\n.. _v6.107.0:\n\n--------------------\n6.107.0 - 2024-07-13\n--------------------\n\nThe ``alphabet=`` argument to :func:`~hypothesis.strategies.from_regex`\nnow accepts unions of :func:`~hypothesis.strategies.characters` and\n:func:`~hypothesis.strategies.sampled_from` strategies, in addition to\naccepting each individually.\n\nThis patch also fixes a bug where ``text(...).filter(re.compile(...).match)``\ncould generate non-matching instances if the regex pattern contained ``|``\n(:issue:`4008`).\n\n.. _v6.106.1:\n\n--------------------\n6.106.1 - 2024-07-12\n--------------------\n\nThis patch improves our pretty-printer (:issue:`4037`).\n\nIt also fixes the codemod for ``HealthCheck.all()`` from\n:ref:`version 6.72 <v6.72.0>`, which was instead trying to\nfix ``Healthcheck.all()`` - note the lower-case ``c``!\nSince our tests had the same typo, it all looked good...\nuntil :issue:`4030`.\n\n.. _v6.106.0:\n\n--------------------\n6.106.0 - 2024-07-12\n--------------------\n\nThis release improves support for unions of :pypi:`numpy` dtypes such as\n``np.float64 | np.complex128`` in :func:`~hypothesis.strategies.from_type`\nand :func:`~hypothesis.extra.numpy.arrays` (:issue:`4041`).\n\n.. _v6.105.2:\n\n--------------------\n6.105.2 - 2024-07-12\n--------------------\n\nThis patch improves the reporting of certain flaky errors.\n\n.. _v6.105.1:\n\n--------------------\n6.105.1 - 2024-07-07\n--------------------\n\nThis patch iterates on our experimental support for alternative backends (:ref:`alternative-backends`). See :pull:`4029` for details.\n\n.. _v6.105.0:\n\n--------------------\n6.105.0 - 2024-07-04\n--------------------\n\nThis release improves support for Django 5.0, and drops support for end-of-life Django versions (< 4.2).\n\nThanks to Joshua Munn for this contribution.\n\n.. _v6.104.4:\n\n--------------------\n6.104.4 - 2024-07-04\n--------------------\n\nClean up internal cache implementation.\n\n.. _v6.104.3:\n\n--------------------\n6.104.3 - 2024-07-04\n--------------------\n\nThis patch updates our autoformatting tools, improving our code style without any API changes.\n\n.. _v6.104.2:\n\n--------------------\n6.104.2 - 2024-06-29\n--------------------\n\nThis patch fixes an issue when realizing symbolics with our experimental :obj:`~hypothesis.settings.backend` setting.\n\n.. _v6.104.1:\n\n--------------------\n6.104.1 - 2024-06-25\n--------------------\n\nImproves internal test coverage.\n\n.. _v6.104.0:\n\n--------------------\n6.104.0 - 2024-06-24\n--------------------\n\nThis release adds strategies for Django's ``ModelChoiceField`` and\n``ModelMultipleChoiceField`` (:issue:`4010`).\n\nThanks to Joshua Munn for this contribution.\n\n.. _v6.103.5:\n\n--------------------\n6.103.5 - 2024-06-24\n--------------------\n\nFixes and reinstates full coverage of internal tests, which was accidentally\ndisabled in :pull:`3935` (:issue:`4003`).\n\n.. _v6.103.4:\n\n--------------------\n6.103.4 - 2024-06-24\n--------------------\n\nThis release prevents a race condition inside internal cache implementation.\n\n.. _v6.103.3:\n\n--------------------\n6.103.3 - 2024-06-24\n--------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.103.2:\n\n--------------------\n6.103.2 - 2024-06-14\n--------------------\n\nThis patch improves our deduplication tracking across all strategies (:pull:`4007`). Hypothesis is now less likely to generate the same input twice.\n\n.. _v6.103.1:\n\n--------------------\n6.103.1 - 2024-06-05\n--------------------\n\nAccount for time spent in garbage collection during tests, to avoid\nflaky ``DeadlineExceeded`` errors as seen in :issue:`3975`.\n\nAlso fixes overcounting of stateful run times,\na minor observability bug dating to :ref:`version 6.98.9 <v6.98.9>`\n(:pull:`3890`).\n\n.. _v6.103.0:\n\n--------------------\n6.103.0 - 2024-05-29\n--------------------\n\nThis release migrates the shrinker to our new internal representation, called the IR layer (:pull:`3962`). This improves the shrinker's performance in the majority of cases. For example, on the Hypothesis test suite, shrinking is a median of 1.38x faster.\n\nIt is possible this release regresses performance while shrinking certain strategies. If you encounter strategies which reliably shrink more slowly than they used to (or shrink slowly at all), please open an issue!\n\nYou can read more about the IR layer at :issue:`3921`.\n\n.. _v6.102.6:\n\n--------------------\n6.102.6 - 2024-05-23\n--------------------\n\nThis patch fixes one of our shrinking passes getting into a rare ``O(n)`` case instead of ``O(log(n))``.\n\n.. _v6.102.5:\n\n--------------------\n6.102.5 - 2024-05-22\n--------------------\n\nThis patch fixes some introspection errors new in Python 3.11.9 and\n3.13.0b1, for the Ghostwriter and :func:`~hypothesis.strategies.from_type`.\n\n.. _v6.102.4:\n\n--------------------\n6.102.4 - 2024-05-15\n--------------------\n\nInternal developer documentation, no user-visible changes.\n\n.. _v6.102.3:\n\n--------------------\n6.102.3 - 2024-05-15\n--------------------\n\nThis patch improves our shrinking of unique collections, such as  :func:`~hypothesis.strategies.dictionaries`,\n:func:`~hypothesis.strategies.sets`, and :func:`~hypothesis.strategies.lists` with ``unique=True``.\n\n.. _v6.102.2:\n\n--------------------\n6.102.2 - 2024-05-15\n--------------------\n\nThis patch fixes a rare internal error when generating very large elements from strategies (:issue:`3874`).\n\n.. _v6.102.1:\n\n--------------------\n6.102.1 - 2024-05-13\n--------------------\n\nThis patch fixes an overly strict internal type assertion.\n\n.. _v6.102.0:\n\n--------------------\n6.102.0 - 2024-05-13\n--------------------\n\nThis release improves our support for the :pypi:`annotated-types` iterable\n``GroupedMetadata`` protocol.  In order to treat the elements \"as if they\nhad been unpacked\", if one such element is a :class:`~hypothesis.strategies.SearchStrategy`\nwe now resolve to that strategy.  Previously, we treated this as an unknown\nfilter predicate.\n\nWe expect this to be useful for libraries implementing custom metadata -\ninstead of requiring downstream integration, they can implement the protocol\nand yield a lazily-created strategy.  Doing so only if Hypothesis is in\n:obj:`sys.modules` gives powerful integration with no runtime overhead\nor extra dependencies.\n\n.. _v6.101.0:\n\n--------------------\n6.101.0 - 2024-05-13\n--------------------\n\nThe :func:`~hypothesis.extra.django.from_model` function currently\ntries to create a strategy for :obj:`~django:django.db.models.AutoField`\nfields if they don't have :attr:`~django:django.db.models.Field.auto_created`\nset to `True`.  The docs say it's supposed to skip all\n:obj:`~django:django.db.models.AutoField` fields, so this patch updates\nthe code to do what the docs say (:issue:`3978`).\n\n.. _v6.100.8:\n\n--------------------\n6.100.8 - 2024-05-13\n--------------------\n\nThis patch adds some internal type annotations (:issue:`3074`).\nThanks to Andrew Sansom for his contribution!\n\n.. _v6.100.7:\n\n--------------------\n6.100.7 - 2024-05-12\n--------------------\n\nThis patch fixes a rare internal error when using :func:`~hypothesis.strategies.integers` with a high ``max_examples`` setting (:issue:`3974`).\n\n.. _v6.100.6:\n\n--------------------\n6.100.6 - 2024-05-10\n--------------------\n\nThis patch improves our internal caching logic. We don't expect it to result in any performance improvements (yet!).\n\n.. _v6.100.5:\n\n--------------------\n6.100.5 - 2024-05-06\n--------------------\n\nThis patch turns off a check in :func:`~hypothesis.register_random` for possibly\nunreferenced RNG instances on the free-threaded build of CPython 3.13 because\nthis check has a much higher false positive rate in the free-threaded build\n(:issue:`3965`).\n\nThanks to Nathan Goldbaum for this patch.\n\n.. _v6.100.4:\n\n--------------------\n6.100.4 - 2024-05-05\n--------------------\n\nThis patch turns off a warning for functions decorated with\n:func:`typing.overload` and then :func:`~hypothesis.strategies.composite`,\nalthough only in that order (:issue:`3970`).\n\n.. _v6.100.3:\n\n--------------------\n6.100.3 - 2024-05-04\n--------------------\n\nThis patch fixes a significant slowdown when using the :func:`~hypothesis.stateful.precondition` decorator in some cases, due to expensive repr formatting internally (:issue:`3963`).\n\n.. _v6.100.2:\n\n--------------------\n6.100.2 - 2024-04-28\n--------------------\n\nExplicitly cast :obj:`numpy.finfo.smallest_normal <numpy.finfo>` to builtin `float` in\npreparation for the :pypi:`numpy==2.0 <numpy>` release (:issue:`3950`)\n\n.. _v6.100.1:\n\n--------------------\n6.100.1 - 2024-04-08\n--------------------\n\nThis patch improve a rare error message for flaky tests (:issue:`3940`).\n\n.. _v6.100.0:\n\n--------------------\n6.100.0 - 2024-03-31\n--------------------\n\nThe :func:`~hypothesis.extra.numpy.from_dtype` function no longer generates\n``NaT`` (\"not-a-time\") values for the ``datetime64`` or ``timedelta64`` dtypes\nif passed ``allow_nan=False`` (:issue:`3943`).\n\n.. _v6.99.13:\n\n--------------------\n6.99.13 - 2024-03-24\n--------------------\n\nThis patch includes the :obj:`~hypothesis.settings.backend` setting in the\n``how_generated`` field of our :ref:`observability output <observability>`.\n\n.. _v6.99.12:\n\n--------------------\n6.99.12 - 2024-03-23\n--------------------\n\nIf you were running Python 3.13 (currently in alpha) with :pypi:`pytest-xdist`\nand then attempted to pretty-print a ``lambda`` functions which was created\nusing the :func:`eval` builtin, it would have raised an AssertionError.\nNow you'll get ``\"lambda ...: <unknown>\"``, as expected.\n\n.. _v6.99.11:\n\n--------------------\n6.99.11 - 2024-03-20\n--------------------\n\nThis release improves an internal invariant.\n\n.. _v6.99.10:\n\n--------------------\n6.99.10 - 2024-03-20\n--------------------\n\nThis patch fixes Hypothesis sometimes raising a ``Flaky`` error when generating collections of unique floats containing ``nan``. See :issue:`3926` for more details.\n\n.. _v6.99.9:\n\n-------------------\n6.99.9 - 2024-03-19\n-------------------\n\nThis patch continues our work on refactoring the shrinker (:issue:`3921`).\n\n.. _v6.99.8:\n\n-------------------\n6.99.8 - 2024-03-18\n-------------------\n\nThis patch continues our work on refactoring shrinker internals (:issue:`3921`).\n\n.. _v6.99.7:\n\n-------------------\n6.99.7 - 2024-03-18\n-------------------\n\nThis release resolves :py:exc:`PermissionError` that come from\ncreating databases on inaccessible paths.\n\n.. _v6.99.6:\n\n-------------------\n6.99.6 - 2024-03-14\n-------------------\n\nThis patch starts work on refactoring our shrinker internals. There is no user-visible change.\n\n.. _v6.99.5:\n\n-------------------\n6.99.5 - 2024-03-12\n-------------------\n\nThis patch fixes a longstanding performance problem in stateful testing (:issue:`3618`),\nwhere state machines which generated a substantial amount of input for each step would\nhit the maximum amount of entropy and then fail with an ``Unsatisfiable`` error.\n\nWe now stop taking additional steps when we're approaching the entropy limit,\nwhich neatly resolves the problem without touching unaffected tests.\n\n.. _v6.99.4:\n\n-------------------\n6.99.4 - 2024-03-11\n-------------------\n\nFix regression caused by using :pep:`696` default in TypeVar with Python 3.13.0a3.\n\n.. _v6.99.3:\n\n-------------------\n6.99.3 - 2024-03-11\n-------------------\n\nThis patch further improves the type annotations in :mod:`hypothesis.extra.numpy`.\n\n.. _v6.99.2:\n\n-------------------\n6.99.2 - 2024-03-10\n-------------------\n\nSimplify the type annotation of :func:`~hypothesis.extra.pandas.column` and\n:func:`~hypothesis.extra.pandas.columns` by using :pep:`696` to avoid overloading.\n\n.. _v6.99.1:\n\n-------------------\n6.99.1 - 2024-03-10\n-------------------\n\nThis patch implements type annotations for :func:`~hypothesis.extra.pandas.column`.\n\n.. _v6.99.0:\n\n-------------------\n6.99.0 - 2024-03-09\n-------------------\n\nThis release adds the **experimental and unstable** :obj:`~hypothesis.settings.backend`\nsetting.  See :ref:`alternative-backends` for details.\n\n.. _v6.98.18:\n\n--------------------\n6.98.18 - 2024-03-09\n--------------------\n\nThis patch fixes :issue:`3900`, a performance regression for\n:func:`~hypothesis.extra.numpy.arrays` due to the interaction of\n:ref:`v6.98.12` and :ref:`v6.97.1`.\n\n.. _v6.98.17:\n\n--------------------\n6.98.17 - 2024-03-04\n--------------------\n\nThis patch improves the type annotations in :mod:`hypothesis.extra.numpy`,\nwhich makes inferred types more precise for both :pypi:`mypy` and\n:pypi:`pyright`, and fixes some strict-mode errors on the latter.\n\nThanks to Jonathan Plasse for reporting and fixing this in :pull:`3889`!\n\n.. _v6.98.16:\n\n--------------------\n6.98.16 - 2024-03-04\n--------------------\n\nThis patch paves the way for future shrinker improvements. There is no user-visible change.\n\n.. _v6.98.15:\n\n--------------------\n6.98.15 - 2024-02-29\n--------------------\n\nThis release adds support for the Array API's `2023.12 release\n<https://data-apis.org/array-api/2023.12/>`_ via the ``api_version`` argument in\n:func:`~hypothesis.extra.array_api.make_strategies_namespace`. The API additions\nand modifications in the ``2023.12`` spec do not necessitate any changes in the\nHypothesis strategies, hence there is no distinction between a ``2022.12`` and\n``2023.12`` strategies namespace.\n\n.. _v6.98.14:\n\n--------------------\n6.98.14 - 2024-02-29\n--------------------\n\nThis patch adjusts the printing of bundle values to correspond\nwith their names when using stateful testing.\n\n.. _v6.98.13:\n\n--------------------\n6.98.13 - 2024-02-27\n--------------------\n\nThis patch implements filter-rewriting for :func:`~hypothesis.strategies.text`\nand :func:`~hypothesis.strategies.binary` with the :meth:`~re.Pattern.search`,\n:meth:`~re.Pattern.match`, or :meth:`~re.Pattern.fullmatch` method of a\n:func:`re.compile`\\ d regex.\n\n.. _v6.98.12:\n\n--------------------\n6.98.12 - 2024-02-25\n--------------------\n\nThis patch implements filter-rewriting for most length filters on some\nadditional collection types (:issue:`3795`), and fixes several latent\nbugs where unsatisfiable or partially-infeasible rewrites could trigger\ninternal errors.\n\n.. _v6.98.11:\n\n--------------------\n6.98.11 - 2024-02-24\n--------------------\n\nThis patch makes stateful testing somewhat less likely to get stuck\nwhen there are only a few possible rules.\n\n.. _v6.98.10:\n\n--------------------\n6.98.10 - 2024-02-22\n--------------------\n\nThis patch :pep:`adds a note <678>` to errors which occur while drawing from\na strategy, to make it easier to tell why your test failed in such cases.\n\n.. _v6.98.9:\n\n-------------------\n6.98.9 - 2024-02-20\n-------------------\n\nThis patch ensures that :ref:`observability <observability>` outputs include\nan informative repr for :class:`~hypothesis.stateful.RuleBasedStateMachine`\nstateful tests, along with more detailed timing information.\n\n.. _v6.98.8:\n\n-------------------\n6.98.8 - 2024-02-18\n-------------------\n\nThis patch improves :ref:`the Ghostwriter <ghostwriter>` for binary operators.\n\n.. _v6.98.7:\n\n-------------------\n6.98.7 - 2024-02-18\n-------------------\n\nThis patch improves import-detection in :ref:`the Ghostwriter <ghostwriter>`\n(:issue:`3884`), particularly for :func:`~hypothesis.strategies.from_type`\nand strategies from ``hypothesis.extra.*``.\n\n.. _v6.98.6:\n\n-------------------\n6.98.6 - 2024-02-15\n-------------------\n\nThis patch clarifies the documentation on stateful testing (:issue:`3511`).\n\n.. _v6.98.5:\n\n-------------------\n6.98.5 - 2024-02-14\n-------------------\n\nThis patch improves argument-to-json conversion for :ref:`observability <observability>`\noutput.  Checking for a ``.to_json()`` method on the object *before* a few other\noptions like dataclass support allows better user control of the process (:issue:`3880`).\n\n.. _v6.98.4:\n\n-------------------\n6.98.4 - 2024-02-12\n-------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.98.3:\n\n-------------------\n6.98.3 - 2024-02-08\n-------------------\n\nThis patch fixes an error when generating :ref:`observability <observability>` reports involving large (``n > 1e308``) integers.\n\n.. _v6.98.2:\n\n-------------------\n6.98.2 - 2024-02-05\n-------------------\n\nThis patch refactors some internals. There is no user-visible change.\n\n.. _v6.98.1:\n\n-------------------\n6.98.1 - 2024-02-05\n-------------------\n\nThis release improves our distribution of generated values for all strategies, by doing a better job of tracking which values we have generated before and avoiding generating them again.\n\nFor example, ``st.lists(st.integers())`` previously generated ~5 each of ``[]`` ``[0]`` in 100 examples. In this release, each of ``[]`` and ``[0]`` are generated ~1-2 times each.\n\n.. _v6.98.0:\n\n-------------------\n6.98.0 - 2024-02-05\n-------------------\n\nThis release deprecates use of the global random number generator while drawing\nfrom a strategy, because this makes test cases less diverse and prevents us\nfrom reporting minimal counterexamples (:issue:`3810`).\n\nIf you see this new warning, you can get a quick fix by using\n:func:`~hypothesis.strategies.randoms`; or use more idiomatic strategies\n:func:`~hypothesis.strategies.sampled_from`, :func:`~hypothesis.strategies.floats`,\n:func:`~hypothesis.strategies.integers`, and so on.\n\nNote that the same problem applies to e.g. ``numpy.random``, but\nfor performance reasons we only check the stdlib :mod:`random` module -\nignoring even other sources passed to :func:`~hypothesis.register_random`.\n\n.. _v6.97.6:\n\n-------------------\n6.97.6 - 2024-02-04\n-------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.97.5:\n\n-------------------\n6.97.5 - 2024-02-03\n-------------------\n\nThis patch adds some :ref:`observability information <observability>`\nabout how many times predicates in :func:`~hypothesis.assume` or\n:func:`~hypothesis.stateful.precondition` were satisfied, so that\ndownstream tools can warn you if some were *never* satisfied by\nany test case.\n\n.. _v6.97.4:\n\n-------------------\n6.97.4 - 2024-01-31\n-------------------\n\nThis patch improves formatting and adds some cross-references to our docs.\n\n.. _v6.97.3:\n\n-------------------\n6.97.3 - 2024-01-30\n-------------------\n\nInternal test refactoring.\n\n.. _v6.97.2:\n\n-------------------\n6.97.2 - 2024-01-30\n-------------------\n\nThis patch slightly changes how we replay examples from\n:ref:`the database <database>`: if the behavior of the saved example has\nchanged, we now keep running the test case instead of aborting at the size\nof the saved example.  While we know it's not the *same* example, we might\nas well continue running the test!\n\nBecause we now finish running a few more examples for affected tests, this\nmight be a slight slowdown - but correspondingly more likely to find a bug.\n\nWe've also applied similar tricks to the |Phase.target| phase, where\nthey are a pure performance improvement for affected tests.\n\n.. _v6.97.1:\n\n-------------------\n6.97.1 - 2024-01-27\n-------------------\n\nImproves the performance of the :func:`~hypothesis.extra.numpy.arrays`\nstrategy when generating unique values.\n\n.. _v6.97.0:\n\n-------------------\n6.97.0 - 2024-01-25\n-------------------\n\nChanges the distribution of :func:`~hypothesis.strategies.sampled_from` when\nsampling from a :class:`~python:enum.Flag`. Previously, no-flags-set values would\nnever be generated, and all-flags-set values would be unlikely for large enums.\nWith this change, the distribution is more uniform in the number of flags set.\n\n.. _v6.96.4:\n\n-------------------\n6.96.4 - 2024-01-23\n-------------------\n\nThis patch slightly refactors some internals. There is no user-visible change.\n\n.. _v6.96.3:\n\n-------------------\n6.96.3 - 2024-01-22\n-------------------\n\nThis patch fixes a spurious warning about slow imports when ``HYPOTHESIS_EXPERIMENTAL_OBSERVABILITY`` was set.\n\n.. _v6.96.2:\n\n-------------------\n6.96.2 - 2024-01-21\n-------------------\n\nThis patch refactors some more internals, continuing our work on supporting alternative backends (:issue:`3086`). There is no user-visible change.\n\n.. _v6.96.1:\n\n-------------------\n6.96.1 - 2024-01-18\n-------------------\n\nFix a spurious warning seen when running pytest's test\nsuite, caused by never realizing we got out of\ninitialization due to imbalanced hook calls.\n\n.. _v6.96.0:\n\n-------------------\n6.96.0 - 2024-01-17\n-------------------\n\nWarns when constructing a `repr` that is overly long. This can\nhappen by accident if stringifying arbitrary strategies, and\nis expensive in time and memory. The associated deferring of\nthese long strings in :func:`~hypothesis.strategies.sampled_from`\nshould also lead to improved performance.\n\n.. _v6.95.0:\n\n-------------------\n6.95.0 - 2024-01-17\n-------------------\n\nThis release adds the ability to pass any object to :func:`~hypothesis.note`, instead of just strings. The pretty-printed representation of the object will be used.\n\nSee also :issue:`3843`.\n\n.. _v6.94.0:\n\n-------------------\n6.94.0 - 2024-01-16\n-------------------\n\nThis release avoids creating a ``.hypothesis`` directory when using\n:func:`~hypothesis.strategies.register_type_strategy` (:issue:`3836`),\nand adds warnings for plugins which do so by other means or have\nother unintended side-effects.\n\n.. _v6.93.2:\n\n-------------------\n6.93.2 - 2024-01-15\n-------------------\n\nThis patch improves :ref:`observability <observability>` reports by moving\ntiming information from ``metadata`` to a new ``timing`` key, and supporting\nconversion of additional argument types to json rather than string reprs\nvia a ``.to_json()`` method (including e.g. Pandas dataframes).\n\nAdditionally, the :obj:`~hypothesis.HealthCheck.too_slow` health check will\nnow report *which* strategies were slow, e.g. for strategies a, b, c, ...::\n\n        count | fraction |    slowest draws (seconds)\n    a |    3  |     65%  |      --      --      --   0.357,  2.000\n    b |    8  |     16%  |   0.100,  0.100,  0.100,  0.111,  0.123\n    c |    3  |      8%  |      --      --   0.030,  0.050,  0.200\n    (skipped 2 rows of fast draws)\n\n.. _v6.93.1:\n\n-------------------\n6.93.1 - 2024-01-15\n-------------------\n\nThis patch refactors some internals, continuing our work on supporting alternative backends\n(:issue:`3086`). There is no user-visible change.\n\n.. _v6.93.0:\n\n-------------------\n6.93.0 - 2024-01-13\n-------------------\n\nThe :func:`~hypothesis.extra.lark.from_lark` strategy now accepts an ``alphabet=``\nargument, which is passed through to :func:`~hypothesis.strategies.from_regex`,\nso that you can e.g. constrain the generated strings to a particular codec.\n\nIn support of this feature, :func:`~hypothesis.strategies.from_regex` will avoid\ngenerating optional parts which do not fit the alphabet.  For example,\n``from_regex(r\"abc|def\", alphabet=\"abcd\")`` was previously an error, and will now\ngenerate only ``'abc'``.  Cases where there are no valid strings remain an error.\n\n.. _v6.92.9:\n\n-------------------\n6.92.9 - 2024-01-12\n-------------------\n\nThis patch refactors some internals, continuing our work on supporting alternative backends (:issue:`3086`). There is no user-visible change.\n\n.. _v6.92.8:\n\n-------------------\n6.92.8 - 2024-01-11\n-------------------\n\nThis patch adds a :ref:`test statistics <statistics>` event when a generated example is rejected via :func:`assume <hypothesis.assume>`.\n\nThis may also help with distinguishing ``gave_up`` examples in :ref:`observability <observability>` (:issue:`3827`).\n\n.. _v6.92.7:\n\n-------------------\n6.92.7 - 2024-01-10\n-------------------\n\nThis introduces the rewriting of length filters on some collection strategies (:issue:`3791`).\n\nThanks to Reagan Lee for implementing this feature!\n\n.. _v6.92.6:\n\n-------------------\n6.92.6 - 2024-01-08\n-------------------\n\nIf a test uses :func:`~hypothesis.strategies.sampled_from` on a sequence of\nstrategies, and raises a ``TypeError``, we now :pep:`add a note <678>` asking\nwhether you meant to use :func:`~hypothesis.strategies.one_of`.\n\nThanks to Vince Reuter for suggesting and implementing this hint!\n\n.. _v6.92.5:\n\n-------------------\n6.92.5 - 2024-01-08\n-------------------\n\nThis patch registers explicit strategies for a handful of builtin types,\nmotivated by improved introspection in PyPy 7.3.14 triggering existing\ninternal warnings.\nThanks to Carl Friedrich Bolz-Tereick for helping us work out what changed!\n\n.. _v6.92.4:\n\n-------------------\n6.92.4 - 2024-01-08\n-------------------\n\nThis patch fixes an error when writing :ref:`observability <observability>` reports without a pre-existing ``.hypothesis`` directory.\n\n.. _v6.92.3:\n\n-------------------\n6.92.3 - 2024-01-08\n-------------------\n\nThis patch adds a new environment variable ``HYPOTHESIS_EXPERIMENTAL_OBSERVABILITY_NOCOVER``,\nwhich turns on :ref:`observability <observability>` data collection without collecting\ncode coverage data, which may be faster on Python 3.11 and earlier.\n\nThanks to Harrison Goldstein for reporting and fixing :issue:`3821`.\n\n.. _v6.92.2:\n\n-------------------\n6.92.2 - 2023-12-27\n-------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.92.1:\n\n-------------------\n6.92.1 - 2023-12-16\n-------------------\n\nThis patch fixes a bug introduced in :ref:`version 6.92.0 <v6.92.0>`,\nwhere using the :func:`~hypothesis.strategies.data` strategy would fail\nto draw a :func:`~python:dataclasses.dataclass` with a\n:class:`~python:collections.defaultdict` field.  This was due to a bug\nin the standard library which `was fixed in 3.12\n<https://github.com/python/cpython/pull/32056>`__, so we've vendored the fix.\n\n.. _v6.92.0:\n\n-------------------\n6.92.0 - 2023-12-10\n-------------------\n\nThis release adds an experimental :wikipedia:`observability <Observability_(software)>`\nmode.  :ref:`You can read the docs about it here <observability>`.\n\n.. _v6.91.2:\n\n-------------------\n6.91.2 - 2023-12-10\n-------------------\n\nThis patch refactors some more internals, continuing our work on supporting alternative backends (:issue:`3086`). There is no user-visible change.\n\n.. _v6.91.1:\n\n-------------------\n6.91.1 - 2023-12-08\n-------------------\n\nThis patch fixes an issue where :func:`~hypothesis.strategies.builds` could not be used with :pypi:`attrs` objects that defined private attributes (i.e. attributes with a leading underscore). See also :issue:`3791`.\n\nThis patch also adds support more generally for using :func:`~hypothesis.strategies.builds` with attrs' ``alias`` parameter, which was previously unsupported.\n\nThis patch increases the minimum required version of attrs to 22.2.0.\n\n.. _v6.91.0:\n\n-------------------\n6.91.0 - 2023-11-27\n-------------------\n\nThis release adds an optional ``payload`` argument to :func:`hypothesis.event`,\nso that you can clearly express the difference between the label and the value\nof an observation.  :ref:`statistics` will still summarize it as a string, but\nfuture observability options can preserve the distinction.\n\n.. _v6.90.1:\n\n-------------------\n6.90.1 - 2023-11-27\n-------------------\n\nThis patch supports assigning ``settings = settings(...)`` as a class attribute\non a subclass of a ``.TestCase`` attribute of a :class:`~hypothesis.stateful.RuleBasedStateMachine`.\nPreviously, this did nothing at all.\n\n.. code-block:: python\n\n    # works as of this release\n    class TestMyStatefulMachine(MyStatefulMachine.TestCase):\n        settings = settings(max_examples=10000)\n\n    # the old way still works, but it's more verbose.\n    MyStateMachine.TestCase.settings = settings(max_examples=10000)\n\n    class TestMyStatefulMachine(MyStatefulMachine.TestCase):\n        pass\n\nThanks to Joey Tran for reporting these settings-related edge cases in stateful testing.\n\n.. _v6.90.0:\n\n-------------------\n6.90.0 - 2023-11-20\n-------------------\n\nThis release makes it an error to assign ``settings = settings(...)``\nas a class attribute on a :class:`~hypothesis.stateful.RuleBasedStateMachine`.\nThis has never had any effect, and it should be used as a decorator instead:\n\n.. code-block:: python\n\n    class BadMachine(RuleBasedStateMachine):\n        \"\"\"This doesn't do anything, and is now an error!\"\"\"\n\n        settings = settings(derandomize=True)\n\n    @settings(derandomize=True)\n    class GoodMachine(RuleBasedStateMachine):\n        \"\"\"This is the right way to do it :-)\"\"\"\n\n.. _v6.89.1:\n\n-------------------\n6.89.1 - 2023-11-19\n-------------------\n\nThis patch refactors some internals.  There is no user-visible change,\nbut we hope to improve performance and unlock support for alternative\nbackends such as :pypi:`symbolic execution with crosshair <crosshair-tool>`\nin future (:issue:`3086`).\n\nThanks to Liam DeVoe for this fantastic contribution!\n\n.. _v6.89.0:\n\n-------------------\n6.89.0 - 2023-11-16\n-------------------\n\nThis release teaches :func:`~hypothesis.strategies.from_type` to handle constraints\nimplied by the :pypi:`annotated-types` package - as used by e.g. :pypi:`pydantic`.\nThis is usually efficient, but falls back to filtering in a few remaining cases.\n\nThanks to Viicos for :pull:`3780`!\n\n.. _v6.88.4:\n\n-------------------\n6.88.4 - 2023-11-13\n-------------------\n\nThis patch adds a warning when :func:`@st.composite <hypothesis.strategies.composite>`\nwraps a function annotated as returning a :class:`~hypothesis.strategies.SearchStrategy`,\nsince this is usually an error (:issue:`3786`).  The function should return a value,\nand the decorator will convert it to a function which returns a strategy.\n\n.. _v6.88.3:\n\n-------------------\n6.88.3 - 2023-11-05\n-------------------\n\nThis patch refactors ``from_type(typing.Tuple)``, allowing\n:func:`~hypothesis.strategies.register_type_strategy` to take effect\nfor tuples instead of being silently ignored (:issue:`3750`).\n\nThanks to Nick Collins for reporting and extensive work on this issue.\n\n.. _v6.88.2:\n\n-------------------\n6.88.2 - 2023-11-05\n-------------------\n\nThis patch improves the speed of the explain phase on python 3.12+, by using the new\n:mod:`sys.monitoring` module to collect coverage, instead of :obj:`sys.settrace`.\n\nThanks to Liam DeVoe for :pull:`3776`!\n\n.. _v6.88.1:\n\n-------------------\n6.88.1 - 2023-10-16\n-------------------\n\nThis patch improves :func:`~hypothesis.strategies.register_type_strategy` when used with ``tuple`` subclasses,\nby preventing them from being interpreted as generic and provided to strategies like ``st.from_type(Sequence[int])``\n(:issue:`3767`).\n\n.. _v6.88.0:\n\n-------------------\n6.88.0 - 2023-10-15\n-------------------\n\nThis release allows strategy-generating functions registered with\n:func:`~hypothesis.strategies.register_type_strategy` to conditionally not\nreturn a strategy, by returning :data:`NotImplemented` (:issue:`3767`).\n\n.. _v6.87.4:\n\n-------------------\n6.87.4 - 2023-10-12\n-------------------\n\nWhen :func:`~hypothesis.strategies.randoms` was called with ``use_true_randoms=False``,\ncalling ``r.sample([], 0)`` would result in an error,\nwhen it should have returned an empty sequence to agree with the normal behaviour of\n:func:`random.sample`. This fixes that discrepancy (:issue:`3765`).\n\n.. _v6.87.3:\n\n-------------------\n6.87.3 - 2023-10-06\n-------------------\n\nThis patch ensures that the :ref:`hypothesis codemod <codemods>` CLI\nwill print a warning instead of stopping with an internal error if\none of your files contains invalid syntax (:issue:`3759`).\n\n.. _v6.87.2:\n\n-------------------\n6.87.2 - 2023-10-06\n-------------------\n\nThis patch makes some small changes to our NumPy integration to ensure forward\ncompatibility.  Thanks to Mateusz Sokół for :pull:`3761`.\n\n.. _v6.87.1:\n\n-------------------\n6.87.1 - 2023-10-01\n-------------------\n\nFixes :issue:`3755`, where an internal condition turns out\nto be reachable after all.\n\n.. _v6.87.0:\n\n-------------------\n6.87.0 - 2023-09-25\n-------------------\n\nThis release deprecates use of :func:`~hypothesis.assume` and ``reject()``\noutside of property-based tests, because these functions work by raising a\nspecial exception (:issue:`3743`).  It also fixes some type annotations\n(:issue:`3753`).\n\n.. _v6.86.2:\n\n-------------------\n6.86.2 - 2023-09-18\n-------------------\n\nHotfix for :issue:`3747`, a bug in explain mode which is so rare that\nwe missed it in six months of dogfooding.  Thanks to :pypi:`mygrad`\nfor discovering and promptly reporting this!\n\n.. _v6.86.1:\n\n-------------------\n6.86.1 - 2023-09-17\n-------------------\n\nThis patch improves the documentation of :obj:`@example(...).xfail() <hypothesis.example.xfail>`\nby adding a note about :pep:`614`, similar to :obj:`@example(...).via() <hypothesis.example.via>`,\nand adds a warning when a strategy generates a test case which seems identical to\none provided by an xfailed example.\n\n.. _v6.86.0:\n\n-------------------\n6.86.0 - 2023-09-17\n-------------------\n\nThis release enables the |Phase.explain| phase\nby default.  We hope it helps you to understand *why* your failing tests have\nfailed!\n\n.. _v6.85.1:\n\n-------------------\n6.85.1 - 2023-09-16\n-------------------\n\nThis patch switches some of our type annotations to use :obj:`typing.Literal`\nwhen only a few specific values are allowed, such as UUID or IP address versions.\n\n.. _v6.85.0:\n\n-------------------\n6.85.0 - 2023-09-16\n-------------------\n\nThis release deprecates the old whitelist/blacklist arguments\nto :func:`~hypothesis.strategies.characters`, in favor of\ninclude/exclude arguments which more clearly describe their\neffects on the set of characters which can be generated.\n\nYou can :ref:`use Hypothesis' codemods <codemods>` to automatically\nupgrade to the new argument names.  In a future version, the old\nnames will start to raise a ``DeprecationWarning``.\n\n.. _v6.84.3:\n\n-------------------\n6.84.3 - 2023-09-10\n-------------------\n\nThis patch automatically disables the :obj:`~hypothesis.HealthCheck.differing_executors`\nhealth check for methods which are also pytest parametrized tests, because\nthose were mostly false alarms (:issue:`3733`).\n\n.. _v6.84.2:\n\n-------------------\n6.84.2 - 2023-09-06\n-------------------\n\nBuilding on recent releases, :func:`~hypothesis.strategies.characters`\nnow accepts _any_ ``codec=``, not just ``\"utf-8\"`` and ``\"ascii\"``.\n\nThis includes standard codecs from the :mod:`codecs` module and their\naliases, platform specific and user-registered codecs if they are\navailable, and `python-specific text encodings\n<https://docs.python.org/3/library/codecs.html#python-specific-encodings>`__\n(but not text transforms or binary transforms).\n\n.. _v6.84.1:\n\n-------------------\n6.84.1 - 2023-09-05\n-------------------\n\nThis patch by Reagan Lee makes ``st.text(...).filter(str.isidentifier)``\nreturn an efficient custom strategy (:issue:`3480`).\n\n.. _v6.84.0:\n\n-------------------\n6.84.0 - 2023-09-04\n-------------------\n\nThe :func:`~hypothesis.strategies.from_regex` strategy now takes an optional\n``alphabet=characters(codec=\"utf-8\")`` argument for unicode strings, like\n:func:`~hypothesis.strategies.text`.\n\nThis offers more and more-consistent control over the generated strings,\nremoving previously-hard-coded limitations.  With ``fullmatch=False`` and\n``alphabet=characters()``, surrogate characters are now possible in leading\nand trailing text as well as the body of the match.  Negated character classes\nsuch as ``[^A-Z]`` or ``\\S`` had a hard-coded exclusion of control characters\nand surrogate characters; now they permit anything in ``alphabet=`` consistent\nwith the class, and control characters are permitted by default.\n\n.. _v6.83.2:\n\n-------------------\n6.83.2 - 2023-09-04\n-------------------\n\nAdd a health check that detects if the same test is executed\nseveral times by :ref:`different executors<custom-function-execution>`.\nThis can lead to difficult-to-debug problems such as :issue:`3446`.\n\n.. _v6.83.1:\n\n-------------------\n6.83.1 - 2023-09-03\n-------------------\n\nPretty-printing of failing examples can now use functions registered with\n:func:`IPython.lib.pretty.for_type` or :func:`~IPython.lib.pretty.for_type_by_name`,\nas well as restoring compatibility with ``_repr_pretty_`` callback methods\nwhich were accidentally broken in :ref:`version 6.61.2 <v6.61.2>` (:issue:`3721`).\n\n.. _v6.83.0:\n\n-------------------\n6.83.0 - 2023-09-01\n-------------------\n\nAdds a new ``codec=`` option in :func:`~hypothesis.strategies.characters`, making it\nconvenient to produce only characters which can be encoded as ``ascii`` or ``utf-8``\nbytestrings.\n\nSupport for other codecs will be added in a future release.\n\n.. _v6.82.7:\n\n-------------------\n6.82.7 - 2023-08-28\n-------------------\n\nThis patch updates our autoformatting tools, improving our code style without any API changes.\n\n.. _v6.82.6:\n\n-------------------\n6.82.6 - 2023-08-20\n-------------------\n\nThis patch enables and fixes many more of :pypi:`ruff`\\ 's lint rules.\n\n.. _v6.82.5:\n\n-------------------\n6.82.5 - 2023-08-18\n-------------------\n\nFixes the error message for missing ``[cli]`` extra.\n\n.. _v6.82.4:\n\n-------------------\n6.82.4 - 2023-08-12\n-------------------\n\nThis patch ensures that we always close the download connection in\n:class:`~hypothesis.database.GitHubArtifactDatabase`.\n\n.. _v6.82.3:\n\n-------------------\n6.82.3 - 2023-08-08\n-------------------\n\nWe can now pretty-print combinations of *zero* :class:`enum.Flag`\nvalues, like ``SomeFlag(0)``, which has never worked before.\n\n.. _v6.82.2:\n\n-------------------\n6.82.2 - 2023-08-06\n-------------------\n\nThis patch fixes pretty-printing of combinations of :class:`enum.Flag`\nvalues, which was previously an error (:issue:`3709`).\n\n.. _v6.82.1:\n\n-------------------\n6.82.1 - 2023-08-05\n-------------------\n\nImprove shrinking of floats in narrow regions that don't cross an integer\nboundary. Closes :issue:`3357`.\n\n.. _v6.82.0:\n\n-------------------\n6.82.0 - 2023-07-20\n-------------------\n\n:func:`~hypothesis.strategies.from_regex` now supports the atomic grouping\n(``(?>...)``) and possessive quantifier (``*+``, ``++``, ``?+``, ``{m,n}+``)\nsyntax `added in Python 3.11 <https://docs.python.org/3/whatsnew/3.11.html#re>`__.\n\nThanks to Cheuk Ting Ho for implementing this!\n\n.. _v6.81.2:\n\n-------------------\n6.81.2 - 2023-07-15\n-------------------\n\nIf the :envvar:`HYPOTHESIS_NO_PLUGINS` environment variable is set, we'll avoid\n:ref:`loading plugins <entry-points>` such as `the old Pydantic integration\n<https://docs.pydantic.dev/latest/integrations/hypothesis/>`__ or\n`HypoFuzz' CLI options <https://hypofuzz.com/docs/quickstart.html#running-hypothesis-fuzz>`__.\n\nThis is probably only useful for our own self-tests, but documented in case it might\nhelp narrow down any particularly weird bugs in complex environments.\n\n.. _v6.81.1:\n\n-------------------\n6.81.1 - 2023-07-11\n-------------------\n\nFixes some lingering issues with inference of recursive types\nin :func:`~hypothesis.strategies.from_type`. Closes :issue:`3525`.\n\n.. _v6.81.0:\n\n-------------------\n6.81.0 - 2023-07-10\n-------------------\n\nThis release further improves our ``.patch``-file support from\n:ref:`version 6.75 <v6.75.0>`, skipping duplicates, tests which use\n:func:`~hypothesis.strategies.data` (and don't support\n:obj:`@example() <hypothesis.example>`\\ ), and various broken edge-cases.\n\nBecause :pypi:`libCST <libcst>` has released version 1.0 which uses the native parser\nby default, we no longer set the ``LIBCST_PARSER_TYPE=native`` environment\nvariable.  If you are using an older version, you may need to upgrade or\nset this envvar for yourself.\n\n.. _v6.80.1:\n\n-------------------\n6.80.1 - 2023-07-06\n-------------------\n\nThis patch updates some internal code for selftests.\nThere is no user-visible change.\n\n.. _v6.80.0:\n\n-------------------\n6.80.0 - 2023-06-27\n-------------------\n\nThis release drops support for Python 3.7, `which reached end of life on\n2023-06-27 <https://devguide.python.org/versions/>`__.\n\n.. _v6.79.4:\n\n-------------------\n6.79.4 - 2023-06-27\n-------------------\n\nFixes occasional recursion-limit-exceeded errors when validating\ndeeply nested strategies. Closes: :issue:`3671`\n\n.. _v6.79.3:\n\n-------------------\n6.79.3 - 2023-06-26\n-------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.79.2:\n\n-------------------\n6.79.2 - 2023-06-22\n-------------------\n\nImprove the type rendered in :func:`~hypothesis.strategies.from_type`,\nwhich improves the coverage of Ghostwriter.\n\n.. _v6.79.1:\n\n-------------------\n6.79.1 - 2023-06-19\n-------------------\n\nWe now test against Python 3.12 beta in CI, and this patch\nfixes some new deprecations.\n\n.. _v6.79.0:\n\n-------------------\n6.79.0 - 2023-06-17\n-------------------\n\nThis release changes :func:`~hypothesis.strategies.register_type_strategy`\nfor compatibility with :pep:`585`: we now store only a single strategy or\nresolver function which is used for both the builtin and the ``typing``\nmodule version of each type (:issue:`3635`).\n\nIf you previously relied on registering separate strategies for e.g.\n``list`` vs ``typing.List``, you may need to use explicit strategies\nrather than inferring them from types.\n\n.. _v6.78.3:\n\n-------------------\n6.78.3 - 2023-06-15\n-------------------\n\nThis release ensures that Ghostwriter does not use the deprecated aliases\nfor the ``collections.abc`` classes in ``collections``.\n\n.. _v6.78.2:\n\n-------------------\n6.78.2 - 2023-06-13\n-------------------\n\nThis patch improves Ghostwriter's use of qualified names for re-exported\nfunctions and classes, and avoids importing useless :obj:`~typing.TypeVar`\\ s.\n\n.. _v6.78.1:\n\n-------------------\n6.78.1 - 2023-06-12\n-------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.78.0:\n\n-------------------\n6.78.0 - 2023-06-11\n-------------------\n\nNew input validation for :func:`~hypothesis.strategies.recursive`\nwill raise an error rather than hanging indefinitely if passed\ninvalid ``max_leaves=`` arguments.\n\n.. _v6.77.0:\n\n-------------------\n6.77.0 - 2023-06-09\n-------------------\n\n:func:`~hypothesis.strategies.from_type` now handles numpy array types:\n:obj:`np.typing.ArrayLike <numpy.typing.ArrayLike>`,\n:obj:`np.typing.NDArray <numpy.typing.NDArray>`, and parameterized\nversions including :class:`np.ndarray[shape, elem_type] <numpy.ndarray>`.\n\n.. _v6.76.0:\n\n-------------------\n6.76.0 - 2023-06-04\n-------------------\n\nWarn in :func:`~hypothesis.strategies.from_type` if the inferred strategy\nhas no variation (always returning default instances). Also handles numpy\ndata types by calling :func:`~hypothesis.extra.numpy.from_dtype` on the\ncorresponding dtype, thus ensuring proper variation for these types.\n\n.. _v6.75.9:\n\n-------------------\n6.75.9 - 2023-05-31\n-------------------\n\n:func:`~hypothesis.strategies.from_type` now works in cases where we use\n:func:`~hypothesis.strategies.builds` to create an instance and the constructor\nhas an argument which would lead to recursion.  Previously, this would raise\nan error if the argument had a default value.\n\nThanks to Joachim B Haga for reporting and fixing this problem.\n\n.. _v6.75.8:\n\n-------------------\n6.75.8 - 2023-05-31\n-------------------\n\nIn preparation for supporting JAX in :ref:`hypothesis.extra.array_api <array-api>`,\nthis release supports immutable arrays being generated via :func:`xps.arrays`.\nIn particular, we internally removed an instance of in-place array modification,\nwhich isn't possible for an immutable array.\n\n.. _v6.75.7:\n\n-------------------\n6.75.7 - 2023-05-30\n-------------------\n\nThis release fixes some ``.patch``-file bugs from :ref:`version 6.75 <v6.75.0>`,\nand adds automatic support for writing ``@hypothesis.example()`` or ``@example()``\ndepending on the current style in your test file - defaulting to the latter.\n\nNote that this feature requires :pypi:`libcst` to be installed, and :pypi:`black`\nis strongly recommended.  You can ensure you have the dependencies with\n``pip install \"hypothesis[cli,codemods]\"``.\n\n.. _v6.75.6:\n\n-------------------\n6.75.6 - 2023-05-27\n-------------------\n\nThis patch continues the work started in :pull:`3651` by adding\n:pypi:`ruff` linter rules for :pypi:`pyflakes`, :pypi:`flake8-comprehensions`,\nand :pypi:`flake8-implicit-str-concat`.\n\n.. _v6.75.5:\n\n-------------------\n6.75.5 - 2023-05-26\n-------------------\n\nThis patch updates our linter stack to use :pypi:`ruff`, and fixes some\npreviously-ignored lints.  Thanks to Christian Clauss for his careful\nreview and :pull:`3651`!\n\n.. _v6.75.4:\n\n-------------------\n6.75.4 - 2023-05-26\n-------------------\n\nHypothesis will now record an event for more cases where data is marked\ninvalid, including for exceeding the internal depth limit.\n\n.. _v6.75.3:\n\n-------------------\n6.75.3 - 2023-05-14\n-------------------\n\nThis patch fixes :func:`~hypothesis.strategies.complex_numbers` accidentally\ninvalidating itself when passed magnitude arguments for 32 and 64-bit widths,\ni.e. 16- and 32-bit floats, due to not internally down-casting numbers (:issue:`3573`).\n\n.. _v6.75.2:\n\n-------------------\n6.75.2 - 2023-05-04\n-------------------\n\nImproved the documentation regarding how to use :class:`~hypothesis.database.GitHubArtifactDatabase`\nand fixed a bug that occurred in repositories with no existing artifacts.\n\nThanks to Agustín Covarrubias for this contribution.\n\n.. _v6.75.1:\n\n-------------------\n6.75.1 - 2023-04-30\n-------------------\n\n``hypothesis.errors`` will now raise :py:exc:`AttributeError` when attempting\nto access an undefined attribute, rather than returning :py:obj:`None`.\n\n.. _v6.75.0:\n\n-------------------\n6.75.0 - 2023-04-30\n-------------------\n\nSick of adding :obj:`@example() <hypothesis.example>`\\ s by hand?\nOur Pytest plugin now writes ``.patch`` files to insert them for you, making\n`this workflow <https://blog.nelhage.com/post/property-testing-like-afl/>`__\neasier than ever before.\n\nNote that you'll need :pypi:`LibCST <libcst>` (via :ref:`codemods`), and that\n:obj:`@example().via() <hypothesis.example.via>` requires :pep:`614`\n(Python 3.9 or later).\n\n.. _v6.74.1:\n\n-------------------\n6.74.1 - 2023-04-28\n-------------------\n\nThis patch provides better error messages for datetime- and timedelta-related\ninvalid dtypes in our Pandas extra (:issue:`3518`).\nThanks to Nick Muoh at the PyCon Sprints!\n\n.. _v6.74.0:\n\n-------------------\n6.74.0 - 2023-04-26\n-------------------\n\nThis release adds support for `nullable pandas dtypes <https://pandas.pydata.org/docs/user_guide/integer_na.html>`__\nin :func:`~hypothesis.extra.pandas` (:issue:`3604`).\nThanks to Cheuk Ting Ho for implementing this at the PyCon sprints!\n\n.. _v6.73.1:\n\n-------------------\n6.73.1 - 2023-04-27\n-------------------\n\nThis patch updates our minimum Numpy version to 1.16, and restores compatibility\nwith versions before 1.20, which were broken by a mistake in Hypothesis 6.72.4\n(:issue:`3625`).\n\n.. _v6.73.0:\n\n-------------------\n6.73.0 - 2023-04-25\n-------------------\n\nThis release upgrades the |Phase.explain| phase (:issue:`3411`).\n\n* Following the first failure, Hypothesis will (usually, depending on the enabled |Phase|) track which\n  lines of code were executed by passing and failing examples, and report where they\n  diverged - with some heuristics to drop unhelpful reports.  This is an existing\n  feature, now upgraded and newly enabled by default.\n\n* After shrinking to a minimal failing example, Hypothesis will try to find parts of\n  the example -- e.g. separate args to :func:`@given() <hypothesis.given>` -- which\n  can vary freely without changing the result of that minimal failing example.\n  If the automated experiments run without finding a passing variation, we leave a\n  comment in the final report:\n\n  .. code-block:: python\n\n      test_x_divided_by_y(\n          x=0,  # or any other generated value\n          y=0,\n      )\n\nJust remember that the *lack* of an explanation sometimes just means that Hypothesis\ncouldn't efficiently find one, not that no explanation (or simpler failing example)\nexists.\n\n.. _v6.72.4:\n\n-------------------\n6.72.4 - 2023-04-25\n-------------------\n\nThis patch fixes type annotations for the :func:`~hypothesis.extra.numpy.arrays`\nstrategy.  Thanks to Francesc Elies for :pull:`3602`.\n\n.. _v6.72.3:\n\n-------------------\n6.72.3 - 2023-04-25\n-------------------\n\nThis patch fixes a bug with :func:`~hypothesis.strategies.from_type()` with ``dict[tuple[int, int], str]``\n(:issue:`3527`).  Thanks to Nick Muoh at the PyCon Sprints!\n\n.. _v6.72.2:\n\n-------------------\n6.72.2 - 2023-04-24\n-------------------\n\nThis patch refactors our internals to facilitate an upcoming feature.\n\n.. _v6.72.1:\n\n-------------------\n6.72.1 - 2023-04-19\n-------------------\n\nThis patch fixes some documentation and prepares for future features.\n\n.. _v6.72.0:\n\n-------------------\n6.72.0 - 2023-04-16\n-------------------\n\nThis release deprecates ``Healthcheck.all()``, and :ref:`adds a codemod <codemods>`\nto automatically replace it with ``list(Healthcheck)`` (:issue:`3596`).\n\n.. _v6.71.0:\n\n-------------------\n6.71.0 - 2023-04-07\n-------------------\n\nThis release adds :class:`~hypothesis.database.GitHubArtifactDatabase`, a new database\nbackend that allows developers to access the examples found by a Github Actions CI job.\nThis is particularly useful for workflows that involve continuous fuzzing,\nlike `HypoFuzz <https://hypofuzz.com/>`__.\n\nThanks to Agustín Covarrubias for this feature!\n\n.. _v6.70.2:\n\n-------------------\n6.70.2 - 2023-04-03\n-------------------\n\nThis patch clarifies the reporting of time spent generating data. A\nsimple arithmetic mean of the percentage of time spent can be\nmisleading; reporting the actual time spent avoids misunderstandings.\n\nThanks to Andrea Reina for reporting and fixing :issue:`3598`!\n\n.. _v6.70.1:\n\n-------------------\n6.70.1 - 2023-03-27\n-------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.70.0:\n\n-------------------\n6.70.0 - 2023-03-16\n-------------------\n\nThis release adds an optional ``domains=`` parameter to the\n:func:`~hypothesis.strategies.emails` strategy, and excludes\nthe special-use :wikipedia:`.arpa` domain from the default\nstrategy (:issue:`3567`).\n\nThanks to Jens Tröger for reporting and fixing this bug!\n\n.. _v6.69.0:\n\n-------------------\n6.69.0 - 2023-03-15\n-------------------\n\nThis release turns ``HealthCheck.return_value`` and ``HealthCheck.not_a_test_method``\ninto unconditional errors.  Passing them to ``suppress_health_check=`` is therefore a deprecated no-op.\n(:issue:`3568`).  Thanks to Reagan Lee for the patch!\n\nSeparately, GraalPy can now run and pass most of the hypothesis test suite (:issue:`3587`).\n\n.. _v6.68.3:\n\n-------------------\n6.68.3 - 2023-03-15\n-------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.68.2:\n\n-------------------\n6.68.2 - 2023-02-17\n-------------------\n\nThis patch fixes missing imports of the :mod:`re` module, when :ref:`ghostwriting <ghostwriter>`\ntests which include compiled patterns or regex flags.\nThanks to Jens Heinrich for reporting and promptly fixing this bug!\n\n.. _v6.68.1:\n\n-------------------\n6.68.1 - 2023-02-12\n-------------------\n\nThis patch adds some private hooks for use in research on\n`Schemathesis <https://github.com/schemathesis/schemathesis>`__\n(`see our preprint here <https://arxiv.org/abs/2112.10328>`__).\n\n.. _v6.68.0:\n\n-------------------\n6.68.0 - 2023-02-09\n-------------------\n\nThis release adds support for the Array API's `2022.12 release\n<https://data-apis.org/array-api/2022.12/>`_ via the ``api_version`` argument in\n:func:`~hypothesis.extra.array_api.make_strategies_namespace`. Concretely this\ninvolves complex support in its existing strategies, plus an introduced\n:func:`xps.complex_dtypes` strategy.\n\nAdditionally this release now treats :ref:`hypothesis.extra.array_api\n<array-api>` as stable, meaning breaking changes should only happen with major\nreleases of Hypothesis.\n\n.. _v6.67.1:\n\n-------------------\n6.67.1 - 2023-02-05\n-------------------\n\nThis patch updates our autoformatting tools, improving our code style without any API changes.\n\n.. _v6.67.0:\n\n-------------------\n6.67.0 - 2023-02-05\n-------------------\n\nThis release allows for more precise generation of complex numbers using\n:func:`~hypothesis.extra.numpy.from_dtype`, by supporting the ``width``,\n``min_magnitude``, and ``min_magnitude`` arguments (:issue:`3468`).\n\nThanks to Felix Divo for this feature!\n\n.. _v6.66.2:\n\n-------------------\n6.66.2 - 2023-02-04\n-------------------\n\nThis patch fixes a rare ``RecursionError`` when pretty-printing a multi-line\nobject without type-specific printer, which was passed to a function which\nreturned the same object by ``.map()`` or :func:`~hypothesis.strategies.builds`\nand thus recursed due to the new pretty reprs in Hypothesis :ref:`v6.65.0`\n(:issue:`3560`).  Apologies to all those affected.\n\n.. _v6.66.1:\n\n-------------------\n6.66.1 - 2023-02-03\n-------------------\n\nThis makes :func:`~hypothesis.extra.numpy.from_dtype` pass through the parameter\n``allow_subnormal`` for complex dtypes.\n\n.. _v6.66.0:\n\n-------------------\n6.66.0 - 2023-02-02\n-------------------\n\nThis release adds a ``width`` parameter to :func:`~hypothesis.strategies.complex_numbers`,\nanalogously to :func:`~hypothesis.strategies.floats`.\n\nThanks to Felix Divo for the new feature!\n\n.. _v6.65.2:\n\n-------------------\n6.65.2 - 2023-01-27\n-------------------\n\nThis patch fixes invalid annotations detected for the tests generated by\n:ref:`Ghostwriter <ghostwriter>`. It will now correctly generate ``Optional``\ntypes with just one type argument and handle union expressions inside of type\narguments correctly. Additionally, it now supports code with the\n``from __future__ import annotations`` marker for Python 3.10 and newer.\n\n.. _v6.65.1:\n\n-------------------\n6.65.1 - 2023-01-26\n-------------------\n\nThis release improves the pretty-printing of enums in falsifying examples,\nso that they print as their full identifier rather than their repr.\n\n.. _v6.65.0:\n\n-------------------\n6.65.0 - 2023-01-24\n-------------------\n\nHypothesis now reports some failing inputs by showing the call which constructed\nan object, rather than the repr of the object.  This can be helpful when the default\nrepr does not include all relevant details, and will unlock further improvements\nin a future version.\n\nFor now, we capture calls made via :func:`~hypothesis.strategies.builds`, and via\n|.map|.\n\n.. _v6.64.0:\n\n-------------------\n6.64.0 - 2023-01-23\n-------------------\n\nThe :ref:`Ghostwriter <ghostwriter>` will now include type annotations on tests\nfor type-annotated code.  If you want to force this to happen (or not happen),\npass a boolean to the new ``annotate=`` argument to the Python functions, or\nthe ``--[no-]annotate`` CLI flag.\n\nThanks to Nicolas Ganz for this new feature!\n\n.. _v6.63.0:\n\n-------------------\n6.63.0 - 2023-01-20\n-------------------\n\n:func:`~hypothesis.extra.pandas.range_indexes` now accepts a ``name=`` argument,\nto generate named :class:`pandas.RangeIndex` objects.\n\nThanks to Sam Watts for this new feature!\n\n.. _v6.62.1:\n\n-------------------\n6.62.1 - 2023-01-14\n-------------------\n\nThis patch tweaks :func:`xps.arrays` internals to improve PyTorch compatibility.\nSpecifically, ``torch.full()`` does not accept integers as the shape argument\n(n.b. technically \"size\" in torch), but such behaviour is expected in internal\ncode, so we copy the ``torch`` module and patch in a working ``full()`` function.\n\n.. _v6.62.0:\n\n-------------------\n6.62.0 - 2023-01-08\n-------------------\n\nA classic error when testing is to write a test function that can never fail,\neven on inputs that aren't allowed or manually provided.  By analogy to the\ndesign pattern of::\n\n    @pytest.mark.parametrize(\"arg\", [\n        ...,  # passing examples\n        pytest.param(..., marks=[pytest.mark.xfail])  # expected-failing input\n    ])\n\nwe now support :obj:`@example(...).xfail() <hypothesis.example.xfail>`, with\nthe same (optional) ``condition``, ``reason``, and ``raises`` arguments as\n``pytest.mark.xfail()``.\n\nNaturally you can also write ``.via(...).xfail(...)``, or ``.xfail(...).via(...)``,\nif you wish to note the provenance of expected-failing examples.\n\n.. _v6.61.3:\n\n-------------------\n6.61.3 - 2023-01-08\n-------------------\n\nThis patch teaches our enhanced :func:`~typing.get_type_hints` function to\n'see through' :obj:`~functools.partial` application, allowing inference\nfrom type hints to work in a few more cases which aren't (yet!) supported\nby the standard-library version.\n\n.. _v6.61.2:\n\n-------------------\n6.61.2 - 2023-01-07\n-------------------\n\nThis patch improves our pretty-printing of failing examples, including\nsome refactoring to prepare for exciting future features.\n\n.. _v6.61.1:\n\n-------------------\n6.61.1 - 2023-01-06\n-------------------\n\nThis patch brings our :func:`~hypothesis.provisional.domains` and\n:func:`~hypothesis.strategies.emails` strategies into compliance with\n:rfc:`RFC 5890 §2.3.1 <5890>`: we no longer generate parts-of-domains\nwhere the third and fourth characters are ``--`` (\"R-LDH labels\"),\nthough future versions *may* deliberately generate ``xn--`` punycode\nlabels.  Thanks to :pypi:`python-email-validator` for `the report\n<https://github.com/JoshData/python-email-validator/issues/92>`__!\n\n.. _v6.61.0:\n\n-------------------\n6.61.0 - 2022-12-11\n-------------------\n\nThis release improves our treatment of database keys, which based on (among other things)\nthe source code of your test function.  We now post-process this source to ignore\ndecorators, comments, trailing whitespace, and blank lines - so that you can add\n:obj:`@example() <hypothesis.example>`\\ s or make some small no-op edits to your code\nwithout preventing replay of any known failing or covering examples.\n\n.. _v6.60.1:\n\n-------------------\n6.60.1 - 2022-12-11\n-------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.60.0:\n\n-------------------\n6.60.0 - 2022-12-04\n-------------------\n\nThis release improves Hypothesis' ability to resolve forward references in\ntype annotations. It fixes a bug that prevented\n:func:`~hypothesis.strategies.builds` from being used with `pydantic models that\npossess updated forward references <https://pydantic-docs.helpmanual.io/usage/postponed_annotations/>`__. See :issue:`3519`.\n\n.. _v6.59.0:\n\n-------------------\n6.59.0 - 2022-12-02\n-------------------\n\nThe :obj:`@example(...) <hypothesis.example>` decorator now has a ``.via()``\nmethod, which future tools will use to track automatically-added covering\nexamples (:issue:`3506`).\n\n.. _v6.58.2:\n\n-------------------\n6.58.2 - 2022-11-30\n-------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.58.1:\n\n-------------------\n6.58.1 - 2022-11-26\n-------------------\n\nThis patch shifts ``hypothesis[lark]`` from depending on the old :pypi:`lark-parser`\npackage to the new :pypi:`lark` package.  There are no code changes in Hypothesis,\nit's just that Lark got a new name on PyPI for version 1.0 onwards.\n\n.. _v6.58.0:\n\n-------------------\n6.58.0 - 2022-11-19\n-------------------\n\n:func:`~hypothesis.register_random` has used :mod:`weakref` since :ref:`v6.27.1`,\nallowing the :class:`~random.Random`-compatible objects to be garbage-collected when\nthere are no other references remaining in order to avoid memory leaks.\nWe now raise an error or emit a warning when this seems likely to happen immediately.\n\nThe type annotation of :func:`~hypothesis.register_random` was also widened so that\nstructural subtypes of :class:`~random.Random` are accepted by static typecheckers.\n\n.. _v6.57.1:\n\n-------------------\n6.57.1 - 2022-11-14\n-------------------\n\nThis patch updates some internal type annotations and fixes a formatting bug in the\n:obj:`~hypothesis.Phase.explain` phase reporting.\n\n.. _v6.57.0:\n\n-------------------\n6.57.0 - 2022-11-14\n-------------------\n\nHypothesis now raises an error if you passed a strategy as the ``alphabet=``\nargument to :func:`~hypothesis.strategies.text`, and it generated something\nwhich was not a length-one string.  This has never been supported, we're just\nadding explicit validation to catch cases like `this StackOverflow question\n<https://stackoverflow.com/a/74336909/9297601>`__.\n\n.. _v6.56.4:\n\n-------------------\n6.56.4 - 2022-10-28\n-------------------\n\nThis patch updates some docs, and depends on :pypi:`exceptiongroup` 1.0.0\nfinal to avoid a bug in the previous version.\n\n.. _v6.56.3:\n\n-------------------\n6.56.3 - 2022-10-17\n-------------------\n\nThis patch teaches :func:`~hypothesis.strategies.text` to rewrite a few more\nfilter predicates (:issue:`3134`).  You're unlikely to notice any change.\n\n.. _v6.56.2:\n\n-------------------\n6.56.2 - 2022-10-10\n-------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy, and fixes some\nincorrect examples in the docs for :func:`~hypothesis.extra.numpy.mutually_broadcastable_shapes`.\n\n.. _v6.56.1:\n\n-------------------\n6.56.1 - 2022-10-05\n-------------------\n\nThis patch improves the error message when Hypothesis detects \"flush to zero\"\nmode for floating-point: we now report which package(s) enabled this, which\ncan make debugging much easier.  See :issue:`3458` for details.\n\n.. _v6.56.0:\n\n-------------------\n6.56.0 - 2022-10-02\n-------------------\n\nThis release defines ``__bool__()`` on :class:`~hypothesis.strategies.SearchStrategy`.\nIt always returns ``True``, like before, but also emits a warning to help with\ncases where you intended to draw a value (:issue:`3463`).\n\n.. _v6.55.0:\n\n-------------------\n6.55.0 - 2022-09-29\n-------------------\n\nIn preparation for `future versions of the Array API standard\n<https://data-apis.org/array-api/latest/future_API_evolution.html>`__,\n:func:`~hypothesis.extra.array_api.make_strategies_namespace` now accepts an\noptional ``api_version`` argument, which determines the version conformed to by\nthe returned strategies namespace. If ``None``, the version of the passed array\nmodule ``xp`` is inferred.\n\nThis release also introduces :func:`xps.real_dtypes`. This is currently\nequivalent to the existing :func:`xps.numeric_dtypes` strategy, but exists\nbecause the latter is expected to include complex numbers in the next version of\nthe standard.\n\n.. _v6.54.6:\n\n-------------------\n6.54.6 - 2022-09-18\n-------------------\n\nIf multiple explicit examples (from :obj:`@example() <hypothesis.example>`)\nraise a Skip exception, for consistency with generated examples we now re-raise\nthe first instead of collecting them into an ExceptionGroup (:issue:`3453`).\n\n.. _v6.54.5:\n\n-------------------\n6.54.5 - 2022-09-05\n-------------------\n\nThis patch updates our autoformatting tools, improving our code style without any API changes.\n\n.. _v6.54.4:\n\n-------------------\n6.54.4 - 2022-08-20\n-------------------\n\nThis patch fixes some type annotations for Python 3.9 and earlier (:issue:`3397`),\nand teaches the |Phase.explain| phase about certain locations it should not\nbother reporting (:issue:`3439`).\n\n.. _v6.54.3:\n\n-------------------\n6.54.3 - 2022-08-12\n-------------------\n\nThis patch teaches the Ghostwriter an additional check for function\nand class locations that should make it use public APIs more often.\n\n.. _v6.54.2:\n\n-------------------\n6.54.2 - 2022-08-10\n-------------------\n\nThis patch fixes our workaround for `a pytest bug where the inner exceptions in\nan ExceptionGroup are not displayed <https://github.com/pytest-dev/pytest/issues/9159>`__\n(:issue:`3430`).\n\n.. _v6.54.1:\n\n-------------------\n6.54.1 - 2022-08-02\n-------------------\n\nThis patch makes ``FailedHealthCheck`` and ``DeadlineExceeded`` exceptions\npicklable, for compatibility with Django's parallel test runner (:issue:`3426`).\n\n.. _v6.54.0:\n\n-------------------\n6.54.0 - 2022-08-02\n-------------------\n\nReporting of :obj:`multiple failing examples <hypothesis.settings.report_multiple_bugs>`\nnow uses the :pep:`654` `ExceptionGroup <https://docs.python.org/3.11/library/exceptions.html#ExceptionGroup>`__ type, which is provided by the\n:pypi:`exceptiongroup` backport on Python 3.10 and earlier (:issue:`3175`).\n``hypothesis.errors.MultipleFailures`` is therefore deprecated.\n\nFailing examples and other reports are now stored as :pep:`678` exception notes, which\nensures that they will always appear together with the traceback and other information\nabout their respective error.\n\n.. _v6.53.0:\n\n-------------------\n6.53.0 - 2022-07-25\n-------------------\n\n:func:`~hypothesis.extra.django.from_field` now supports ``UsernameField``\nfrom :mod:`django.contrib.auth.forms`.\n\nThanks to Afonso Silva for reporting and working on :issue:`3417`.\n\n.. _v6.52.4:\n\n-------------------\n6.52.4 - 2022-07-22\n-------------------\n\nThis patch improves the error message when you pass filenames to the :command:`hypothesis write`\nCLI, which takes the name of a module or function (e.g. :command:`hypothesis write gzip` or\n:command:`hypothesis write package.some_function` rather than :command:`hypothesis write script.py`).\n\nThanks to Ed Rogers for implementing this as part of the SciPy 2022 sprints!\n\n.. _v6.52.3:\n\n-------------------\n6.52.3 - 2022-07-19\n-------------------\n\nThis patch ensures that the warning for non-interactive ``.example()``\npoints to your code instead of Hypothesis internals (:issue:`3403`).\n\nThanks to @jameslamb for this fix.\n\n.. _v6.52.2:\n\n-------------------\n6.52.2 - 2022-07-19\n-------------------\n\nThis patch makes :func:`~hypothesis.strategies.integers` more likely to\ngenerate boundary values for large two-sided intervals (:issue:`2942`).\n\n.. _v6.52.1:\n\n-------------------\n6.52.1 - 2022-07-18\n-------------------\n\nThis patch adds filter rewriting for :func:`math.isfinite`, :func:`math.isinf`, and :func:`math.isnan`\non :func:`~hypothesis.strategies.integers` or :func:`~hypothesis.strategies.floats` (:issue:`2701`).\n\nThanks to Sam Clamons at the SciPy Sprints!\n\n.. _v6.52.0:\n\n-------------------\n6.52.0 - 2022-07-18\n-------------------\n\nThis release adds the ``allow_subnormal`` argument to :func:`~hypothesis.strategies.complex_numbers` by\napplying it to each of the real and imaginary parts separately. Closes :issue:`3390`.\n\nThanks to Evan Tey for this fix.\n\n.. _v6.51.0:\n\n-------------------\n6.51.0 - 2022-07-17\n-------------------\n\nIssue a deprecation warning if a function decorated with\n:func:`@composite <hypothesis.strategies.composite>`\ndoes not draw any values (:issue:`3384`).\n\nThanks to Grzegorz Zieba, Rodrigo Girão, and Thomas Ball for\nworking on this at the EuroPython sprints!\n\n.. _v6.50.1:\n\n-------------------\n6.50.1 - 2022-07-09\n-------------------\n\nThis patch improves the error messages in :obj:`@example() <hypothesis.example>`\nargument validation following the recent release of :ref:`6.49.1 <v6.49.1>`.\n\n.. _v6.50.0:\n\n-------------------\n6.50.0 - 2022-07-09\n-------------------\n\nThis release allows :func:`~hypothesis.extra.numpy.from_dtype` to generate\nUnicode strings which cannot be encoded in UTF-8, but are valid in Numpy\narrays (which use UTF-32).\n\nThis logic will only be used with :pypi:`numpy` >= 1.19, because earlier\nversions have `an issue <https://github.com/numpy/numpy/issues/15363>`__\nwhich led us to revert :ref:`Hypothesis 5.2 <v5.2.0>` last time!\n\n.. _v6.49.1:\n\n-------------------\n6.49.1 - 2022-07-05\n-------------------\n\nThis patch fixes some inconsistency between argument handling for\n:obj:`@example <hypothesis.example>` and :func:`@given <hypothesis.given>`\n(:issue:`2706 <2706#issuecomment-1168363177>`).\n\n.. _v6.49.0:\n\n-------------------\n6.49.0 - 2022-07-04\n-------------------\n\nThis release uses :pep:`612` :obj:`python:typing.ParamSpec` (or the\n:pypi:`typing-extensions` backport) to express the first-argument-removing\nbehaviour of :func:`@st.composite <hypothesis.strategies.composite>`\nand signature-preservation of :func:`~hypothesis.strategies.functions`\nto IDEs, editor plugins, and static type checkers such as :pypi:`mypy`.\n\n.. _v6.48.3:\n\n-------------------\n6.48.3 - 2022-07-03\n-------------------\n\n:func:`hypothesis.event` now works for hashable objects which do not\nsupport weakrefs, such as integers and tuples.\n\n.. _v6.48.2:\n\n-------------------\n6.48.2 - 2022-06-29\n-------------------\n\nThis patch tidies up some internal introspection logic, which will improve\nsupport for positional-only arguments in a future release (:issue:`2706`).\n\n.. _v6.48.1:\n\n-------------------\n6.48.1 - 2022-06-27\n-------------------\n\nThis release automatically rewrites some simple filters, such as\n``floats().filter(lambda x: x >= 10)`` to the more efficient\n``floats(min_value=10)``, based on the AST of the predicate.\n\nWe continue to recommend using the efficient form directly wherever\npossible, but this should be useful for e.g. :pypi:`pandera` \"``Checks``\"\nwhere you already have a simple predicate and translating manually\nis really annoying.  See :issue:`2701` for details.\n\n.. _v6.48.0:\n\n-------------------\n6.48.0 - 2022-06-27\n-------------------\n\nThis release raises :class:`~unittest.SkipTest` for tests which never executed any\nexamples, for example because the :obj:`~hypothesis.settings.phases` setting\nexcluded the :obj:`~hypothesis.Phase.explicit`, :obj:`~hypothesis.Phase.reuse`,\nand :obj:`~hypothesis.Phase.generate` phases.  This helps to avoid cases where\nbroken tests appear to pass, because they didn't actually execute (:issue:`3328`).\n\n.. _v6.47.5:\n\n-------------------\n6.47.5 - 2022-06-25\n-------------------\n\nThis patch fixes type annotations that had caused the signature of\n:func:`@given <hypothesis.given>` to be partially-unknown to type-checkers for Python\nversions before 3.10.\n\n.. _v6.47.4:\n\n-------------------\n6.47.4 - 2022-06-23\n-------------------\n\nThis patch fixes :func:`~hypothesis.strategies.from_type` on Python 3.11,\nfollowing `python/cpython#93754 <https://github.com/python/cpython/pull/93754/>`__.\n\n.. _v6.47.3:\n\n-------------------\n6.47.3 - 2022-06-15\n-------------------\n\nThis patch makes the :obj:`~hypothesis.HealthCheck.too_slow` health check more\nconsistent with long :obj:`~hypothesis.settings.deadline` tests (:issue:`3367`)\nand fixes an install issue under :pypi:`pipenv` which was introduced in\n:ref:`Hypothesis 6.47.2 <v6.47.2>` (:issue:`3374`).\n\n.. _v6.47.2:\n\n-------------------\n6.47.2 - 2022-06-12\n-------------------\n\nWe now use the :pep:`654` `ExceptionGroup <https://docs.python.org/3.11/library/exceptions.html#ExceptionGroup>`__\ntype - provided by the :pypi:`exceptiongroup` backport on older Pythons -\nto ensure that if multiple errors are raised in teardown, they will all propagate.\n\n.. _v6.47.1:\n\n-------------------\n6.47.1 - 2022-06-10\n-------------------\n\nOur pretty-printer no longer sorts dictionary keys, since iteration order is\nstable in Python 3.7+ and this can affect reproducing examples (:issue:`3370`).\nThis PR was kindly supported by `Ordina Pythoneers\n<https://www.ordina.nl/vakgebieden/python/>`__.\n\n.. _v6.47.0:\n\n-------------------\n6.47.0 - 2022-06-07\n-------------------\n\nThe :ref:`Ghostwriter <ghostwriter>` can now write tests for\n:obj:`@classmethod <classmethod>` or :obj:`@staticmethod <staticmethod>`\nmethods, in addition to the existing support for functions and other callables\n(:issue:`3318`).  Thanks to Cheuk Ting Ho for the patch.\n\n.. _v6.46.11:\n\n--------------------\n6.46.11 - 2022-06-02\n--------------------\n\nMention :func:`hypothesis.strategies.timezones`\nin the documentation of :func:`hypothesis.strategies.datetimes` for completeness.\n\nThanks to George Macon for this addition.\n\n.. _v6.46.10:\n\n--------------------\n6.46.10 - 2022-06-01\n--------------------\n\nThis release contains some small improvements to our documentation.\nThanks to Felix Divo for his contribution!\n\n.. _v6.46.9:\n\n-------------------\n6.46.9 - 2022-05-25\n-------------------\n\nThis patch by Adrian Garcia Badaracco adds type annotations\nto some private internals (:issue:`3074`).\n\n.. _v6.46.8:\n\n-------------------\n6.46.8 - 2022-05-25\n-------------------\n\nThis patch by Phillip Schanely makes changes to the\n:func:`~hypothesis.strategies.floats` strategy when ``min_value`` or ``max_value`` is\npresent.\nHypothesis will now be capable of generating every representable value in the bounds.\nYou may notice that hypothesis is more likely to test values near boundaries, and values\nthat are very close to zero.\n\nThese changes also support future integrations with symbolic execution tools and fuzzers\n(:issue:`3086`).\n\n.. _v6.46.7:\n\n-------------------\n6.46.7 - 2022-05-19\n-------------------\n\nThis patch updates the type annotations for :func:`~hypothesis.strategies.tuples` and\n:func:`~hypothesis.strategies.one_of` so that type-checkers require its arguments to be\npositional-only, and so that it no longer fails under pyright-strict mode (see\n:issue:`3348`). Additional changes are made to Hypothesis' internals improve pyright\nscans.\n\n.. _v6.46.6:\n\n-------------------\n6.46.6 - 2022-05-18\n-------------------\n\nThis patch by Cheuk Ting Ho adds support for :pep:`655` ``Required`` and ``NotRequired`` as attributes of\n:obj:`~python:typing.TypedDict` in :func:`~hypothesis.strategies.from_type` (:issue:`3339`).\n\n.. _v6.46.5:\n\n-------------------\n6.46.5 - 2022-05-15\n-------------------\n\nThis patch fixes :func:`~hypothesis.extra.numpy.from_dtype` with long-precision\nfloating-point datatypes (typecode ``g``; see :func:`numpy:numpy.typename`).\n\n.. _v6.46.4:\n\n-------------------\n6.46.4 - 2022-05-15\n-------------------\n\nThis patch improves some error messages for custom signatures\ncontaining invalid parameter names (:issue:`3317`).\n\n.. _v6.46.3:\n\n-------------------\n6.46.3 - 2022-05-11\n-------------------\n\nThis patch by Cheuk Ting Ho makes it an explicit error to call :func:`~hypothesis.strategies.from_type`\nor :func:`~hypothesis.strategies.register_type_strategy` with types that have no runtime instances (:issue:`3280`).\n\n.. _v6.46.2:\n\n-------------------\n6.46.2 - 2022-05-03\n-------------------\n\nThis patch fixes silently dropping examples when the :obj:`@example <hypothesis.example>`\ndecorator is applied to itself (:issue:`3319`).  This was always a weird pattern, but now it\nworks.  Thanks to Ray Sogata, Keeri Tramm, and Kevin Khuong for working on this patch!\n\n.. _v6.46.1:\n\n-------------------\n6.46.1 - 2022-05-01\n-------------------\n\nThis patch fixes a rare bug where we could incorrectly treat\n:obj:`~python:inspect.Parameter.empty` as a type annotation,\nif the callable had an explicitly assigned ``__signature__``.\n\n.. _v6.46.0:\n\n-------------------\n6.46.0 - 2022-05-01\n-------------------\n\nThis release adds an ``allow_nil`` argument to :func:`~hypothesis.strategies.uuids`,\nwhich you can use to... generate the nil UUID.  Thanks to Shlok Gandhi for the patch!\n\n.. _v6.45.4:\n\n-------------------\n6.45.4 - 2022-05-01\n-------------------\n\nThis patch fixes some missing imports for certain :ref:`Ghostwritten <ghostwriter>`\ntests.  Thanks to Mel Seto for fixing :issue:`3316`.\n\n.. _v6.45.3:\n\n-------------------\n6.45.3 - 2022-04-30\n-------------------\n\nThis patch teaches :ref:`the Ghostwriter <ghostwriter>` to recognize\nmany more common argument names (:issue:`3311`).\n\n.. _v6.45.2:\n\n-------------------\n6.45.2 - 2022-04-29\n-------------------\n\nThis patch fixes :issue:`3314`, where Hypothesis would raise an internal\nerror from :func:`~hypothesis.provisional.domains` or (only on Windows)\nfrom :func:`~hypothesis.strategies.timezones` in some rare circumstances\nwhere the installation was subtly broken.\n\nThanks to Munir Abdinur for this contribution.\n\n.. _v6.45.1:\n\n-------------------\n6.45.1 - 2022-04-27\n-------------------\n\nThis release fixes deprecation warnings about ``sre_compile`` and ``sre_parse``\nimports and ``importlib.resources`` usage when running Hypothesis on Python 3.11.\n\nThanks to Florian Bruhin for this contribution.\n\n.. _v6.45.0:\n\n-------------------\n6.45.0 - 2022-04-22\n-------------------\n\nThis release updates :func:`xps.indices` by introducing an ``allow_newaxis``\nargument, defaulting to ``False``. If ``allow_newaxis=True``, indices can be\ngenerated that add dimensions to arrays, which is achieved by the indexer\ncontaining ``None``. This change is to support a specification change that\nexpand dimensions via indexing (`data-apis/array-api#408\n<https://github.com/data-apis/array-api/pull/408>`_).\n\n.. _v6.44.0:\n\n-------------------\n6.44.0 - 2022-04-21\n-------------------\n\nThis release adds a ``names`` argument to :func:`~hypothesis.extra.pandas.indexes`\nand :func:`~hypothesis.extra.pandas.series`, so that you can create Pandas\nobjects with specific or varied names.\n\nContributed by Sam Watts.\n\n.. _v6.43.3:\n\n-------------------\n6.43.3 - 2022-04-18\n-------------------\n\nThis patch updates the type annotations for :func:`@given <hypothesis.given>`\nso that type-checkers will warn on mixed positional and keyword arguments,\nas well as fixing :issue:`3296`.\n\n.. _v6.43.2:\n\n-------------------\n6.43.2 - 2022-04-16\n-------------------\n\nFixed a type annotation for ``pyright --strict`` (:issue:`3287`).\n\n.. _v6.43.1:\n\n-------------------\n6.43.1 - 2022-04-13\n-------------------\n\nThis patch makes it an explicit error to call\n:func:`~hypothesis.strategies.register_type_strategy` with a\n`Pydantic GenericModel <https://docs.pydantic.dev/latest/concepts/models/#generic-models>`__\nand a callable, because ``GenericModel`` isn't actually a generic type at\nruntime and so you have to register each of the \"parametrized versions\"\n(actually subclasses!) manually.  See :issue:`2940` for more details.\n\n.. _v6.43.0:\n\n-------------------\n6.43.0 - 2022-04-12\n-------------------\n\nThis release makes it an explicit error to apply\n:func:`@pytest.fixture <pytest:pytest.fixture>` to a function which has\nalready been decorated with :func:`@given() <hypothesis.given>`.  Previously,\n``pytest`` would convert your test to a fixture, and then never run it.\n\n.. _v6.42.3:\n\n-------------------\n6.42.3 - 2022-04-10\n-------------------\n\nThis patch fixes :func:`~hypothesis.strategies.from_type` on a :obj:`~python:typing.TypedDict`\nwith complex annotations, defined in a file using ``from __future__ import annotations``.\nThanks to Katelyn Gigante for identifying and fixing this bug!\n\n.. _v6.42.2:\n\n-------------------\n6.42.2 - 2022-04-10\n-------------------\n\nThe Hypothesis pytest plugin was not outputting valid xunit2 nodes when\n``--junit-xml`` was specified. This has been broken since Pytest 5.4, which\nchanged the internal API for adding nodes to the junit report.\n\nThis also fixes the issue when using hypothesis with ``--junit-xml`` and\n``pytest-xdist`` where the junit xml report would not be xunit2 compatible.\nNow, when using with ``pytest-xdist``, the junit report will just omit the\n``<properties>`` node.\n\nFor more details, see `this pytest issue <https://github.com/pytest-dev/pytest/issues/1126#issuecomment-484581283>`__,\n`this pytest issue <https://github.com/pytest-dev/pytest/issues/7767#issuecomment-1082436256>`__,\nand :issue:`1935`.\n\nThanks to Brandon Chinn for this bug fix!\n\n.. _v6.42.1:\n\n-------------------\n6.42.1 - 2022-04-10\n-------------------\n\nThis patch fixes pretty-printing of regular expressions in Python 3.11.0a7, and\nupdates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,.\n\n.. _v6.42.0:\n\n-------------------\n6.42.0 - 2022-04-09\n-------------------\n\nThis release makes :func:`st.functions(pure=True) <hypothesis.strategies.functions>` less noisy (:issue:`3253`),\nand generally improves pretty-printing of functions.\n\n.. _v6.41.0:\n\n-------------------\n6.41.0 - 2022-04-01\n-------------------\n\nThis release changes the implementation of :const:`~hypothesis.infer` to be an alias\nfor :obj:`python:Ellipsis`. E.g. ``@given(a=infer)`` is now equivalent to ``@given(a=...)``. Furthermore, ``@given(...)`` can now be specified so that\n:func:`@given <hypothesis.given>` will infer the strategies for *all* arguments of the\ndecorated function based on its annotations.\n\n.. _v6.40.3:\n\n-------------------\n6.40.3 - 2022-04-01\n-------------------\n\nThis patch simplifies the repr of the strategies namespace returned in\n:func:`~hypothesis.extra.array_api.make_strategies_namespace`, e.g.\n\n.. code-block:: pycon\n\n    >>> from hypothesis.extra.array_api import make_strategies_namespace\n    >>> from numpy import array_api as xp\n    >>> xps = make_strategies_namespace(xp)\n    >>> xps\n    make_strategies_namespace(numpy.array_api)\n\n.. _v6.40.2:\n\n-------------------\n6.40.2 - 2022-04-01\n-------------------\n\nFixed :func:`~hypothesis.strategies.from_type` support for\n:pep:`604` union types, like ``int | None`` (:issue:`3255`).\n\n.. _v6.40.1:\n\n-------------------\n6.40.1 - 2022-04-01\n-------------------\n\nFixed an internal error when :func:`~hypothesis.given` was passed a lambda.\n\n.. _v6.40.0:\n\n-------------------\n6.40.0 - 2022-03-29\n-------------------\n\n:ref:`The Ghostwriter <ghostwriter>` can now write tests which check that\ntwo or more functions are equivalent on valid inputs, *or* raise the same\ntype of exception for invalid inputs (:issue:`3267`).\n\n.. _v6.39.6:\n\n-------------------\n6.39.6 - 2022-03-27\n-------------------\n\nThis patch makes some quality-of-life improvements to the\n:ref:`Ghostwriter <ghostwriter>`: we guess the :func:`~hypothesis.strategies.text`\nstrategy for arguments named ``text`` (...obvious in hindsight, eh?);\nand improved the error message if you accidentally left in a\n:func:`~hypothesis.strategies.nothing` or broke your :pypi:`rich` install.\n\n.. _v6.39.5:\n\n-------------------\n6.39.5 - 2022-03-26\n-------------------\n\nThis patch improves our error detection and message when Hypothesis is run\non a Python implementation without support for ``-0.0``, which is required\nfor the :func:`~hypothesis.strategies.floats` strategy but can be disabled by\n`unsafe compiler options <https://simonbyrne.github.io/notes/fastmath/>`__\n(:issue:`3265`).\n\n.. _v6.39.4:\n\n-------------------\n6.39.4 - 2022-03-17\n-------------------\n\nThis patch tweaks some internal formatting.  There is no user-visible change.\n\n.. _v6.39.3:\n\n-------------------\n6.39.3 - 2022-03-07\n-------------------\n\nIf the :obj:`~hypothesis.Phase.shrink` phase is disabled, we now stop the\n:obj:`~hypothesis.Phase.generate` phase as soon as an error is found regardless\nof the value of the ``report_multiple_examples`` setting, since that's\nprobably what you wanted (:issue:`3244`).\n\n.. _v6.39.2:\n\n-------------------\n6.39.2 - 2022-03-07\n-------------------\n\nThis patch clarifies rare error messages in\n:func:`~hypothesis.strategies.builds` (:issue:`3225`) and\n:func:`~hypothesis.strategies.floats` (:issue:`3207`).\n\n.. _v6.39.1:\n\n-------------------\n6.39.1 - 2022-03-03\n-------------------\n\nThis patch fixes a regression where the bound inner function\n(``your_test.hypothesis.inner_test``) would be invoked with positional\narguments rather than passing them by name, which broke\n:pypi:`pytest-asyncio` (:issue:`3245`).\n\n.. _v6.39.0:\n\n-------------------\n6.39.0 - 2022-03-01\n-------------------\n\nThis release improves Hypothesis' handling of positional-only arguments,\nwhich are now allowed :func:`@st.composite <hypothesis.strategies.composite>`\nstrategies.\n\nOn Python 3.8 and later, the first arguments to :func:`~hypothesis.strategies.builds`\nand :func:`~hypothesis.extra.django.from_model` are now natively positional-only.\nIn cases which were already errors, the ``TypeError`` from incorrect usage will\ntherefore be raises immediately when the function is called, rather than when\nthe strategy object is used.\n\n.. _v6.38.0:\n\n-------------------\n6.38.0 - 2022-02-26\n-------------------\n\nThis release makes :func:`~hypothesis.strategies.floats` error *consistently* when\nyour floating-point hardware has been configured to violate IEEE-754 for\n:wikipedia:`subnormal numbers <Subnormal_number>`, instead of\nonly when an internal assertion was tripped (:issue:`3092`).\n\nIf this happens to you, passing ``allow_subnormal=False`` will suppress the explicit\nerror.  However, we strongly recommend fixing the root cause by disabling global-effect\nunsafe-math compiler options instead, or at least consulting e.g. Simon Byrne's\n`Beware of fast-math <https://simonbyrne.github.io/notes/fastmath/>`__ explainer first.\n\n.. _v6.37.2:\n\n-------------------\n6.37.2 - 2022-02-21\n-------------------\n\nThis patch fixes a bug in stateful testing, where returning a single value\nwrapped in :func:`~hypothesis.stateful.multiple` would be printed such that\nthe assigned variable was a tuple rather than the single element\n(:issue:`3236`).\n\n.. _v6.37.1:\n\n-------------------\n6.37.1 - 2022-02-21\n-------------------\n\nThis patch fixes a warning under :pypi:`pytest` 7 relating to our\nrich traceback display logic (:issue:`3223`).\n\n.. _v6.37.0:\n\n-------------------\n6.37.0 - 2022-02-18\n-------------------\n\nWhen distinguishing multiple errors, Hypothesis now looks at the inner\nexceptions of :pep:`654` ``ExceptionGroup``\\ s.\n\n.. _v6.36.2:\n\n-------------------\n6.36.2 - 2022-02-13\n-------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.36.1:\n\n-------------------\n6.36.1 - 2022-01-31\n-------------------\n\nThis patch fixes some deprecation warnings from :pypi:`pytest` 7.0,\nalong with some code formatting and docs updates.\n\n.. _v6.36.0:\n\n-------------------\n6.36.0 - 2022-01-19\n-------------------\n\nThis release disallows using :obj:`python:typing.Final`\nwith :func:`~hypothesis.strategies.from_type`\nand :func:`~hypothesis.strategies.register_type_strategy`.\n\nWhy?\nBecause ``Final`` can only be used during ``class`` definition.\nWe don't generate class attributes.\n\nIt also does not make sense as a runtime type on its own.\n\n.. _v6.35.1:\n\n-------------------\n6.35.1 - 2022-01-17\n-------------------\n\nThis patch fixes ``hypothesis write`` output highlighting with :pypi:`rich`\nversion 12.0 and later.\n\n.. _v6.35.0:\n\n-------------------\n6.35.0 - 2022-01-08\n-------------------\n\nThis release disallows using :obj:`python:typing.ClassVar`\nwith :func:`~hypothesis.strategies.from_type`\nand :func:`~hypothesis.strategies.register_type_strategy`.\n\nWhy?\nBecause ``ClassVar`` can only be used during ``class`` definition.\nWe don't generate class attributes.\n\nIt also does not make sense as a runtime type on its own.\n\n.. _v6.34.2:\n\n-------------------\n6.34.2 - 2022-01-05\n-------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.34.1:\n\n-------------------\n6.34.1 - 2021-12-31\n-------------------\n\nThis patch fixes :issue:`3169`, an extremely rare bug which would\ntrigger if an internal least-recently-reused cache dropped a newly\nadded entry immediately after it was added.\n\n.. _v6.34.0:\n\n-------------------\n6.34.0 - 2021-12-31\n-------------------\n\nThis release fixes :issue:`3133` and :issue:`3144`, where attempting\nto generate Pandas series of lists or sets would fail with confusing\nerrors if you did not specify ``dtype=object``.\n\n.. _v6.33.0:\n\n-------------------\n6.33.0 - 2021-12-30\n-------------------\n\nThis release disallows using :obj:`python:typing.TypeAlias`\nwith :func:`~hypothesis.strategies.from_type`\nand :func:`~hypothesis.strategies.register_type_strategy`.\n\nWhy? Because ``TypeAlias`` is not really a type,\nit is a tag for type checkers that some expression is a type alias,\nnot something else.\n\nIt does not make sense for Hypothesis to resolve it as a strategy.\nReferences :issue:`2978`.\n\n.. _v6.32.1:\n\n-------------------\n6.32.1 - 2021-12-23\n-------------------\n\nThis patch updates our autoformatting tools, improving our code style without any API changes.\n\n.. _v6.32.0:\n\n-------------------\n6.32.0 - 2021-12-23\n-------------------\n\nThis release drops support for Python 3.6, which `reached end of life upstream\n<https://devguide.python.org/#status-of-python-branches>`__ on 2021-12-23.\n\n.. _v6.31.6:\n\n-------------------\n6.31.6 - 2021-12-15\n-------------------\n\nThis patch adds a temporary hook for a downstream tool,\nwhich is not part of the public API.\n\n.. _v6.31.5:\n\n-------------------\n6.31.5 - 2021-12-14\n-------------------\n\nThis release updates our copyright headers to `use a general authorship statement and omit the year\n<https://www.linuxfoundation.org/blog/copyright-notices-in-open-source-software-projects/>`__.\n\n.. _v6.31.4:\n\n-------------------\n6.31.4 - 2021-12-11\n-------------------\n\nThis patch makes the ``.example()`` method more representative of\ntest-time data generation, albeit often at a substantial cost to\nreadability (:issue:`3182`).\n\n.. _v6.31.3:\n\n-------------------\n6.31.3 - 2021-12-10\n-------------------\n\nThis patch improves annotations on some of Hypothesis' internal functions, in order to\ndeobfuscate the signatures of some strategies. In particular, strategies shared between\n:ref:`hypothesis.extra.numpy <hypothesis-numpy>` and\n:ref:`the hypothesis.extra.array_api extra <array-api>` will benefit from this patch.\n\n.. _v6.31.2:\n\n-------------------\n6.31.2 - 2021-12-10\n-------------------\n\nThis patch fix invariants display in stateful falsifying examples (:issue:`3185`).\n\n.. _v6.31.1:\n\n-------------------\n6.31.1 - 2021-12-10\n-------------------\n\nThis patch updates :func:`xps.indices` so no flat indices are generated, i.e.\ngenerated indices will now always explicitly cover each axes of an array if no\nellipsis is present. This is to be consistent with a specification change that\ndropped support for flat indexing\n(`#272 <https://github.com/data-apis/array-api/pull/272>`_).\n\n.. _v6.31.0:\n\n-------------------\n6.31.0 - 2021-12-09\n-------------------\n\nThis release makes us compatible with :pypi:`Django` 4.0, in particular by adding\nsupport for use of :mod:`zoneinfo` timezones (though we respect the new\n``USE_DEPRECATED_PYTZ`` setting if you need it).\n\n.. _v6.30.1:\n\n-------------------\n6.30.1 - 2021-12-05\n-------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.30.0:\n\n-------------------\n6.30.0 - 2021-12-03\n-------------------\n\nThis release adds an ``allow_subnormal`` argument to the\n:func:`~hypothesis.strategies.floats` strategy, which can explicitly toggle the\ngeneration of :wikipedia:`subnormal floats <Subnormal_number>` (:issue:`3155`).\nDisabling such generation is useful when testing flush-to-zero builds of\nlibraries.\n\n:func:`nps.from_dtype() <hypothesis.extra.numpy.from_dtype>` and\n:func:`xps.from_dtype` can also accept the ``allow_subnormal`` argument, and\n:func:`xps.from_dtype` or :func:`xps.arrays` will disable subnormals by default\nif the array module ``xp`` is detected to flush-to-zero (like is typical with\nCuPy).\n\n.. _v6.29.3:\n\n-------------------\n6.29.3 - 2021-12-02\n-------------------\n\nThis patch fixes a bug in :func:`~hypothesis.extra.numpy.mutually_broadcastable_shapes`,\nwhich restricted the patterns of singleton dimensions that could be generated for\ndimensions that extended beyond ``base_shape`` (:issue:`3170`).\n\n.. _v6.29.2:\n\n-------------------\n6.29.2 - 2021-12-02\n-------------------\n\nThis patch clarifies our pretty-printing of DataFrames (:issue:`3114`).\n\n.. _v6.29.1:\n\n-------------------\n6.29.1 - 2021-12-02\n-------------------\n\nThis patch documents :func:`~hypothesis.strategies.timezones`\n`Windows-only requirement <https://docs.python.org/3/library/zoneinfo.html#data-sources>`__\nfor the :pypi:`tzdata` package, and ensures that\n``pip install hypothesis[zoneinfo]`` will install the latest version.\n\n.. _v6.29.0:\n\n-------------------\n6.29.0 - 2021-11-29\n-------------------\n\nThis release teaches :func:`~hypothesis.strategies.builds` to use\n:func:`~hypothesis.strategies.deferred` when resolving unrecognised type hints,\nso that you can conveniently register strategies for recursive types\nwith constraints on some arguments (:issue:`3026`):\n\n.. code-block:: python\n\n    class RecursiveClass:\n        def __init__(self, value: int, next_node: typing.Optional[\"SomeClass\"]):\n            assert value > 0\n            self.value = value\n            self.next_node = next_node\n\n    st.register_type_strategy(\n        RecursiveClass, st.builds(RecursiveClass, value=st.integers(min_value=1))\n    )\n\n.. _v6.28.1:\n\n-------------------\n6.28.1 - 2021-11-28\n-------------------\n\nThis release fixes some internal calculations related to collection sizes (:issue:`3143`).\n\n.. _v6.28.0:\n\n-------------------\n6.28.0 - 2021-11-28\n-------------------\n\nThis release modifies our :pypi:`pytest` plugin, to avoid importing Hypothesis\nand therefore triggering :ref:`Hypothesis' entry points <entry-points>` for\ntest suites where Hypothesis is installed but not actually used (:issue:`3140`).\n\n.. _v6.27.3:\n\n-------------------\n6.27.3 - 2021-11-28\n-------------------\n\nThis release fixes :issue:`3080`, where :func:`~hypothesis.strategies.from_type`\nfailed on unions containing :pep:`585` builtin generic types (like ``list[int]``)\nin Python 3.9 and later.\n\n.. _v6.27.2:\n\n-------------------\n6.27.2 - 2021-11-26\n-------------------\n\nThis patch makes the :command:`hypothesis codemod`\n:ref:`command <hypothesis-cli>` somewhat faster.\n\n.. _v6.27.1:\n\n-------------------\n6.27.1 - 2021-11-22\n-------------------\n\nThis patch changes the backing datastructures of :func:`~hypothesis.register_random`\nand a few internal caches to use :class:`weakref.WeakValueDictionary`.  This reduces\nmemory usage and may improve performance when registered :class:`~random.Random`\ninstances are only used for a subset of your tests (:issue:`3131`).\n\n.. _v6.27.0:\n\n-------------------\n6.27.0 - 2021-11-22\n-------------------\n\nThis release teaches Hypothesis' multiple-error reporting to format tracebacks\nusing :pypi:`pytest` or :pypi:`better-exceptions`, if they are installed and\nenabled (:issue:`3116`).\n\n.. _v6.26.0:\n\n-------------------\n6.26.0 - 2021-11-21\n-------------------\n\nDid you know that of the 2\\ :superscript:`64` possible floating-point numbers,\n2\\ :superscript:`53` of them are ``nan`` - and Python prints them all the same way?\n\nWhile nans *usually* have all zeros in the sign bit and mantissa, this\n`isn't always true <https://wingolog.org/archives/2011/05/18/value-representation-in-javascript-implementations>`__,\nand :wikipedia:`'signaling' nans might trap or error <NaN#Signaling_NaN>`.\nTo help distinguish such errors in e.g. CI logs, Hypothesis now prints ``-nan`` for\nnegative nans, and adds a comment like ``# Saw 3 signaling NaNs`` if applicable.\n\n.. _v6.25.0:\n\n-------------------\n6.25.0 - 2021-11-19\n-------------------\n\nThis release adds special filtering logic to make a few special cases\nlike ``s.map(lambda x: x)`` and ``lists().filter(len)`` more efficient\n(:issue:`2701`).\n\n.. _v6.24.6:\n\n-------------------\n6.24.6 - 2021-11-18\n-------------------\n\nThis patch makes :func:`~hypothesis.strategies.floats` generate\n:wikipedia:`\"subnormal\" floating point numbers <Subnormal_number>`\nmore often, as these rare values can have strange interactions with\n`unsafe compiler optimisations like -ffast-math\n<https://simonbyrne.github.io/notes/fastmath/#flushing_subnormals_to_zero>`__\n(:issue:`2976`).\n\n.. _v6.24.5:\n\n-------------------\n6.24.5 - 2021-11-16\n-------------------\n\nThis patch fixes a rare internal error in the :func:`~hypothesis.strategies.datetimes`\nstrategy, where the implementation of ``allow_imaginary=False`` crashed when checking\na time during the skipped hour of a DST transition *if* the DST offset is negative -\nonly true of ``Europe/Dublin``, who we presume have their reasons - and the ``tzinfo``\nobject is a :pypi:`pytz` timezone (which predates :pep:`495`).\n\n.. _v6.24.4:\n\n-------------------\n6.24.4 - 2021-11-15\n-------------------\n\nThis patch gives Hypothesis it's own internal :class:`~random.Random` instance,\nensuring that test suites which reset the global random state don't induce\nweird correlations between property-based tests (:issue:`2135`).\n\n.. _v6.24.3:\n\n-------------------\n6.24.3 - 2021-11-13\n-------------------\n\nThis patch updates documentation of :func:`~hypothesis.note`\n(:issue:`3147`).\n\n.. _v6.24.2:\n\n-------------------\n6.24.2 - 2021-11-05\n-------------------\n\nThis patch updates internal testing for the :ref:`Array API extra <array-api>`\nto be consistent with new specification changes: ``sum()`` not accepting\nboolean arrays (`#234 <https://github.com/data-apis/array-api/pull/234>`_),\n``unique()`` split into separate functions\n(`#275 <https://github.com/data-apis/array-api/pull/275>`_), and treating NaNs\nas distinct (`#310 <https://github.com/data-apis/array-api/pull/310>`_). It has\nno user visible impact.\n\n.. _v6.24.1:\n\n-------------------\n6.24.1 - 2021-11-01\n-------------------\n\nThis patch updates our vendored `list of top-level domains <https://www.iana.org/domains/root/db>`__,\nwhich is used by the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n.. _v6.24.0:\n\n-------------------\n6.24.0 - 2021-10-23\n-------------------\n\nThis patch updates our vendored `list of top-level domains\n<https://data.iana.org/TLD/tlds-alpha-by-domain.txt>`__, which is used\nby the provisional :func:`~hypothesis.provisional.domains` strategy.\n\n(did you know that gTLDs can be both `added <https://newgtlds.icann.org/en/>`__\nand `removed <https://www.icann.org/resources/pages/gtld-registry-agreement-termination-2015-10-09-en>`__?)\n\n.. _v6.23.4:\n\n-------------------\n6.23.4 - 2021-10-20\n-------------------\n\nThis patch adds an error for when ``shapes`` in :func:`xps.arrays()` is not\npassed as either a valid shape or strategy.\n\n.. _v6.23.3:\n\n-------------------\n6.23.3 - 2021-10-18\n-------------------\n\nThis patch updates our formatting with :pypi:`shed`.\n\n.. _v6.23.2:\n\n-------------------\n6.23.2 - 2021-10-08\n-------------------\n\nThis patch replaces external links to :doc:`NumPy <numpy:index>` API docs\nwith :mod:`sphinx.ext.intersphinx` cross-references. It is purely a documentation improvement.\n\n.. _v6.23.1:\n\n-------------------\n6.23.1 - 2021-09-29\n-------------------\n\nThis patch cleans up internal logic for :func:`xps.arrays()`. There is no\nuser-visible change.\n\n.. _v6.23.0:\n\n-------------------\n6.23.0 - 2021-09-26\n-------------------\n\nThis release follows :pypi:`pytest` in considering :class:`SystemExit` and\n:class:`GeneratorExit` exceptions to be test failures, meaning that we will\nshink to minimal examples and check for flakiness even though they subclass\n:class:`BaseException` directly (:issue:`2223`).\n\n:class:`KeyboardInterrupt` continues to interrupt everything, and will be\nre-raised immediately.\n\n.. _v6.22.0:\n\n-------------------\n6.22.0 - 2021-09-24\n-------------------\n\nThis release adds :class:`~hypothesis.extra.django.LiveServerTestCase` and\n:class:`~hypothesis.extra.django.StaticLiveServerTestCase` for django test.\nThanks to Ivan Tham for this feature!\n\n.. _v6.21.6:\n\n-------------------\n6.21.6 - 2021-09-19\n-------------------\n\nThis patch fixes some new linter warnings such as :pypi:`flake8-bugbear`'s\n``B904`` for explicit exception chaining, so tracebacks might be a bit nicer.\n\n.. _v6.21.5:\n\n-------------------\n6.21.5 - 2021-09-16\n-------------------\n\nThis release fixes ``None`` being inferred as the float64 dtype in\n:func:`~xps.from_dtype()` and :func:`~xps.arrays()` from the\n:ref:`Array API extra <array-api>`.\n\n.. _v6.21.4:\n\n-------------------\n6.21.4 - 2021-09-16\n-------------------\n\nThis release fixes the type hint for the\n:func:`@given() <hypothesis.given>` decorator\nwhen decorating an ``async`` function (:issue:`3099`).\n\n.. _v6.21.3:\n\n-------------------\n6.21.3 - 2021-09-15\n-------------------\n\nThis release improves Ghostwritten tests for builtins (:issue:`2977`).\n\n.. _v6.21.2:\n\n-------------------\n6.21.2 - 2021-09-15\n-------------------\n\nThis release deprecates use of both ``min_dims > len(shape)`` and\n``max_dims > len(shape)`` when ``allow_newaxis == False`` in\n:func:`~hypothesis.extra.numpy.basic_indices` (:issue:`3091`).\n\n.. _v6.21.1:\n\n-------------------\n6.21.1 - 2021-09-13\n-------------------\n\nThis release improves the behaviour of :func:`~hypothesis.strategies.builds`\nand :func:`~hypothesis.strategies.from_type` in certain situations involving\ndecorators (:issue:`2495` and :issue:`3029`).\n\n.. _v6.21.0:\n\n-------------------\n6.21.0 - 2021-09-11\n-------------------\n\nThis release introduces strategies for array/tensor libraries adopting the\n`Array API standard <https://data-apis.org/>`__ (:issue:`3037`).\nThey are available in :ref:`the hypothesis.extra.array_api extra <array-api>`,\nand work much like the existing :ref:`strategies for NumPy <hypothesis-numpy>`.\n\n.. _v6.20.1:\n\n-------------------\n6.20.1 - 2021-09-10\n-------------------\n\nThis patch fixes :issue:`961`, where calling ``given()`` inline on a\nbound method would fail to handle the ``self`` argument correctly.\n\n.. _v6.20.0:\n\n-------------------\n6.20.0 - 2021-09-09\n-------------------\n\nThis release allows :func:`~hypothesis.strategies.slices` to generate ``step=None``,\nand fixes an off-by-one error where the ``start`` index could be equal to ``size``.\nThis works fine for all Python sequences and Numpy arrays, but is undefined behaviour\nin the `Array API standard <https://data-apis.org/>`__ (see :pull:`3065`).\n\n.. _v6.19.0:\n\n-------------------\n6.19.0 - 2021-09-08\n-------------------\n\nThis release makes :ref:`stateful testing <stateful>` more likely to tell you\nif you do something unexpected and unsupported:\n\n- The :obj:`~hypothesis.HealthCheck.return_value` health check now applies to\n  :func:`~hypothesis.stateful.rule` and :func:`~hypothesis.stateful.initialize`\n  rules, if they don't have ``target`` bundles, as well as\n  :func:`~hypothesis.stateful.invariant`.\n- Using a :func:`~hypothesis.stateful.consumes` bundle as a ``target`` is\n  deprecated, and will be an error in a future version.\n\nIf existing code triggers these new checks, check for related bugs and\nmisunderstandings - these patterns *never* had any effect.\n\n.. _v6.18.0:\n\n-------------------\n6.18.0 - 2021-09-06\n-------------------\n\nThis release teaches :func:`~hypothesis.strategies.from_type` a neat trick:\nwhen resolving an :obj:`python:typing.Annotated` type, if one of the annotations\nis a strategy object we use that as the inferred strategy.  For example:\n\n.. code-block:: python\n\n    PositiveInt = Annotated[int, st.integers(min_value=1)]\n\nIf there are multiple strategies, we use the last outer-most annotation.\nSee :issue:`2978` and :pull:`3082` for discussion.\n\n*Requires Python 3.9 or later for*\n:func:`get_type_hints(..., include_extras=False) <typing.get_type_hints>`.\n\n.. _v6.17.4:\n\n-------------------\n6.17.4 - 2021-08-31\n-------------------\n\nThis patch makes unique :func:`~hypothesis.extra.numpy.arrays` much more\nefficient, especially when there are only a few valid elements - such as\nfor eight-bit integers (:issue:`3066`).\n\n.. _v6.17.3:\n\n-------------------\n6.17.3 - 2021-08-30\n-------------------\n\nThis patch fixes the repr of :func:`~hypothesis.extra.numpy.array_shapes`.\n\n.. _v6.17.2:\n\n-------------------\n6.17.2 - 2021-08-30\n-------------------\n\nThis patch wraps some internal helper code in our proxies decorator to prevent\nmutations of method docstrings carrying over to other instances of the respective\nmethods.\n\n.. _v6.17.1:\n\n-------------------\n6.17.1 - 2021-08-29\n-------------------\n\nThis patch moves some internal helper code in preparation for :issue:`3065`.\nThere is no user-visible change, unless you depended on undocumented internals.\n\n.. _v6.17.0:\n\n-------------------\n6.17.0 - 2021-08-27\n-------------------\n\nThis release adds type annotations to the :ref:`stateful testing <stateful>` API.\n\nThanks to Ruben Opdebeeck for this contribution!\n\n.. _v6.16.0:\n\n-------------------\n6.16.0 - 2021-08-27\n-------------------\n\nThis release adds the :class:`~hypothesis.strategies.DrawFn` type as a reusable\ntype hint for the ``draw`` argument of\n:func:`@composite <hypothesis.strategies.composite>` functions.\n\nThanks to Ruben Opdebeeck for this contribution!\n\n.. _v6.15.0:\n\n-------------------\n6.15.0 - 2021-08-22\n-------------------\n\nThis release emits a more useful error message when :func:`@given() <hypothesis.given>`\nis applied to a coroutine function, i.e. one defined using ``async def`` (:issue:`3054`).\n\nThis was previously only handled by the generic :obj:`~hypothesis.HealthCheck.return_value`\nhealth check, which doesn't direct you to use either :ref:`a custom executor <custom-function-execution>`\nor a library such as :pypi:`pytest-trio` or :pypi:`pytest-asyncio` to handle it for you.\n\n.. _v6.14.9:\n\n-------------------\n6.14.9 - 2021-08-20\n-------------------\n\nThis patch fixes a regression in Hypothesis 6.14.8, where :func:`~hypothesis.strategies.from_type`\nfailed to resolve types which inherit from multiple parametrised generic types,\naffecting the :pypi:`returns` package (:issue:`3060`).\n\n.. _v6.14.8:\n\n-------------------\n6.14.8 - 2021-08-16\n-------------------\n\nThis patch ensures that registering a strategy for a subclass of a parametrised\ngeneric type such as ``class Lines(Sequence[str]):`` will not \"leak\" into unrelated\nstrategies such as ``st.from_type(Sequence[int])`` (:issue:`2951`).\nUnfortunately this fix requires :pep:`560`, meaning Python 3.7 or later.\n\n.. _v6.14.7:\n\n-------------------\n6.14.7 - 2021-08-14\n-------------------\n\nThis patch fixes :issue:`3050`, where :pypi:`attrs` classes could\ncause an internal error in the :ref:`ghostwriter <ghostwriter>`.\n\n.. _v6.14.6:\n\n-------------------\n6.14.6 - 2021-08-07\n-------------------\n\nThis patch improves the error message for :issue:`3016`, where :pep:`585`\nbuiltin generics with self-referential forward-reference strings cannot be\nresolved to a strategy by :func:`~hypothesis.strategies.from_type`.\n\n.. _v6.14.5:\n\n-------------------\n6.14.5 - 2021-07-27\n-------------------\n\nThis patch fixes ``hypothesis.strategies._internal.types.is_a_new_type``.\nIt was failing on Python ``3.10.0b4``, where ``NewType`` is a function.\n\n.. _v6.14.4:\n\n-------------------\n6.14.4 - 2021-07-26\n-------------------\n\nThis patch fixes :func:`~hypothesis.strategies.from_type` and\n:func:`~hypothesis.strategies.register_type_strategy` for\n:obj:`python:typing.NewType` on Python 3.10, which changed the\nunderlying implementation (see :bpo:`44353` for details).\n\n.. _v6.14.3:\n\n-------------------\n6.14.3 - 2021-07-18\n-------------------\n\nThis patch updates our autoformatting tools, improving our code style without any API changes.\n\n.. _v6.14.2:\n\n-------------------\n6.14.2 - 2021-07-12\n-------------------\n\nThis patch ensures that we shorten tracebacks for tests which fail due\nto inconsistent data generation between runs (i.e. raise ``Flaky``).\n\n.. _v6.14.1:\n\n-------------------\n6.14.1 - 2021-07-02\n-------------------\n\nThis patch updates some internal type annotations.\nThere is no user-visible change.\n\n.. _v6.14.0:\n\n-------------------\n6.14.0 - 2021-06-09\n-------------------\n\nThe |Phase.explain| phase now requires shrinking to be enabled,\nand will be automatically skipped for deadline-exceeded errors.\n\n.. _v6.13.14:\n\n--------------------\n6.13.14 - 2021-06-04\n--------------------\n\nThis patch improves the :func:`~hypothesis.strategies.tuples` strategy\ntype annotations, to preserve the element types for up to length-five\ntuples (:issue:`3005`).\n\nAs for :func:`~hypothesis.strategies.one_of`, this is the best we can do\nbefore a `planned extension <https://mail.python.org/archives/list/typing-sig@python.org/thread/LOQFV3IIWGFDB7F5BDX746EZJG4VVBI3/>`__\nto :pep:`646` is released, hopefully in Python 3.11.\n\n.. _v6.13.13:\n\n--------------------\n6.13.13 - 2021-06-04\n--------------------\n\nThis patch teaches :ref:`the Ghostwriter <ghostwriter>` how to find\n:doc:`custom ufuncs <numpy:reference/ufuncs>` from *any* module that defines them,\nand that ``yaml.unsafe_load()`` does not undo ``yaml.safe_load()``.\n\n.. _v6.13.12:\n\n--------------------\n6.13.12 - 2021-06-03\n--------------------\n\nThis patch reduces the amount of internal code excluded from our test suite's\ncode coverage checks.\n\nThere is no user-visible change.\n\n.. _v6.13.11:\n\n--------------------\n6.13.11 - 2021-06-02\n--------------------\n\nThis patch removes some old internal helper code that previously existed\nto make Python 2 compatibility easier.\n\nThere is no user-visible change.\n\n.. _v6.13.10:\n\n--------------------\n6.13.10 - 2021-05-30\n--------------------\n\nThis release adjusts some internal code to help make our test suite more\nreliable.\n\nThere is no user-visible change.\n\n.. _v6.13.9:\n\n-------------------\n6.13.9 - 2021-05-30\n-------------------\n\nThis patch cleans up some internal code related to filtering strategies.\n\nThere is no user-visible change.\n\n.. _v6.13.8:\n\n-------------------\n6.13.8 - 2021-05-28\n-------------------\n\nThis patch slightly improves the performance of some internal code for\ngenerating integers.\n\n.. _v6.13.7:\n\n-------------------\n6.13.7 - 2021-05-27\n-------------------\n\nThis patch fixes a bug in :func:`~hypothesis.strategies.from_regex` that\ncaused ``from_regex(\"\", fullmatch=True)`` to unintentionally generate non-empty\nstrings (:issue:`4982`).\n\nThe only strings that completely match an empty regex pattern are empty\nstrings.\n\n.. _v6.13.6:\n\n-------------------\n6.13.6 - 2021-05-26\n-------------------\n\nThis patch fixes a bug that caused :func:`~hypothesis.strategies.integers`\nto shrink towards negative values instead of positive values in some cases.\n\n.. _v6.13.5:\n\n-------------------\n6.13.5 - 2021-05-24\n-------------------\n\nThis patch fixes rare cases where ``hypothesis write --binary-op`` could\nprint :ref:`reproducing instructions <reproducing-inputs>` from the internal\nsearch for an identity element.\n\n.. _v6.13.4:\n\n-------------------\n6.13.4 - 2021-05-24\n-------------------\n\nThis patch removes some unnecessary intermediate list-comprehensions,\nusing the latest versions of :pypi:`pyupgrade` and :pypi:`shed`.\n\n.. _v6.13.3:\n\n-------------------\n6.13.3 - 2021-05-23\n-------------------\n\nThis patch adds a ``.hypothesis`` property to invalid test functions, bringing\nthem inline with valid tests and fixing a bug where :pypi:`pytest-asyncio` would\nswallow the real error message and mistakenly raise a version incompatibility\nerror.\n\n.. _v6.13.2:\n\n-------------------\n6.13.2 - 2021-05-23\n-------------------\n\nSome of Hypothesis's numpy/pandas strategies use a ``fill`` argument to speed\nup generating large arrays, by generating a single fill value and sharing that\nvalue among many array slots instead of filling every single slot individually.\n\nWhen no ``fill`` argument is provided, Hypothesis tries to detect whether it is\nOK to automatically use the ``elements`` argument as a fill strategy, so that\nit can still use the faster approach.\n\nThis patch fixes a bug that would cause that optimization to trigger in some\ncases where it isn't 100% guaranteed to be OK.\n\nIf this makes some of your numpy/pandas tests run more slowly, try adding an\nexplicit ``fill`` argument to the relevant strategies to ensure that Hypothesis\nalways uses the faster approach.\n\n.. _v6.13.1:\n\n-------------------\n6.13.1 - 2021-05-20\n-------------------\n\nThis patch strengthens some internal import-time consistency checks for the\nbuilt-in strategies.\n\nThere is no user-visible change.\n\n.. _v6.13.0:\n\n-------------------\n6.13.0 - 2021-05-18\n-------------------\n\nThis release adds URL fragment generation to the :func:`~hypothesis.provisional.urls`\nstrategy (:issue:`2908`). Thanks to Pax (R. Margret) for contributing this patch at the\n`PyCon US Mentored Sprints <https://us.pycon.org/2021/summits/mentored-sprints/>`__!\n\n.. _v6.12.1:\n\n-------------------\n6.12.1 - 2021-05-17\n-------------------\n\nThis patch fixes :issue:`2964`, where ``.map()`` and ``.filter()`` methods\nwere omitted from the ``repr()`` of :func:`~hypothesis.strategies.just` and\n:func:`~hypothesis.strategies.sampled_from` strategies, since\n:ref:`version 5.43.7 <v5.43.7>`.\n\n.. _v6.12.0:\n\n-------------------\n6.12.0 - 2021-05-06\n-------------------\n\nThis release automatically rewrites some simple filters, such as\n``integers().filter(lambda x: x > 9)`` to the more efficient\n``integers(min_value=10)``, based on the AST of the predicate.\n\nWe continue to recommend using the efficient form directly wherever\npossible, but this should be useful for e.g. :pypi:`pandera` \"``Checks``\"\nwhere you already have a simple predicate and translating manually\nis really annoying.  See :issue:`2701` for ideas about floats and\nsimple text strategies.\n\n.. _v6.11.0:\n\n-------------------\n6.11.0 - 2021-05-06\n-------------------\n\n:func:`hypothesis.target` now returns the ``observation`` value,\nallowing it to be conveniently used inline in expressions such as\n``assert target(abs(a - b)) < 0.1``.\n\n.. _v6.10.1:\n\n-------------------\n6.10.1 - 2021-04-26\n-------------------\n\nThis patch fixes a deprecation warning if you're using recent versions\nof :pypi:`importlib-metadata` (:issue:`2934`), which we use to load\n:ref:`third-party plugins <entry-points>` such as `Pydantic's integration\n<https://docs.pydantic.dev/latest/hypothesis_plugin/>`__.\nOn older versions of :pypi:`importlib-metadata`, there is no change and\nyou don't need to upgrade.\n\n.. _v6.10.0:\n\n-------------------\n6.10.0 - 2021-04-17\n-------------------\n\nThis release teaches the :ref:`Ghostwriter <ghostwriter>` to read parameter\ntypes from Sphinx, Google, or Numpy-style structured docstrings, and improves\nsome related heuristics about how to test scientific and numerical programs.\n\n.. _v6.9.2:\n\n------------------\n6.9.2 - 2021-04-15\n------------------\n\nThis release improves the :ref:`Ghostwriter's <ghostwriter>` handling\nof exceptions, by reading ``:raises ...:`` entries in function docstrings\nand ensuring that we don't suppresss the error raised by test assertions.\n\n.. _v6.9.1:\n\n------------------\n6.9.1 - 2021-04-12\n------------------\n\nThis patch updates our autoformatting tools, improving our code style without any API changes.\n\n.. _v6.9.0:\n\n------------------\n6.9.0 - 2021-04-11\n------------------\n\nThis release teaches :func:`~hypothesis.strategies.from_type` how to see\nthrough :obj:`python:typing.Annotated`.  Thanks to Vytautas Strimaitis\nfor reporting and fixing :issue:`2919`!\n\n.. _v6.8.12:\n\n-------------------\n6.8.12 - 2021-04-11\n-------------------\n\nIf :pypi:`rich` is installed, the :command:`hypothesis write` command\nwill use it to syntax-highlight the :ref:`Ghostwritten <ghostwriter>`\ncode.\n\n.. _v6.8.11:\n\n-------------------\n6.8.11 - 2021-04-11\n-------------------\n\nThis patch improves an error message from :func:`~hypothesis.strategies.builds`\nwhen :func:`~hypothesis.strategies.from_type` would be more suitable (:issue:`2930`).\n\n.. _v6.8.10:\n\n-------------------\n6.8.10 - 2021-04-11\n-------------------\n\nThis patch updates the type annotations for :func:`~hypothesis.extra.numpy.arrays` to reflect that\n``shape: SearchStrategy[int]`` is supported.\n\n.. _v6.8.9:\n\n------------------\n6.8.9 - 2021-04-07\n------------------\n\nThis patch fixes :func:`~hypothesis.strategies.from_type` with\n:mod:`abstract types <python:abc>` which have either required but\nnon-type-annotated arguments to ``__init__``, or where\n:func:`~hypothesis.strategies.from_type` can handle some concrete\nsubclasses but not others.\n\n.. _v6.8.8:\n\n------------------\n6.8.8 - 2021-04-07\n------------------\n\nThis patch teaches :command:`hypothesis write` to check for possible roundtrips\nin several more cases, such as by looking for an inverse in the module which\ndefines the function to test.\n\n.. _v6.8.7:\n\n------------------\n6.8.7 - 2021-04-07\n------------------\n\nThis patch adds a more helpful error message if you try to call\n:func:`~hypothesis.strategies.sampled_from` on an :class:`~python:enum.Enum`\nwhich has no members, but *does* have :func:`~python:dataclasses.dataclass`-style\nannotations (:issue:`2923`).\n\n.. _v6.8.6:\n\n------------------\n6.8.6 - 2021-04-06\n------------------\n\nThe :func:`~hypothesis.strategies.fixed_dictionaries` strategy now preserves\ndict iteration order instead of sorting the keys.  This also affects the\npretty-printing of keyword arguments to :func:`@given() <hypothesis.given>`\n(:issue:`2913`).\n\n.. _v6.8.5:\n\n------------------\n6.8.5 - 2021-04-05\n------------------\n\nThis patch teaches :command:`hypothesis write` to default to ghostwriting\ntests with ``--style=pytest`` only if :pypi:`pytest` is installed, or\n``--style=unittest`` otherwise.\n\n.. _v6.8.4:\n\n------------------\n6.8.4 - 2021-04-01\n------------------\n\nThis patch adds type annotations for the :class:`~hypothesis.settings` decorator,\nto avoid an error when running mypy in strict mode.\n\n.. _v6.8.3:\n\n------------------\n6.8.3 - 2021-03-28\n------------------\n\nThis patch improves the :ref:`Ghostwriter's <ghostwriter>` handling\nof strategies to generate various fiddly types including frozensets,\nkeysviews, valuesviews, regex matches and patterns, and so on.\n\n.. _v6.8.2:\n\n------------------\n6.8.2 - 2021-03-27\n------------------\n\nThis patch fixes some internal typos.  There is no user-visible change.\n\n.. _v6.8.1:\n\n------------------\n6.8.1 - 2021-03-14\n------------------\n\nThis patch lays more groundwork for filter rewriting (:issue:`2701`).\nThere is no user-visible change... yet.\n\n.. _v6.8.0:\n\n------------------\n6.8.0 - 2021-03-11\n------------------\n\nThis release :func:`registers <hypothesis.strategies.register_type_strategy>` the\nremaining builtin types, and teaches :func:`~hypothesis.strategies.from_type` to\ntry resolving :class:`~python:typing.ForwardRef` and :class:`~python:typing.Type`\nreferences to built-in types.\n\n.. _v6.7.0:\n\n------------------\n6.7.0 - 2021-03-10\n------------------\n\nThis release teaches :class:`~hypothesis.stateful.RuleBasedStateMachine` to avoid\nchecking :func:`~hypothesis.stateful.invariant`\\ s until all\n:func:`~hypothesis.stateful.initialize` rules have been run.  You can enable checking\nof specific invariants for incompletely initialized machines by using\n``@invariant(check_during_init=True)`` (:issue:`2868`).\n\nIn previous versions, it was possible if awkward to implement this behaviour\nusing :func:`~hypothesis.stateful.precondition` and an auxiliary variable.\n\n.. _v6.6.1:\n\n------------------\n6.6.1 - 2021-03-09\n------------------\n\nThis patch improves the error message when :func:`~hypothesis.strategies.from_type`\nfails to resolve a forward-reference inside a :class:`python:typing.Type`\nsuch as ``Type[\"int\"]`` (:issue:`2565`).\n\n.. _v6.6.0:\n\n------------------\n6.6.0 - 2021-03-07\n------------------\n\nThis release makes it an explicit error to apply :func:`~hypothesis.stateful.invariant`\nto a :func:`~hypothesis.stateful.rule` or :func:`~hypothesis.stateful.initialize` rule\nin :ref:`stateful testing <stateful>`.  Such a combination had unclear semantics,\nespecially in combination with :func:`~hypothesis.stateful.precondition`, and was never\nmeant to be allowed (:issue:`2681`).\n\n.. _v6.5.0:\n\n------------------\n6.5.0 - 2021-03-07\n------------------\n\nThis release adds |Phase.explain|, in which Hypothesis\nattempts to explain *why* your test failed by pointing to suspicious lines\nof code (i.e. those which were always, and only, run on failing inputs).\nWe plan to include \"generalising\" failing examples in this phase in a\nfuture release (:issue:`2192`).\n\n.. _v6.4.3:\n\n------------------\n6.4.3 - 2021-03-04\n------------------\n\nThis patch fixes :issue:`2794`, where nesting :func:`~hypothesis.strategies.deferred`\nstrategies within :func:`~hypothesis.strategies.recursive` strategies could\ntrigger an internal assertion.  While it was always possible to get the same\nresults from a more sensible strategy, the convoluted form now works too.\n\n.. _v6.4.2:\n\n------------------\n6.4.2 - 2021-03-04\n------------------\n\nThis patch fixes several problems with ``mypy`` when `--no-implicit-reexport <https://mypy.readthedocs.io/en/stable/command_line.html#cmdoption-mypy-no-implicit-reexport>`_ was activated in user projects.\n\nThanks to Nikita Sobolev for fixing :issue:`2884`!\n\n.. _v6.4.1:\n\n------------------\n6.4.1 - 2021-03-04\n------------------\n\nThis patch fixes an exception that occurs when using type unions of\nthe :pypi:`typing-extensions` ``Literal`` backport on Python 3.6.\n\nThanks to Ben Anhalt for identifying and fixing this bug.\n\n.. _v6.4.0:\n\n------------------\n6.4.0 - 2021-03-02\n------------------\n\nThis release fixes :ref:`stateful testing methods <stateful>` with multiple\n:func:`~hypothesis.stateful.precondition` decorators.  Previously, only the\nouter-most precondition was checked (:issue:`2681`).\n\n.. _v6.3.4:\n\n------------------\n6.3.4 - 2021-02-28\n------------------\n\nThis patch refactors some internals of :class:`~hypothesis.stateful.RuleBasedStateMachine`.\nThere is no change to the public API or behaviour.\n\n.. _v6.3.3:\n\n------------------\n6.3.3 - 2021-02-26\n------------------\n\nThis patch moves some internal code, so that future work can avoid\ncreating import cycles.  There is no user-visible change.\n\n.. _v6.3.2:\n\n------------------\n6.3.2 - 2021-02-25\n------------------\n\nThis patch enables :func:`~hypothesis.strategies.register_type_strategy` for subclasses of\n:obj:`python:typing.TypedDict`.  Previously, :func:`~hypothesis.strategies.from_type`\nwould ignore the registered strategy (:issue:`2872`).\n\nThanks to Ilya Lebedev for identifying and fixing this bug!\n\n.. _v6.3.1:\n\n------------------\n6.3.1 - 2021-02-24\n------------------\n\nThis release lays the groundwork for automatic rewriting of simple filters,\nfor example converting ``integers().filter(lambda x: x > 9)`` to\n``integers(min_value=10)``.\n\nNote that this is **not supported yet**, and we will continue to recommend\nwriting the efficient form directly wherever possible - predicate rewriting\nis provided mainly for the benefit of downstream libraries which would\notherwise have to implement it for themselves (e.g. :pypi:`pandera` and\n:pypi:`icontract-hypothesis`).  See :issue:`2701` for details.\n\n.. _v6.3.0:\n\n------------------\n6.3.0 - 2021-02-20\n------------------\n\nThe Hypothesis :pypi:`pytest` plugin now requires pytest version 4.6 or later.\nIf the plugin detects an earlier version of pytest, it will automatically\ndeactivate itself.\n\n`(4.6.x is the earliest pytest branch that still accepts community bugfixes.)\n<https://docs.pytest.org/en/6.2.x/py27-py34-deprecation.html>`__\n\nHypothesis-based tests should continue to work in earlier versions of\npytest, but enhanced integrations provided by the plugin\n(such as ``--hypothesis-show-statistics`` and other command-line flags)\nwill no longer be available in obsolete pytest versions.\n\n.. _v6.2.0:\n\n------------------\n6.2.0 - 2021-02-12\n------------------\n\nIf you use :pypi:`pytest-html`, Hypothesis now includes the\n:ref:`summary statistics for each test <statistics>` in the HTML report,\nwhether or not the ``--hypothesis-show-statistics`` argument was passed\nto show them in the command-line output.\n\n.. _v6.1.1:\n\n------------------\n6.1.1 - 2021-01-31\n------------------\n\nThis patch updates our automatic code formatting to use :pypi:`shed`,\nwhich includes :pypi:`autoflake`, :pypi:`black`, :pypi:`isort`, and\n:pypi:`pyupgrade` (:issue:`2780`).\n\n.. _v6.1.0:\n\n------------------\n6.1.0 - 2021-01-29\n------------------\n\nThis release teaches Hypothesis to distinguish between errors based on the\n`__cause__ or __context__ of otherwise identical exceptions\n<https://docs.python.org/3/library/exceptions.html>`__, which is particularly\nuseful when internal errors can be wrapped by a library-specific or semantically\nappropriate exception such as:\n\n.. code-block:: python\n\n    try:\n        do_the_thing(foo, timeout=10)\n    except Exception as err:\n        raise FooError(\"Failed to do the thing\") from err\n\nEarlier versions of Hypothesis only see the ``FooError``, while we can now\ndistinguish a ``FooError`` raised because of e.g. an internal assertion from\none raised because of a ``TimeoutExceeded`` exception.\n\n.. _v6.0.4:\n\n------------------\n6.0.4 - 2021-01-27\n------------------\n\nThis release prevents a race condition inside :func:`~hypothesis.strategies.recursive` strategies.\nThe race condition occurs when the same :func:`~hypothesis.strategies.recursive` strategy is shared among tests\nthat are running in multiple threads (:issue:`2717`).\n\n.. _v6.0.3:\n\n------------------\n6.0.3 - 2021-01-23\n------------------\n\nThis patch improves the type annotations for :func:`~hypothesis.strategies.one_of`,\nby adding overloads to handle up to five distinct arguments as\n:obj:`~python:typing.Union` before falling back to :obj:`~python:typing.Any`,\nas well as annotating the ``|`` (``__or__``) operator for strategies (:issue:`2765`).\n\n.. _v6.0.2:\n\n------------------\n6.0.2 - 2021-01-14\n------------------\n\nThis release makes some small improvements to how filtered strategies work. It should improve the performance of shrinking filtered strategies,\nand may under some (probably rare) circumstances improve the diversity of generated examples.\n\n.. _v6.0.1:\n\n------------------\n6.0.1 - 2021-01-13\n------------------\n\nThis patch fixes an interaction where our :ref:`test statistics <statistics>`\nhandling made Pytest's ``--junit-xml`` output fail to validate against the\nstrict ``xunit2`` schema (:issue:`1975`).\n\n.. _v6.0.0:\n\n------------------\n6.0.0 - 2021-01-08\n------------------\n\nWelcome to the next major version of Hypothesis!\n\nThere are no new features here, as we release those in minor versions.\nInstead, 6.0 is a chance for us to remove deprecated features (many already\nconverted into no-ops), and turn a variety of warnings into errors.\n\nIf you were running on the last version of Hypothesis 5.x *without any\nHypothesis deprecation warnings*, this will be a very boring upgrade.\n**In fact, nothing will change for you at all.**\n\nChanges\n~~~~~~~\n- Many functions now use :pep:`3102` keyword-only arguments where passing positional\n  arguments :ref:`was deprecated since 5.5 <v5.5.0>`.\n- :func:`hypothesis.extra.django.from_model` no longer accepts ``model`` as a\n  keyword argument, where it could conflict with fields named \"model\".\n- :func:`~hypothesis.strategies.randoms` now defaults to ``use_true_random=False``.\n- :func:`~hypothesis.strategies.complex_numbers` no longer accepts\n  ``min_magnitude=None``; either use ``min_magnitude=0`` or just omit the argument.\n- ``hypothesis.provisional.ip4_addr_strings`` and ``ip6_addr_strings`` are removed\n  in favor of :func:`ip_addresses(v=...).map(str) <hypothesis.strategies.ip_addresses>`.\n- :func:`~hypothesis.strategies.register_type_strategy` no longer accepts generic\n  types with type arguments, which were always pretty badly broken.\n- Using function-scoped pytest fixtures is now a health-check error, instead of a warning.\n\n.. tip::\n    The :command:`hypothesis codemod` command can automatically refactor your code,\n    particularly to convert positional to keyword arguments where those are now\n    required.\n\nHypothesis 5.x\n==============\n\n.. _v5.49.0:\n\n-------------------\n5.49.0 - 2021-01-07\n-------------------\n\nThis release adds the\n:obj:`~hypothesis.HealthCheck.function_scoped_fixture` health check value,\nwhich can be used to suppress the existing warning that appears when\n:func:`@given <hypothesis.given>` is applied to a test that uses pytest\nfunction-scoped fixtures.\n\n(This warning exists because function-scoped fixtures only run once per\nfunction, not once per example, which is usually unexpected and can cause\nsubtle problems.)\n\nWhen this warning becomes a health check error in a future release, suppressing\nit via Python warning settings will no longer be possible.\nIn the rare case that once-per-function behaviour is intended, it will still be\npossible to use :obj:`~hypothesis.HealthCheck.function_scoped_fixture` to\nopt out of the health check error for specific tests.\n\n.. _v5.48.0:\n\n-------------------\n5.48.0 - 2021-01-06\n-------------------\n\nThis release adds :func:`hypothesis.currently_in_test_context`, which can be used\nto check whether the calling code is currently running inside an\n:func:`@given <hypothesis.given>` or :ref:`stateful <stateful>` test.\n\nThis is most useful for third-party integrations and assertion helpers which may\nwish to use :func:`~hypothesis.assume` or :func:`~hypothesis.target`, without also\nrequiring that the helper only be used from property-based tests (:issue:`2581`).\n\n.. _v5.47.0:\n\n-------------------\n5.47.0 - 2021-01-05\n-------------------\n\nThis release upgrades the import logic for :ref:`ghostwritten tests <ghostwriter>`,\nhandling many cases where imports would previously be missing or from unexpected\nlocations.\n\n.. _v5.46.0:\n\n-------------------\n5.46.0 - 2021-01-04\n-------------------\n\nThis release upgrades :func:`~hypothesis.strategies.from_type`, to infer\nstrategies for type-annotated arguments even if they have defaults when\nit otherwise falls back to :func:`~hypothesis.strategies.builds`\n(:issue:`2708`).\n\n.. _v5.45.0:\n\n-------------------\n5.45.0 - 2021-01-04\n-------------------\n\nThis release adds the :ref:`codemods` extra, which you can use to\ncheck for and automatically fix issues such as use of deprecated\nHypothesis APIs (:issue:`2705`).\n\n.. _v5.44.0:\n\n-------------------\n5.44.0 - 2021-01-03\n-------------------\n\nThis patch fixes :func:`~hypothesis.strategies.from_type` with\nthe :pypi:`typing-extensions` ``Literal`` backport on Python 3.6.\n\n.. _v5.43.9:\n\n-------------------\n5.43.9 - 2021-01-02\n-------------------\n\nThis patch fixes :issue:`2722`, where certain orderings of\n:func:`~hypothesis.strategies.register_type_strategy`,\n:class:`~python:typing.ForwardRef`, and :func:`~hypothesis.strategies.from_type`\ncould trigger an internal error.\n\n.. _v5.43.8:\n\n-------------------\n5.43.8 - 2021-01-02\n-------------------\n\nThis patch makes some strategies for collections with a uniqueness constraint\nmuch more efficient, including ``dictionaries(keys=sampled_from(...), values=..)``\nand ``lists(tuples(sampled_from(...), ...), unique_by=lambda x: x[0])``.\n(related to :issue:`2036`)\n\n.. _v5.43.7:\n\n-------------------\n5.43.7 - 2021-01-02\n-------------------\n\nThis patch extends our faster special case for\n:func:`~hypothesis.strategies.sampled_from` elements in unique\n:func:`~hypothesis.strategies.lists` to account for chains of\n``.map(...)`` and ``.filter(...)`` calls (:issue:`2036`).\n\n.. _v5.43.6:\n\n-------------------\n5.43.6 - 2021-01-02\n-------------------\n\nThis patch improves the type annotations on :func:`~hypothesis.assume`\nand :func:`@reproduce_failure() <hypothesis.reproduce_failure>`.\n\n.. _v5.43.5:\n\n-------------------\n5.43.5 - 2021-01-01\n-------------------\n\nThis patch updates our copyright headers to include 2021.  Happy new year!\n\n.. _v5.43.4:\n\n-------------------\n5.43.4 - 2020-12-24\n-------------------\n\nThis change fixes a documentation error in the\n:obj:`~hypothesis.settings.database` setting.\n\nThe previous documentation suggested that callers could specify a database\npath string, or the special string ``\":memory:\"``, but this setting has\nnever actually allowed string arguments.\n\nPermitted values are ``None``, and instances of\n:class:`~hypothesis.database.ExampleDatabase`.\n\n.. _v5.43.3:\n\n-------------------\n5.43.3 - 2020-12-11\n-------------------\n\nThis patch fixes :issue:`2696`, an internal error triggered when the\n:obj:`@example <hypothesis.example>` decorator was used and the\n:obj:`~hypothesis.settings.verbosity` setting was ``quiet``.\n\n.. _v5.43.2:\n\n-------------------\n5.43.2 - 2020-12-10\n-------------------\n\nThis patch improves the error message from the\n:func:`~hypothesis.extra.pandas.data_frames` strategy when both the ``rows``\nand ``columns`` arguments are given, but there is a missing entry in ``rows``\nand the corresponding column has no ``fill`` value (:issue:`2678`).\n\n.. _v5.43.1:\n\n-------------------\n5.43.1 - 2020-12-10\n-------------------\n\nThis patch improves the error message if :func:`~hypothesis.strategies.builds`\nis passed an :class:`~python:enum.Enum` which cannot be called without arguments,\nto suggest using :func:`~hypothesis.strategies.sampled_from` (:issue:`2693`).\n\n.. _v5.43.0:\n\n-------------------\n5.43.0 - 2020-12-09\n-------------------\n\nThis release adds new :func:`~hypothesis.strategies.timezones` and\n:func:`~hypothesis.strategies.timezone_keys` strategies (:issue:`2630`)\nbased on the new :mod:`python:zoneinfo` module in Python 3.9.\n\n``pip install hypothesis[zoneinfo]`` will ensure that you have the\nappropriate backports installed if you need them.\n\n.. _v5.42.3:\n\n-------------------\n5.42.3 - 2020-12-09\n-------------------\n\nThis patch fixes an internal error in :func:`~hypothesis.strategies.datetimes`\nwith ``allow_imaginary=False`` where the ``timezones`` argument can generate\n``tzinfo=None`` (:issue:`2662`).\n\n.. _v5.42.2:\n\n-------------------\n5.42.2 - 2020-12-09\n-------------------\n\nThis patch teaches :func:`hypothesis.extra.django.from_field` to infer\nmore efficient strategies by inspecting (not just filtering by) field\nvalidators for numeric and string fields (:issue:`1116`).\n\n.. _v5.42.1:\n\n-------------------\n5.42.1 - 2020-12-09\n-------------------\n\nThis patch refactors :class:`hypothesis.settings` to use type-annotated\nkeyword arguments instead of ``**kwargs``, which makes tab-completion\nmuch more useful - as well as type-checkers like :pypi:`mypy`.\n\n.. _v5.42.0:\n\n-------------------\n5.42.0 - 2020-12-09\n-------------------\n\nThis patch teaches the :func:`~hypothesis.extra.ghostwriter.magic` ghostwriter\nto recognise \"en/de\" function roundtrips other than the common encode/decode\npattern, such as encrypt/decrypt or, encipher/decipher.\n\n.. _v5.41.5:\n\n-------------------\n5.41.5 - 2020-12-05\n-------------------\n\nThis patch adds a performance optimisation to avoid saving redundant\nseeds when using :ref:`the .fuzz_one_input hook <fuzz_one_input>`.\n\n.. _v5.41.4:\n\n-------------------\n5.41.4 - 2020-11-28\n-------------------\n\nThis patch fixes :issue:`2657`, where passing unicode patterns compiled with\n:obj:`python:re.IGNORECASE` to :func:`~hypothesis.strategies.from_regex` could\ntrigger an internal error when casefolding a character creates a longer string\n(e.g. ``\"\\u0130\".lower() -> \"i\\u0370\"``).\n\n.. _v5.41.3:\n\n-------------------\n5.41.3 - 2020-11-18\n-------------------\n\nThis patch adds a final fallback clause to :ref:`our plugin logic <entry-points>`\nto fail with a warning rather than error on Python < 3.8 when neither the\n:pypi:`importlib-metadata` (preferred) or :pypi:`setuptools` (fallback)\npackages are available.\n\n.. _v5.41.2:\n\n-------------------\n5.41.2 - 2020-11-08\n-------------------\n\nThis patch fixes :func:`~hypothesis.provisional.urls` strategy ensuring that\n``~`` (tilde) is treated as one of the url-safe characters (:issue:`2658`).\n\n.. _v5.41.1:\n\n-------------------\n5.41.1 - 2020-11-03\n-------------------\n\nThis patch improves our :ref:`CLI help and documentation <hypothesis-cli>`.\n\n.. _v5.41.0:\n\n-------------------\n5.41.0 - 2020-10-30\n-------------------\n\nHypothesis now shrinks examples where the error is raised while drawing from\na strategy.  This makes complicated custom strategies *much* easier to debug,\nat the cost of a slowdown for use-cases where you catch and ignore such errors.\n\n.. _v5.40.0:\n\n-------------------\n5.40.0 - 2020-10-30\n-------------------\n\nThis release teaches :func:`~hypothesis.strategies.from_type` how to handle\n:class:`~python:typing.ChainMap`, :class:`~python:typing.Counter`,\n:class:`~python:typing.Deque`, :class:`~python:typing.Generator`,\n:class:`~python:typing.Match`, :class:`~python:typing.OrderedDict`,\n:class:`~python:typing.Pattern`, and :class:`~python:collections.abc.Set`\n(:issue:`2654`).\n\n.. _v5.39.0:\n\n-------------------\n5.39.0 - 2020-10-30\n-------------------\n\n:func:`~hypothesis.strategies.from_type` now knows how to resolve :pep:`585`\nparameterized standard collection types, which are new in Python 3.9\n(:issue:`2629`).\n\n.. _v5.38.1:\n\n-------------------\n5.38.1 - 2020-10-26\n-------------------\n\nThis patch fixes :func:`~hypothesis.strategies.builds`, so that when passed\n:obj:`~hypothesis.infer` for an argument with a non-:obj:`~python:typing.Optional`\ntype annotation and a default value of ``None`` to build a class which defines\nan explicit ``__signature__`` attribute, either ``None`` or that type may be\ngenerated.\n\nThis is unlikely to happen unless you are using :pypi:`pydantic` (:issue:`2648`).\n\n.. _v5.38.0:\n\n-------------------\n5.38.0 - 2020-10-24\n-------------------\n\nThis release improves our support for :func:`@st.composite <hypothesis.strategies.composite>`\non a :obj:`python:classmethod` or :obj:`python:staticmethod` (:issue:`2578`).\n\n.. _v5.37.5:\n\n-------------------\n5.37.5 - 2020-10-24\n-------------------\n\nThis patch fixes :func:`~hypothesis.strategies.from_type` with\n:class:`Iterable[T] <python:typing.Iterable>` (:issue:`2645`).\n\n.. _v5.37.4:\n\n-------------------\n5.37.4 - 2020-10-20\n-------------------\n\nThis patch teaches the :func:`~hypothesis.extra.ghostwriter.magic` ghostwriter\nto recognise that pairs of functions like :func:`~python:colorsys.rgb_to_hsv`\nand :func:`~python:colorsys.hsv_to_rgb` should\n:func:`~hypothesis.extra.ghostwriter.roundtrip`.\n\n.. _v5.37.3:\n\n-------------------\n5.37.3 - 2020-10-15\n-------------------\n\nThis patch improves :func:`~hypothesis.strategies.builds` and\n:func:`~hypothesis.strategies.from_type` support for explicitly defined ``__signature__``\nattributes, from :ref:`version 5.8.3 <v5.8.3>`, to support generic types from the\n:mod:`python:typing` module.\n\nThanks to Rónán Carrigan for identifying and fixing this problem!\n\n.. _v5.37.2:\n\n-------------------\n5.37.2 - 2020-10-14\n-------------------\n\nThis patch fixes :func:`~hypothesis.extra.lark.from_lark` with version\n0.10.1+ of the :pypi:`lark-parser` package.\n\n.. _v5.37.1:\n\n-------------------\n5.37.1 - 2020-10-07\n-------------------\n\nThis patch fixes some broken links in the :mod:`~hypothesis.extra.lark`\nextra documentation.\n\n.. _v5.37.0:\n\n-------------------\n5.37.0 - 2020-10-03\n-------------------\n\nThis release adds a new :class:`~hypothesis.extra.redis.RedisExampleDatabase`,\nalong with the :class:`~hypothesis.database.ReadOnlyDatabase`\nand :class:`~hypothesis.database.MultiplexedDatabase` helpers, to support\nteam workflows where failing examples can be seamlessly shared between everyone\non the team - and your CI servers or buildbots.\n\n.. _v5.36.2:\n\n-------------------\n5.36.2 - 2020-10-02\n-------------------\n\nThis patch ensures that if the :ref:`\"hypothesis\" entry point <entry-points>`\nis callable, we call it after importing it.  You can still use non-callable\nentry points (like modules), which are only imported.\n\nWe also prefer `importlib.metadata <https://docs.python.org/3/library/importlib.metadata.html>`__\nor :pypi:`the backport <importlib-metadata>` over `pkg_resources\n<https://setuptools.pypa.io/en/latest/pkg_resources.html>`__,\nwhich makes ``import hypothesis`` around 200 milliseconds faster\n(:issue:`2571`).\n\n.. _v5.36.1:\n\n-------------------\n5.36.1 - 2020-09-25\n-------------------\n\nThis patch adds some helpful suggestions to error messages you might see\nwhile learning to use the :obj:`@example() <hypothesis.example>` decorator\n(:issue:`2611`) or the :func:`~hypothesis.strategies.one_of` strategy.\n\n.. _v5.36.0:\n\n-------------------\n5.36.0 - 2020-09-24\n-------------------\n\nThis release upgrades the :func:`~hypothesis.extra.numpy.from_dtype` strategy\nto pass optional ``**kwargs`` to the inferred strategy, and upgrades the\n:func:`~hypothesis.extra.numpy.arrays` strategy to accept an ``elements=kwargs``\ndict to pass through to :func:`~hypothesis.extra.numpy.from_dtype`.\n\n``arrays(floating_dtypes(), shape, elements={\"min_value\": -10, \"max_value\": 10})``\nis a particularly useful pattern, as it allows for any floating dtype without\ntriggering the roundoff warning for smaller types or sacrificing variety for\nlarger types (:issue:`2552`).\n\n.. _v5.35.4:\n\n-------------------\n5.35.4 - 2020-09-21\n-------------------\n\nThis patch reformats our code with the latest :pypi:`black` to\ntake advantage of the support for magic trailing commas.\n\n.. _v5.35.3:\n\n-------------------\n5.35.3 - 2020-09-15\n-------------------\n\nThis release significantly improves the performance of Hypothesis's internal\nimplementation of automaton learning. However this code does not run as part\nof the user-accessible API so this has no user-visible impact.\n\n.. _v5.35.2:\n\n-------------------\n5.35.2 - 2020-09-14\n-------------------\n\nThis patch ensures that, when the ``generate`` :obj:`~hypothesis.settings.phases`\nis disabled, we can replay up to :obj:`~hypothesis.settings.max_examples` examples\nfrom the database - which is very useful when\n:ref:`using Hypothesis with a fuzzer <fuzz_one_input>`.\n\nThanks to Afrida Tabassum for fixing :issue:`2585`!\n\n.. _v5.35.1:\n\n-------------------\n5.35.1 - 2020-09-14\n-------------------\n\nThis patch changes some internal :obj:`python:struct.Struct.format` strings\nfrom ``bytes`` to ``str``, to avoid :class:`python:BytesWarning` when running\n`python -bb <https://docs.python.org/3/using/cmdline.html#cmdoption-b>`__.\n\nThanks to everyone involved in `pytest-xdist issue 596\n<https://github.com/pytest-dev/pytest-xdist/issues/596>`__,\n:bpo:`16349`, :bpo:`21071`, and :bpo:`41777` for their work on this -\nit was a remarkably subtle issue!\n\n.. _v5.35.0:\n\n-------------------\n5.35.0 - 2020-09-11\n-------------------\n\nThe :func:`~hypothesis.target` function now accepts integers as well as floats.\n\n.. _v5.34.1:\n\n-------------------\n5.34.1 - 2020-09-11\n-------------------\n\nThis patch adds explicit :obj:`~python:typing.Optional` annotations to our public API,\nto better support users who run :pypi:`mypy` with ``--strict`` or ``no_implicit_optional=True``.\n\nThanks to Krzysztof Przybyła for bringing this to our attention and writing the patch!\n\n.. _v5.34.0:\n\n-------------------\n5.34.0 - 2020-09-11\n-------------------\n\nThis release drops support for Python 3.5, which `reached end of life upstream\n<https://devguide.python.org/#status-of-python-branches>`__ on 2020-09-13.\n\n.. _v5.33.2:\n\n-------------------\n5.33.2 - 2020-09-09\n-------------------\n\nThis patch fixes a problem with :func:`~hypothesis.strategies.builds` that was not able to\ngenerate valid data for annotated classes with constructors.\n\nThanks to Nikita Sobolev for fixing :issue:`2603`!\n\n.. _v5.33.1:\n\n-------------------\n5.33.1 - 2020-09-07\n-------------------\n\nThis patch improves the error message from the :command:`hypothesis write`\ncommand if :pypi:`black` (required for the :ref:`ghostwriter <ghostwriter>`)\nis not installed.\n\nThanks to Nikita Sobolev for fixing :issue:`2604`!\n\n.. _v5.33.0:\n\n-------------------\n5.33.0 - 2020-09-06\n-------------------\n\nWhen reporting failing examples, or tried examples in verbose mode, Hypothesis now\nidentifies which were from :obj:`@example(...) <hypothesis.example>` explicit examples.\n\n.. _v5.32.1:\n\n-------------------\n5.32.1 - 2020-09-06\n-------------------\n\nThis patch contains some internal refactoring.\nThanks to Felix Sheldon for fixing :issue:`2516`!\n\n.. _v5.32.0:\n\n-------------------\n5.32.0 - 2020-09-04\n-------------------\n\nAn array drawn from :func:`~hypothesis.extra.numpy.arrays` will own its own memory; previously most arrays returned by\nthis strategy were views.\n\n.. _v5.31.0:\n\n-------------------\n5.31.0 - 2020-09-04\n-------------------\n\n:func:`~hypothesis.strategies.builds` will use the ``__signature__`` attribute of\nthe target, if it exists, to retrieve type hints.\nPreviously :func:`python:typing.get_type_hints`, was used by default.\nIf argument names varied between the ``__annotations__`` and ``__signature__``,\nthey would not be supplied to the target.\n\nThis was particularly an issue for :pypi:`pydantic` models which use an\n`alias generator <https://docs.pydantic.dev/latest/api/config/#pydantic.alias_generators>`__.\n\n.. _v5.30.1:\n\n-------------------\n5.30.1 - 2020-09-04\n-------------------\n\nThis patch makes the :ref:`ghostwriter <ghostwriter>` much more robust when\npassed unusual modules.\n\n- improved support for non-resolvable type annotations\n- :func:`~hypothesis.extra.ghostwriter.magic` can now write\n  :func:`~hypothesis.extra.ghostwriter.equivalent` tests\n- running :func:`~hypothesis.extra.ghostwriter.magic` on modules where some\n  names in ``__all__`` are undefined skips such names, instead of raising an error\n- :func:`~hypothesis.extra.ghostwriter.magic` now knows to skip mocks\n- improved handling of import-time errors found by the ghostwriter CLI\n\n.. _v5.30.0:\n\n-------------------\n5.30.0 - 2020-08-30\n-------------------\n\n:func:`~hypothesis.strategies.register_type_strategy` now supports\n:class:`python:typing.TypeVar`, which was previously hard-coded, and allows a\nvariety of types to be generated for an unconstrained :class:`~python:typing.TypeVar`\ninstead of just :func:`~hypothesis.strategies.text`.\n\nThanks again to Nikita Sobolev for all your work on advanced types!\n\n.. _v5.29.4:\n\n-------------------\n5.29.4 - 2020-08-28\n-------------------\n\nThis release fixes some hard to trigger bugs in Hypothesis's automata learning\ncode. This code is only run as part of the Hypothesis build process, and not\nfor user code, so this release has no user visible impact.\n\n.. _v5.29.3:\n\n-------------------\n5.29.3 - 2020-08-27\n-------------------\n\nThis patch adds type annotations to the :ref:`hypothesis.database <database>`\nmodule.  There is no runtime change, but your typechecker might notice.\n\n.. _v5.29.2:\n\n-------------------\n5.29.2 - 2020-08-27\n-------------------\n\nThis patch tracks some additional information in Hypothesis internals,\nand has no user-visible impact.\n\n.. _v5.29.1:\n\n-------------------\n5.29.1 - 2020-08-27\n-------------------\n\nThis release fixes a bug in some Hypothesis internal support code for learning\nautomata. This mostly doesn't have any user visible impact, although it slightly\naffects the learned shrink passes so shrinking may be subtly different.\n\n.. _v5.29.0:\n\n-------------------\n5.29.0 - 2020-08-24\n-------------------\n\nThis release adds support for :ref:`entry-points`, which allows for smoother\nintegration of third-party Hypothesis extensions and external libraries.\nUnless you're publishing a library with Hypothesis integration, you'll\nprobably only ever use this indirectly!\n\n.. _v5.28.0:\n\n-------------------\n5.28.0 - 2020-08-24\n-------------------\n\n:func:`~hypothesis.strategies.from_type` can now resolve :class:`~python:typing.TypeVar`\ninstances when the ``bound`` is a :class:`~python:typing.ForwardRef`, so long as that name\nis in fact defined in the same module as the typevar (no ``TYPE_CHECKING`` tricks, sorry).\nThis feature requires Python 3.7 or later.\n\nThanks to Zac Hatfield-Dodds and Nikita Sobolev for this feature!\n\n.. _v5.27.0:\n\n-------------------\n5.27.0 - 2020-08-20\n-------------------\n\nThis patch adds two new :ref:`ghostwriters <ghostwriter>` to test\n:wikipedia:`binary operations <Binary_operation>`, like :func:`python:operator.add`,\nand Numpy :doc:`ufuncs <numpy:reference/ufuncs>` and :doc:`gufuncs\n<numpy:reference/c-api/generalized-ufuncs>` like :data:`np.matmul() <numpy:numpy.matmul>`.\n\n.. _v5.26.1:\n\n-------------------\n5.26.1 - 2020-08-19\n-------------------\n\nThis release improves the performance of some methods in Hypothesis's internal\nautomaton library. These are currently only lightly used by user code, but\nthis may result in slightly faster shrinking.\n\n.. _v5.26.0:\n\n-------------------\n5.26.0 - 2020-08-17\n-------------------\n\n:func:`~hypothesis.strategies.register_type_strategy` no longer accepts\nparametrised user-defined generic types, because the resolution logic\nwas quite badly broken (:issue:`2537`).\n\nInstead of registering a strategy for e.g. ``MyCollection[int]``, you\nshould register a *function* for ``MyCollection`` and `inspect the type\nparameters within that function <https://stackoverflow.com/q/48572831>`__.\n\nThanks to Nikita Sobolev for the bug report, design assistance, and\npull request to implement this feature!\n\n.. _v5.25.0:\n\n-------------------\n5.25.0 - 2020-08-16\n-------------------\n\nTired of writing tests?  Or new to Hypothesis and not sure where to start?\n\nThis release is for you!  With our new :ref:`Ghostwriter functions <ghostwriter>`\nand :command:`hypothesis write ...` :ref:`command-line interface <hypothesis-cli>`,\nyou can stop writing tests entirely... or take the source code Hypothesis\nwrites for you as a starting point.\n\nThis has been in the works for months, from :issue:`2118` to versions\n:ref:`5.18.3 <v5.18.3>`, :ref:`5.23.5 <v5.23.5>`, and :ref:`5.23.5 <v5.23.5>` -\nparticular thanks to the many people who reviewed pull requests or commented on\ndemos, and to Timothy Crosley's :pypi:`hypothesis-auto` project for inspiration.\n\n.. _v5.24.4:\n\n-------------------\n5.24.4 - 2020-08-14\n-------------------\n\nThis patch adds yet more internal functions to support a new feature\nwe're working on, like :ref:`version 5.18.3 <v5.18.3>` and\n:ref:`version 5.23.6 <v5.23.6>`.  We promise it's worth the wait!\n\n.. _v5.24.3:\n\n-------------------\n5.24.3 - 2020-08-13\n-------------------\n\nThis release fixes a small internal bug in Hypothesis's internal automaton library.\nFortunately this bug was currently impossible to hit in user facing code, so this\nhas no user visible impact.\n\n.. _v5.24.2:\n\n-------------------\n5.24.2 - 2020-08-12\n-------------------\n\nThis release improves shrink quality by allowing Hypothesis to automatically learn new shrink passes\nfor difficult to shrink tests.\n\nThe automatic learning is not currently accessible in user code (it still needs significant work\non robustness and performance before it is ready for that), but this release includes learned\npasses that should improve shrinking quality for tests which use any of the\n:func:`~hypothesis.strategies.text`, :func:`~hypothesis.strategies.floats`,\n:func:`~hypothesis.strategies.datetimes`, :func:`~hypothesis.strategies.emails`,\nand :func:`~hypothesis.strategies.complex_numbers` strategies.\n\n.. _v5.24.1:\n\n-------------------\n5.24.1 - 2020-08-12\n-------------------\n\nThis patch updates some docstrings, without changing runtime behaviour.\n\n.. _v5.24.0:\n\n-------------------\n5.24.0 - 2020-08-10\n-------------------\n\nThe :func:`~hypothesis.strategies.functions` strategy has a new argument\n``pure=True``, which ensures that the same return value is generated for\nidentical calls to the generated function (:issue:`2538`).\n\nThanks to Zac Hatfield-Dodds and Nikita Sobolev for this feature!\n\n.. _v5.23.12:\n\n--------------------\n5.23.12 - 2020-08-10\n--------------------\n\nThis release removes a number of Hypothesis's internal \"shrink passes\" - transformations\nit makes to a generated test case during shrinking - which appeared to be redundant with\nother transformations.\n\nIt is unlikely that you will see much impact from this. If you do, it will likely show up\nas a change in shrinking performance (probably slower, maybe faster), or possibly in\nworse shrunk results. If you encounter the latter, please let us know.\n\n.. _v5.23.11:\n\n--------------------\n5.23.11 - 2020-08-04\n--------------------\n\nThis release fixes a bug in some internal Hypothesis support code. It has no user visible impact.\n\n.. _v5.23.10:\n\n--------------------\n5.23.10 - 2020-08-04\n--------------------\n\nThis release improves the quality of shrunk test cases in some special cases.\nSpecifically, it should get shrinking unstuck in some scenarios which require\nsimultaneously changing two parts of the generated test case.\n\n.. _v5.23.9:\n\n-------------------\n5.23.9 - 2020-08-03\n-------------------\n\nThis release improves the performance of some internal support code. It has no user visible impact,\nas that code is not currently run during normal Hypothesis operation.\n\n.. _v5.23.8:\n\n-------------------\n5.23.8 - 2020-07-31\n-------------------\n\nThis release adds a heuristic to detect when shrinking has finished despite the fact\nthat there are many more possible transformations to try. This will be particularly\nuseful for tests where the minimum failing test case is very large despite there being\nmany smaller test cases possible, where it is likely to speed up shrinking dramatically.\n\nIn some cases it is likely that this will result in worse shrunk test cases. In those\ncases rerunning the test will result in further shrinking.\n\n.. _v5.23.7:\n\n-------------------\n5.23.7 - 2020-07-29\n-------------------\n\nThis release makes some performance improvements to shrinking. They should\nonly be noticeable for tests that are currently particularly slow to shrink.\n\n.. _v5.23.6:\n\n-------------------\n5.23.6 - 2020-07-29\n-------------------\n\nThis patch adds some more internal functions to support a new\nfeature we're working on, like :ref:`version 5.18.3 <v5.18.3>`.\nThere is still no user-visible change... yet.\n\n.. _v5.23.5:\n\n-------------------\n5.23.5 - 2020-07-29\n-------------------\n\nThis release makes some changes to internal support code that is not currently used in production Hypothesis.\nIt has no user visible effect at present.\n\n.. _v5.23.4:\n\n-------------------\n5.23.4 - 2020-07-29\n-------------------\n\nThis release improves shrinking quality in some special cases.\n\n.. _v5.23.3:\n\n-------------------\n5.23.3 - 2020-07-27\n-------------------\n\nThis release fixes :issue:`2507`, where lazy evaluation meant that the\nvalues drawn from a :func:`~hypothesis.strategies.sampled_from` strategy\ncould depend on mutations of the sampled sequence that happened after\nthe strategy was constructed.\n\n.. _v5.23.2:\n\n-------------------\n5.23.2 - 2020-07-27\n-------------------\n\nThis patch fixes :issue:`2462`, a bug in our handling of :meth:`unittest.TestCase.subTest`.\nThanks to Israel Fruchter for fixing this at the EuroPython sprints!\n\n.. _v5.23.1:\n\n-------------------\n5.23.1 - 2020-07-26\n-------------------\n\nThis release improves the behaviour of the :func:`~hypothesis.strategies.characters` strategy\nwhen shrinking, by changing which characters are considered smallest to prefer more \"normal\" ascii characters\nwhere available.\n\n.. _v5.23.0:\n\n-------------------\n5.23.0 - 2020-07-26\n-------------------\n\nThe default ``print_blob`` setting is now smarter. It defaults to ``True`` in CI and\n``False`` for local development.\n\nThanks to Hugo van Kemenade for implementing this feature at the EuroPython sprints!\n\n.. _v5.22.0:\n\n-------------------\n5.22.0 - 2020-07-25\n-------------------\n\nThe :func:`~hypothesis.strategies.slices` strategy can now generate slices for empty sequences,\nslices with negative start and stop indices (from the end of the sequence),\nand ``step=None`` in place of ``step=1``.\n\nThanks to Sangarshanan for implementing this feature at the EuroPython sprints!\n\n.. _v5.21.0:\n\n-------------------\n5.21.0 - 2020-07-23\n-------------------\n\nThis release ensures that tests which raise ``RecursionError`` are not\nreported as flaky simply because we run them from different initial\nstack depths (:issue:`2494`).\n\n.. _v5.20.4:\n\n-------------------\n5.20.4 - 2020-07-23\n-------------------\n\nThis release improves the performance of the ``sample`` method on objects obtained from :func:`~hypothesis.strategies.randoms`\nwhen ``use_true_random=False``. This should mostly only be noticeable when the sample size is a large fraction of the population size,\nbut may also help avoid health check failures in some other cases.\n\n.. _v5.20.3:\n\n-------------------\n5.20.3 - 2020-07-21\n-------------------\n\nThis release makes some internal changes for testing purposes and should have no user visible effect.\n\n.. _v5.20.2:\n\n-------------------\n5.20.2 - 2020-07-18\n-------------------\n\nThis release fixes a small caching bug in Hypothesis internals that may under\nsome circumstances have resulted in a less diverse set of test cases being\ngenerated than was intended.\n\nFixing this problem revealed some performance problems that could occur during targeted property based testing, so this release also fixes those. Targeted property-based testing should now be significantly faster in some cases,\nbut this may be at the cost of reduced effectiveness.\n\n.. _v5.20.1:\n\n-------------------\n5.20.1 - 2020-07-17\n-------------------\n\nThis patch updates our formatting to use :pypi:`isort` 5.\nThere is no user-visible change.\n\n.. _v5.20.0:\n\n-------------------\n5.20.0 - 2020-07-17\n-------------------\n\nThe :func:`~hypothesis.extra.numpy.basic_indices` strategy can now generate\nbare indexers in place of length-one tuples. Thanks to Andrea for this patch!\n\n.. _v5.19.3:\n\n-------------------\n5.19.3 - 2020-07-15\n-------------------\n\nThis patch removes an internal use of ``distutils`` in order to avoid\n`this setuptools warning <https://github.com/pypa/setuptools/issues/2261>`__\nfor some users.\n\n.. _v5.19.2:\n\n-------------------\n5.19.2 - 2020-07-13\n-------------------\n\nThis patch contains a small internal refactoring with no user-visible impact.\n\nThanks to Andrea for writing this at\n`the SciPy 2020 Sprints <https://www.scipy2020.scipy.org/sprints-schedule>`__!\n\n.. _v5.19.1:\n\n-------------------\n5.19.1 - 2020-07-12\n-------------------\n\nThis release slightly improves shrinking behaviour. This should mainly only\nimpact stateful tests, but may have some minor positive impact on shrinking\ncollections (lists, sets, etc).\n\n.. _v5.19.0:\n\n-------------------\n5.19.0 - 2020-06-30\n-------------------\n\nThis release improves the :func:`~hypothesis.strategies.randoms` strategy by adding support\nfor ``Random`` instances where Hypothesis generates the random values\nrather than having them be \"truly\" random.\n\n.. _v5.18.3:\n\n-------------------\n5.18.3 - 2020-06-27\n-------------------\n\nThis patch adds some internal functions to support a new feature\nwe're working on.  There is no user-visible change... yet.\n\n.. _v5.18.2:\n\n-------------------\n5.18.2 - 2020-06-26\n-------------------\n\nThis patch improves our docs for the :obj:`~hypothesis.settings.derandomize` setting.\n\n.. _v5.18.1:\n\n-------------------\n5.18.1 - 2020-06-25\n-------------------\n\nThis release consists of some internal refactoring to the shrinker in preparation for future work. It has no user visible impact.\n\n.. _v5.18.0:\n\n-------------------\n5.18.0 - 2020-06-22\n-------------------\n\nThis release teaches Hypothesis to :ref:`shorten tracebacks <v3.79.2>` for |@example|, as we already do\nfor generated examples, so that you can focus on your code rather than ours.\n\nIf you have multiple failing explicit examples, they will now all be reported.\nTo report only the first failure, you can use the :obj:`report_multiple_bugs=False\n<hypothesis.settings.report_multiple_bugs>` setting as for generated examples.\n\n.. _v5.17.0:\n\n-------------------\n5.17.0 - 2020-06-22\n-------------------\n\nThis patch adds strategy inference for the ``Literal``, ``NewType``, ``Type``,\n``DefaultDict``, and ``TypedDict`` types from the :pypi:`typing-extensions`\nbackport on PyPI.\n\n.. _v5.16.3:\n\n-------------------\n5.16.3 - 2020-06-21\n-------------------\n\nThis patch precomputes some of the setup logic for our\n:ref:`external fuzzer integration <fuzz_one_input>` and sets\n:obj:`deadline=None <hypothesis.settings.deadline>` in fuzzing mode,\nsaving around 150us on each iteration.\n\nThis is around two-thirds the runtime to fuzz an empty test with\n``@given(st.none())``, and nice to have even as a much smaller\nfraction of the runtime for non-trivial tests.\n\n.. _v5.16.2:\n\n-------------------\n5.16.2 - 2020-06-19\n-------------------\n\nThis patch fixes an internal error when warning about the use of function-scoped fixtures\nfor parametrised tests where the parametrised value contained a ``%`` character.\nThanks to Bryant for reporting and fixing this bug!\n\n.. _v5.16.1:\n\n-------------------\n5.16.1 - 2020-06-10\n-------------------\n\nIf you pass a :class:`python:list` or :class:`python:tuple` where a\nstrategy was expected, the error message now mentions\n:func:`~hypothesis.strategies.sampled_from` as an example strategy.\n\nThanks to the enthusiastic participants in the `PyCon Mentored Sprints\n<https://us.pycon.org/2020/hatchery/mentoredsprints/>`__ who suggested\nadding this hint.\n\n.. _v5.16.0:\n\n-------------------\n5.16.0 - 2020-05-27\n-------------------\n\n:func:`~hypothesis.strategies.functions` can now infer the appropriate ``returns``\nstrategy if you pass a ``like`` function with a return-type annotation.  Before,\nomitting the ``returns`` argument would generate functions that always returned None.\n\n.. _v5.15.1:\n\n-------------------\n5.15.1 - 2020-05-21\n-------------------\n\nFix :func:`~hypothesis.strategies.from_type` with generic types under Python 3.9.\n\n.. _v5.15.0:\n\n-------------------\n5.15.0 - 2020-05-19\n-------------------\n\nThis patch fixes an error that happens when multiple threads create new strategies.\n\n.. _v5.14.0:\n\n-------------------\n5.14.0 - 2020-05-13\n-------------------\n\nPassing ``min_magnitude=None`` to :func:`~hypothesis.strategies.complex_numbers` is now\ndeprecated - you can explicitly pass ``min_magnitude=0``, or omit the argument entirely.\n\n.. _v5.13.1:\n\n-------------------\n5.13.1 - 2020-05-13\n-------------------\n\nThis patch fixes an internal error in :func:`~hypothesis.strategies.from_type`\nfor :obj:`python:typing.NamedTuple` in Python 3.9.  Thanks to Michel Salim\nfor reporting and fixing :issue:`2427`!\n\n.. _v5.13.0:\n\n-------------------\n5.13.0 - 2020-05-12\n-------------------\n\nThis release upgrades the test statistics available via the\n:ref:`--hypothesis-show-statistics <statistics>` option to include\nseparate information on each of the :attr:`~hypothesis.settings.phases`\n(:issue:`1555`).\n\n.. _v5.12.2:\n\n-------------------\n5.12.2 - 2020-05-12\n-------------------\n\nThis patch teaches the :func:`~hypothesis.strategies.from_type` internals to\nreturn slightly more efficient strategies for some generic sets and mappings.\n\n.. _v5.12.1:\n\n-------------------\n5.12.1 - 2020-05-12\n-------------------\n\nThis patch adds a ``# noqa`` comment for :pypi:`flake8` 3.8.0, which\ndisagrees with :pypi:`mypy` about how to write the type of ``...``.\n\n.. _v5.12.0:\n\n-------------------\n5.12.0 - 2020-05-10\n-------------------\n\nThis release limits the maximum duration of the shrinking phase to five minutes,\nso that Hypothesis does not appear to hang when making very slow progress\nshrinking a failing example (:issue:`2340`).\n\nIf one of your tests triggers this logic, we would really appreciate a bug\nreport to help us improve the shrinker for difficult but realistic workloads.\n\n.. _v5.11.0:\n\n-------------------\n5.11.0 - 2020-05-07\n-------------------\n\nThis release improves the interaction between :func:`~hypothesis.assume`\nand the :obj:`@example() <hypothesis.example>` decorator, so that the\nfollowing test no longer fails with ``UnsatisfiedAssumption`` (:issue:`2125`):\n\n.. code-block:: python\n\n    @given(value=floats(0, 1))\n    @example(value=0.56789)  # used to make the test fail!\n    @pytest.mark.parametrize(\"threshold\", [0.5, 1])\n    def test_foo(threshold, value):\n        assume(value < threshold)\n        ...\n\n.. _v5.10.5:\n\n-------------------\n5.10.5 - 2020-05-04\n-------------------\n\nIf you have :pypi:`Django` installed but don't use it, this patch will make\n``import hypothesis`` a few hundred milliseconds faster (e.g. 0.704s -> 0.271s).\n\nThanks to :pypi:`importtime-waterfall` for highlighting this problem and\n`Jake Vanderplas <https://twitter.com/jakevdp/status/1130983439862181888>`__ for\nthe solution - it's impossible to misuse code from a module you haven't imported!\n\n.. _v5.10.4:\n\n-------------------\n5.10.4 - 2020-04-24\n-------------------\n\nThis patch improves the internals of :func:`~hypothesis.strategies.builds` type\ninference, to handle recursive forward references in certain dataclasses.\nThis is useful for e.g. :pypi:`hypothesmith`'s forthcoming :pypi:`LibCST <libcst>` mode.\n\n.. _v5.10.3:\n\n-------------------\n5.10.3 - 2020-04-22\n-------------------\n\nThis release reverses the order in which some operations are tried during shrinking.\nThis should generally be a slight performance improvement, but most tests are unlikely to notice much difference.\n\n.. _v5.10.2:\n\n-------------------\n5.10.2 - 2020-04-22\n-------------------\n\nThis patch fixes :issue:`2406`, where use of :obj:`pandas:pandas.Timestamp`\nobjects as bounds for the :func:`~hypothesis.strategies.datetimes` strategy\ncaused an internal error.  This bug was introduced in :ref:`version 5.8.1 <v5.8.2>`.\n\n.. _v5.10.1:\n\n-------------------\n5.10.1 - 2020-04-19\n-------------------\n\nThis release is a small internal refactoring to how shrinking interacts with :ref:`targeted property-based testing <targeted>` that should have no user visible impact.\n\n.. _v5.10.0:\n\n-------------------\n5.10.0 - 2020-04-18\n-------------------\n\nThis release improves our support for datetimes and times around DST transitions.\n\n:func:`~hypothesis.strategies.times` and :func:`~hypothesis.strategies.datetimes`\nare now sometimes generated with ``fold=1``, indicating that they represent the\nsecond occurrence of a given wall-time when clocks are set backwards.\nThis may be set even when there is no transition, in which case the ``fold``\nvalue should be ignored.\n\nFor consistency, timezones provided by the :pypi:`pytz` package can now\ngenerate imaginary times (such as the hour skipped over when clocks 'spring forward'\nto daylight saving time, or during some historical timezone transitions).\nAll other timezones have always supported generation of imaginary times.\n\nIf you prefer the previous behaviour, :func:`~hypothesis.strategies.datetimes`\nnow takes an argument ``allow_imaginary`` which defaults to ``True`` but\ncan be set to ``False`` for any timezones strategy.\n\n.. _v5.9.1:\n\n------------------\n5.9.1 - 2020-04-16\n------------------\n\nThis patch fixes the rendering of :func:`~hypothesis.strategies.binary`\ndocstring by using the proper backticks syntax.\n\n.. _v5.9.0:\n\n------------------\n5.9.0 - 2020-04-15\n------------------\n\nFailing tests which use :func:`~hypothesis.target` now report the highest\nscore observed for each target alongside the failing example(s), even without\n:ref:`explicitly showing test statistics <statistics>`.\n\nThis improves the debugging workflow for tests of accuracy, which assert that the\ntotal imprecision is within some error budget - for example, ``abs(a - b) < 0.5``.\nPreviously, shrinking to a minimal failing example could often make errors seem\nsmaller or more subtle than they really are (see `the threshold problem\n<https://hypothesis.works/articles/threshold-problem/>`__, and :issue:`2180`).\n\n.. _v5.8.6:\n\n------------------\n5.8.6 - 2020-04-15\n------------------\n\nThis patch improves the docstring of :func:`~hypothesis.strategies.binary`,\nthe :func:`python:repr` of :func:`~hypothesis.strategies.sampled_from` on\nan :class:`python:enum.Enum` subclass, and a warning in our pytest plugin.\nThere is no change in runtime behaviour.\n\n.. _v5.8.5:\n\n------------------\n5.8.5 - 2020-04-15\n------------------\n\nThis release (potentially very significantly) improves the performance of failing tests in some rare cases,\nmostly only relevant when using :ref:`targeted property-based testing <targeted>`,\nby stopping further optimisation of unrelated test cases once a failing example is found.\n\n.. _v5.8.4:\n\n------------------\n5.8.4 - 2020-04-14\n------------------\n\nThis release fixes :issue:`2395`, where under some circumstances targeted property-based testing could cause Hypothesis to get caught in an infinite loop.\n\n.. _v5.8.3:\n\n------------------\n5.8.3 - 2020-04-12\n------------------\n\nThis patch teaches :func:`~hypothesis.strategies.builds` and\n:func:`~hypothesis.strategies.from_type` to use the ``__signature__``\nattribute of classes where it has been set, improving our support\nfor :pypi:`pydantic` models (`in pydantic >= 1.5\n<https://github.com/pydantic/pydantic/pull/1034>`__).\n\n.. _v5.8.2:\n\n------------------\n5.8.2 - 2020-04-12\n------------------\n\nThis release improves the performance of the part of the core engine that\ndeliberately generates duplicate values.\n\n.. _v5.8.1:\n\n------------------\n5.8.1 - 2020-04-12\n------------------\n\nThis patch improves :func:`~hypothesis.strategies.dates` shrinking, to simplify\nyear, month, and day like :func:`~hypothesis.strategies.datetimes` rather than\nminimizing the number of days since 2000-01-01.\n\n.. _v5.8.0:\n\n------------------\n5.8.0 - 2020-03-24\n------------------\n\nThis release adds a :ref:`.hypothesis.fuzz_one_input <fuzz_one_input>`\nattribute to :func:`@given <hypothesis.given>` tests, for easy integration\nwith external fuzzers such as `python-afl <https://github.com/jwilk/python-afl>`__\n(supporting :issue:`171`).\n\n.. _v5.7.2:\n\n------------------\n5.7.2 - 2020-03-24\n------------------\n\nThis patch fixes :issue:`2341`, ensuring that the printed output from a\nstateful test cannot use variable names before they are defined.\n\n.. _v5.7.1:\n\n------------------\n5.7.1 - 2020-03-23\n------------------\n\nThis patch fixes :issue:`2375`, preventing incorrect failure when a function\nscoped fixture is overridden with a higher scoped fixture.\n\n.. _v5.7.0:\n\n------------------\n5.7.0 - 2020-03-19\n------------------\n\nThis release allows the :func:`~hypothesis.extra.numpy.array_dtypes` strategy\nto generate Numpy dtypes which have `field titles in addition to field names\n<https://numpy.org/doc/stable/user/basics.rec.html#field-titles>`__.\nWe expect this to expose latent bugs where code expects that\n``set(dtype.names) == set(dtype.fields)``, though the latter may include titles.\n\n.. _v5.6.1:\n\n------------------\n5.6.1 - 2020-03-18\n------------------\n\nThis makes ``model`` a positional-only argument to\n:func:`~hypothesis.extra.django.from_model`, to support models\nwith a field literally named \"model\" (:issue:`2369`).\n\n.. _v5.6.0:\n\n------------------\n5.6.0 - 2020-02-29\n------------------\n\nThis release adds an explicit warning for tests that are both decorated with\n:func:`@given(...) <hypothesis.given>` and request a\n:doc:`function-scoped pytest fixture <pytest:how-to/fixtures>`, because such fixtures\nare only executed once for *all* Hypothesis test cases and that often causes\ntrouble (:issue:`377`).\n\nIt's *very* difficult to fix this on the :pypi:`pytest` side, so since 2015\nour advice has been \"just don't use function-scoped fixtures with Hypothesis\".\nNow we detect and warn about the issue at runtime!\n\n.. _v5.5.5:\n\n------------------\n5.5.5 - 2020-02-29\n------------------\n\nThis release cleans up the internal machinery for :ref:`stateful`,\nafter we dropped the legacy APIs in Hypothesis 5.0 (:issue:`2218`).\nThere is no user-visible change.\n\n.. _v5.5.4:\n\n------------------\n5.5.4 - 2020-02-16\n------------------\n\nThis patch fixes :issue:`2351`, :func:`~hypothesis.extra.numpy.arrays` would\nraise a confusing error if we inferred a strategy for ``datetime64`` or\n``timedelta64`` values with varying time units.\n\nWe now infer an internally-consistent strategy for such arrays, and have a more\nhelpful error message if an inconsistent strategy is explicitly specified.\n\n.. _v5.5.3:\n\n------------------\n5.5.3 - 2020-02-14\n------------------\n\nThis patch improves the signature of :func:`~hypothesis.strategies.builds` by\nspecifying ``target`` as a positional-only argument on Python 3.8 (see :pep:`570`).\nThe semantics of :func:`~hypothesis.strategies.builds` have not changed at all -\nthis just clarifies the documentation.\n\n.. _v5.5.2:\n\n------------------\n5.5.2 - 2020-02-13\n------------------\n\nThis release makes Hypothesis faster at generating test cases that contain\nduplicated values in their inputs.\n\n.. _v5.5.1:\n\n------------------\n5.5.1 - 2020-02-07\n------------------\n\nThis patch has some tiny internal code clean-ups, with no user-visible change.\n\n.. _v5.5.0:\n\n------------------\n5.5.0 - 2020-02-07\n------------------\n\n:gh-file:`Our style guide <guides/api-style.rst>` suggests that optional\nparameters should usually be keyword-only arguments (see :pep:`3102`) to\nprevent confusion based on positional arguments - for example,\n:func:`hypothesis.strategies.floats` takes up to *four* boolean flags\nand many of the Numpy strategies have both ``dims`` and ``side`` bounds.\n\nThis release converts most optional parameters in our API to use\nkeyword-only arguments - and adds a compatibility shim so you get\nwarnings rather than errors everywhere (:issue:`2130`).\n\n.. _v5.4.2:\n\n------------------\n5.4.2 - 2020-02-06\n------------------\n\nThis patch fixes compatibility with Python 3.5.2 (:issue:`2334`).\nNote that :doc:`we only test the latest patch of each minor version <compatibility>`,\nthough as in this case we usually accept pull requests for older patch versions.\n\n.. _v5.4.1:\n\n------------------\n5.4.1 - 2020-02-01\n------------------\n\nThis patch improves the repr of :func:`~hypothesis.strategies.from_type`,\nso that in most cases it will display the strategy it resolves to rather\nthan ``from_type(...)``.  The latter form will continue to be used where\nresolution is not immediately successful, e.g. invalid arguments or\nrecursive type definitions involving forward references.\n\n.. _v5.4.0:\n\n------------------\n5.4.0 - 2020-01-30\n------------------\n\nThis release removes support for Python 3.5.0 and 3.5.1, where the\n:mod:`python:typing` module was quite immature (e.g. missing\n:func:`~python:typing.overload` and :obj:`~python:typing.Type`).\n\nNote that Python 3.5 will reach its end-of-life in September 2020,\nand new releases of Hypothesis may drop support somewhat earlier.\n\n.. note::\n    ``pip install hypothesis`` should continue to give you the latest compatible version.\n    If you have somehow ended up with an incompatible version, you need to update your\n    packaging stack to ``pip >= 9.0`` and ``setuptools >= 24.2`` - see `here for details\n    <https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires>`__.\n    Then ``pip uninstall hypothesis && pip install hypothesis`` will get you back to\n    a compatible version.\n\n.. _v5.3.1:\n\n------------------\n5.3.1 - 2020-01-26\n------------------\n\nThis patch does some minor internal cleanup; there is no user-visible change.\n\n.. _v5.3.0:\n\n------------------\n5.3.0 - 2020-01-21\n------------------\n\nThe standard library :mod:`ipaddress` module is new in Python 3, and this release\nadds the new :func:`~hypothesis.strategies.ip_addresses` strategy to generate\n:class:`~python:ipaddress.IPv4Address`\\ es and/or\n:class:`~python:ipaddress.IPv6Address`\\ es (depending on the ``v`` and ``network``\narguments).\n\nIf you use them in type annotations, :func:`~hypothesis.strategies.from_type` now\nhas strategies registered for :mod:`ipaddress` address, network, and interface types.\n\nThe provisional strategies for IP address strings are therefore deprecated.\n\n.. _v5.2.1:\n\n------------------\n5.2.1 - 2020-01-21\n------------------\n\nThis patch reverts :ref:`version 5.2 <v5.2.0>`, due to a\n`strange issue <https://github.com/numpy/numpy/issues/15363>`__\nwhere indexing an array of strings can raise an error instead of\nreturning an item which contains certain surrogate characters.\n\n.. _v5.2.0:\n\n------------------\n5.2.0 - 2020-01-19\n------------------\n\nThis release allows :func:`~hypothesis.extra.numpy.from_dtype` to generate\nUnicode strings which cannot be encoded in UTF-8, but are valid in Numpy\narrays (which use UTF-32).\n\n.. _v5.1.6:\n\n------------------\n5.1.6 - 2020-01-19\n------------------\n\nThis patch fixes :issue:`2320`, where ``from_type(Set[Hashable])`` could raise\nan internal error because ``Decimal(\"snan\")`` is of a hashable type, but raises\nan error when hashed.  We now ensure that set elements and dict keys in generic\ntypes can actually be hashed.\n\n.. _v5.1.5:\n\n------------------\n5.1.5 - 2020-01-12\n------------------\n\nThis patch fixes an internal error when running in an :pypi:`ipython` repl or\n:pypi:`jupyter` notebook on Windows (:issue:`2319`), and an internal error on\nPython 3.5.1 (:issue:`2318`).\n\n.. _v5.1.4:\n\n------------------\n5.1.4 - 2020-01-11\n------------------\n\nThis patch fixes a bug where errors in third-party extensions such as\n:pypi:`hypothesis-trio` or :pypi:`hypothesis-jsonschema` were incorrectly\nconsidered to be Hypothesis internal errors, which could result in\nconfusing error messages.\n\nThanks to Vincent Michel for reporting and fixing the bug!\n\n.. _v5.1.3:\n\n------------------\n5.1.3 - 2020-01-11\n------------------\n\nThis release converts the type hint comments on our public API to\n:pep:`484` type annotations.\n\nThanks to Ivan Levkivskyi for :pypi:`com2ann` - with the refactoring\ntools from :ref:`5.0.1 <v5.0.1>` it made this process remarkably easy!\n\n.. _v5.1.2:\n\n------------------\n5.1.2 - 2020-01-09\n------------------\n\nThis patch makes :func:`~hypothesis.stateful.multiple` iterable, so that\noutput like ``a, b = state.some_rule()`` is actually executable and\ncan be used to reproduce failing examples.\n\nThanks to Vincent Michel for reporting and fixing :issue:`2311`!\n\n.. _v5.1.1:\n\n------------------\n5.1.1 - 2020-01-06\n------------------\n\nThis patch contains many small refactorings to replace our Python 2\ncompatibility functions with their native Python 3 equivalents.\nSince Hypothesis is now Python 3 only, there is no user-visible change.\n\n.. _v5.1.0:\n\n------------------\n5.1.0 - 2020-01-03\n------------------\n\nThis release teaches :func:`~hypothesis.strategies.from_type` how to generate\n:class:`python:datetime.timezone`.  As a result, you can now generate\n:class:`python:datetime.tzinfo` objects without having :pypi:`pytz` installed.\n\nIf your tests specifically require :pypi:`pytz` timezones, you should be using\n:func:`hypothesis.extra.pytz.timezones` instead of ``st.from_type(tzinfo)``.\n\n.. _v5.0.1:\n\n------------------\n5.0.1 - 2020-01-01\n------------------\n\nThis patch contains mostly-automated refactorings to remove code\nthat we only needed to support Python 2.  Since Hypothesis is now\nPython 3 only (hurray!), there is no user-visible change.\n\nOur sincere thanks to the authors of :pypi:`autoflake`, :pypi:`black`,\n:pypi:`isort`, and :pypi:`pyupgrade`, who have each and collectively\nmade this kind of update enormously easier.\n\n.. _v5.0.0:\n\n------------------\n5.0.0 - 2020-01-01\n------------------\n\nWelcome to the next major version of Hypothesis!\n\nThere are no new features here, as we release those in minor versions.\nInstead, 5.0 is a chance for us to remove deprecated features (many already\nconverted into no-ops), and turn a variety of warnings into errors.\n\nIf you were running on the last version of Hypothesis 4.x *without any\nHypothesis deprecation warnings*, this will be a very boring upgrade.\n**In fact, nothing will change for you at all.**\n\n.. note::\n    This release drops support for Python 2, which has passed\n    `its end of life date <https://devguide.python.org/#status-of-python-branches>`__.\n    The `Python 3 Statement <https://python3statement.github.io>`__ outlines our\n    reasons, and lists many other packages that have made the same decision.\n\n    ``pip install hypothesis`` should continue to give you the latest compatible version.\n    If you have somehow ended up with Hypothesis 5.0 on Python 2, you need to update your\n    packaging stack to ``pip >= 9.0`` and ``setuptools >= 24.2`` - see `here for details\n    <https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires>`__.\n    Then ``pip uninstall hypothesis && pip install hypothesis`` will get you back to\n    a compatible version.\n\n\nStrategies\n~~~~~~~~~~\n- :func:`~hypothesis.strategies.integers` bounds must be equal to an integer,\n  though they can still be other types.\n- If :func:`~hypothesis.strategies.fractions` is passed a ``max_denominator``,\n  the bounds must have at most that denominator.\n- :func:`~hypothesis.strategies.floats` bounds must be exactly representable as a\n  floating-point number with the given ``width``.  If not, the error message\n  includes the nearest such number.\n- :func:`sampled_from([]) <hypothesis.strategies.sampled_from>` is now an error.\n- The values from the ``elements`` and ``fill`` strategies for\n  :func:`hypothesis.extra.numpy.arrays` must be losslessly representable in an\n  array of the given dtype.\n- The ``min_size`` and ``max_size`` arguments to all collection strategies must\n  be of type :class:`python:int` (or ``max_size`` may be ``None``).\n\nMiscellaneous\n~~~~~~~~~~~~~\n- The ``.example()`` method of strategies (intended for interactive\n  exploration) no longer takes a ``random`` argument.\n- It is now an error to apply :obj:`@example <hypothesis.example>`,\n  :func:`@seed <hypothesis.seed>`, or :func:`@reproduce_failure <hypothesis.reproduce_failure>`\n  without also applying :func:`@given <hypothesis.given>`.\n- You may pass either the ``target`` or ``targets`` argument to stateful rules, but not both.\n- :obj:`~hypothesis.settings.deadline` must be ``None`` (to disable), a\n  :class:`~python:datetime.timedelta`, or an integer or float number of milliseconds.\n- Both of :obj:`~hypothesis.settings.derandomize` and\n  :obj:`~hypothesis.settings.print_blob` must be either ``True`` or ``False``,\n  where they previously accepted other values.\n- :obj:`~hypothesis.settings.stateful_step_count` must be at least one.\n- :obj:`~hypothesis.settings.max_examples` must be at least one.\n  To disable example generation, use the :obj:`~hypothesis.settings.phases` setting.\n\nRemovals\n~~~~~~~~\n- ``hypothesis.stateful.GenericStateMachine`` in favor of :class:`hypothesis.stateful.RuleBasedStateMachine`\n- ``hypothesis.extra.django.models.models`` in favor of :func:`hypothesis.extra.django.from_model`\n  and ``hypothesis.extra.django.models.add_default_field_mapping`` in favor of\n  :func:`hypothesis.extra.django.register_field_strategy`\n- ``hypothesis.HealthCheck.hung_test``, without replacement\n- ``hypothesis.settings.buffer``, without replacement\n- ``hypothesis.PrintSettings``, because :obj:`hypothesis.settings.print_blob` takes ``True`` or ``False``\n- ``hypothesis.settings.timeout``, in favor of :obj:`hypothesis.settings.deadline`\n- ``hypothesis.unlimited`` without replacement (only useful as argument to ``timeout``)\n\nHypothesis 4.x\n==============\n\n.. _v4.57.1:\n\n-------------------\n4.57.1 - 2019-12-29\n-------------------\n\nThis patch improves the type hints and documentation for the\n:ref:`django extra. <hypothesis-django>`  There is no runtime change.\n\n.. _v4.57.0:\n\n-------------------\n4.57.0 - 2019-12-28\n-------------------\n\nThis release improves support for the SupportsOp protocols from the :mod:`python:typing`\nmodule when using on :func:`~hypothesis.strategies.from_type` as outlined in :issue:`2292`.\nThe following types now generate much more varied strategies when called\nwith :func:`~hypothesis.strategies.from_type`:\n\n- :class:`python:typing.SupportsAbs`\n- :class:`python:typing.SupportsBytes`\n- :class:`python:typing.SupportsComplex`\n- :class:`python:typing.SupportsInt`\n- :class:`python:typing.SupportsFloat`\n- :class:`python:typing.SupportsRound`\n\nNote that using :func:`~hypothesis.strategies.from_type` with one of the above strategies will not\nensure that the specified function will execute successfully (ie : the strategy returned for\n``from_type(typing.SupportsAbs)`` may include NaNs or things which cause the :func:`python:abs`\nfunction to error. )\n\nThanks to Lea Provenzano for this patch.\n\n.. _v4.56.3:\n\n-------------------\n4.56.3 - 2019-12-22\n-------------------\n\nThis release fixes a small internal bug in shrinking which could have caused it\nto perform slightly more tests than were necessary. Fixing this shouldn't have\nmuch effect but it will make shrinking slightly faster.\n\n.. _v4.56.2:\n\n-------------------\n4.56.2 - 2019-12-21\n-------------------\n\nThis release removes an internal heuristic that was no longer providing much\nbenefit. It is unlikely that there will be any user visible effect.\n\n.. _v4.56.1:\n\n-------------------\n4.56.1 - 2019-12-19\n-------------------\n\nThis release further improves the optimisation algorithm for :ref:`targeted property-based testing <targeted>`.\n\n.. _v4.56.0:\n\n-------------------\n4.56.0 - 2019-12-18\n-------------------\n\nThis release enables deprecation warnings even when the\n:obj:`~hypothesis.settings.verbosity` setting is ``quiet``,\nin preparation for Hypothesis 5.0 (:issue:`2218`).\n\nWarnings can still be filtered by the standard mechanisms\nprovided in the standard-library :mod:`python:warnings` module.\n\n.. _v4.55.4:\n\n-------------------\n4.55.4 - 2019-12-18\n-------------------\n\nThis release improves Hypothesis's management of the set of test cases it\ntracks between runs. It will only do anything if you have the\n:obj:`~hypothesis.Phase.target` phase enabled and an example database set.\nIn those circumstances it should result in a more thorough and faster set of examples\nthat are tried on each run.\n\n.. _v4.55.3:\n\n-------------------\n4.55.3 - 2019-12-18\n-------------------\n\nThis release makes Hypothesis better at generating test cases where generated\nvalues are duplicated in different parts of the test case. This will be\nespecially noticeable with reasonably complex values, as it was already able\nto do this for simpler ones such as integers or floats.\n\n.. _v4.55.2:\n\n-------------------\n4.55.2 - 2019-12-17\n-------------------\n\nThis release expands the set of test cases that Hypothesis saves in its\ndatabase for future runs to include a representative set of \"structurally\ndifferent\" test cases - e.g. it might try to save test cases where a given list\nis empty or not.\n\nCurrently this is unlikely to have much user visible impact except to produce\nslightly more consistent behaviour between consecutive runs of a test suite.\nIt is mostly groundwork for future improvements which will exploit this\nfunctionality more effectively.\n\n.. _v4.55.1:\n\n-------------------\n4.55.1 - 2019-12-16\n-------------------\n\nThis patch fixes :issue:`2257`, where :func:`~hypothesis.strategies.from_type`\ncould incorrectly generate bytestrings when passed a generic\n:class:`python:typing.Sequence` such as ``Sequence[set]``.\n\n.. _v4.55.0:\n\n-------------------\n4.55.0 - 2019-12-16\n-------------------\n\nThis release adds database support for :ref:`targeted property-based testing <targeted>`,\nso the best examples based on the targeting will be saved and reused between runs.\nThis is mostly laying groundwork for future features in this area, but\nwill also make targeted property-based tests more useful during development,\nwhere the same tests tend to get run over and over again.\n\nIf :obj:`~hypothesis.settings.max_examples` is large, this may increase memory\nusage significantly under some circumstances, but these should be relatively\nrare.\n\nThis release also adds a dependency on the :pypi:`sortedcontainers` package.\n\n.. _v4.54.2:\n\n-------------------\n4.54.2 - 2019-12-16\n-------------------\n\nThis release improves the optimisation algorithm for :ref:`targeted property-based testing <targeted>`,\nso that it will find higher quality results more reliably. Specifically, in cases where it would previously have got near a local optimum,\nit will now tend to achieve the locally optimal value.\n\n.. _v4.54.1:\n\n-------------------\n4.54.1 - 2019-12-16\n-------------------\n\nThis release is mostly internal changes in support of better testing of the\ncore engine. You are unlikely to see much effect, although some internal\nheuristics have changed slightly.\n\n.. _v4.54.0:\n\n-------------------\n4.54.0 - 2019-12-15\n-------------------\n\nThis release adds a dedicated phase for :ref:`targeted property-based testing <targeted>`,\nand (somewhat) improves the targeting algorithm so that it will find higher quality results more reliably.\nThis comes at a cost of making it more likely to get stuck in a local optimum.\n\n.. _v4.53.3:\n\n-------------------\n4.53.3 - 2019-12-15\n-------------------\n\nThis patch fixes :func:`~hypothesis.strategies.from_type` with\n:class:`python:typing.Hashable` and :class:`python:typing.Sized`,\nwhich previously failed with an internal error on Python 3.7 or later.\n\nThanks to Lea Provenzano for both reporting :issue:`2272`\nand writing the patch!\n\n.. _v4.53.2:\n\n-------------------\n4.53.2 - 2019-12-11\n-------------------\n\nThis release reorganises a number of the Hypothesis internal modules into a\npackage structure. If you are only depending on the public API it should have\nno effect. If you are depending on the internal API (which you shouldn't be,\nand which we don't guarantee compatibility on) you may have to rename some\nimports.\n\n.. _v4.53.1:\n\n-------------------\n4.53.1 - 2019-12-09\n-------------------\n\nThis release changes the size distribution of the number of steps run in\nstateful testing: It will now almost always run the maximum number of steps\npermitted.\n\n.. _v4.53.0:\n\n-------------------\n4.53.0 - 2019-12-09\n-------------------\n\n:ref:`statistics` now include the best score seen for each label, which can help avoid\n`the threshold problem <https://hypothesis.works/articles/threshold-problem/>`__  when\nthe minimal example shrinks right down to the threshold of failure (:issue:`2180`).\n\n.. _v4.52.0:\n\n-------------------\n4.52.0 - 2019-12-09\n-------------------\n\nThis release changes the ``stateful_step_count`` setting to raise an error if\nset to ``0``. This is a backwards compatible change because a value of ``0``\nwould never have worked and attempting to run it would have resulted in an\ninternal assertion error.\n\n.. _v4.51.1:\n\n-------------------\n4.51.1 - 2019-12-09\n-------------------\n\nThis release makes a small internal change to the distribution of test cases.\nIt is unlikely to have much user visible impact.\n\n.. _v4.51.0:\n\n-------------------\n4.51.0 - 2019-12-07\n-------------------\n\nThis release deprecates use of :obj:`@example <hypothesis.example>`,\n:func:`@seed <hypothesis.seed>`, or :func:`@reproduce_failure <hypothesis.reproduce_failure>`\nwithout :func:`@given <hypothesis.given>`.\n\nThanks to Nick Anyos for the patch!\n\n.. _v4.50.8:\n\n-------------------\n4.50.8 - 2019-12-05\n-------------------\n\nThis patch makes certain uses of Bundles more efficient in stateful testing (:issue:`2078`).\n\n.. _v4.50.7:\n\n-------------------\n4.50.7 - 2019-12-05\n-------------------\n\nThis release refactors some of Hypothesis's internal interfaces for representing\ndata generation. It should have no user visible effect.\n\n.. _v4.50.6:\n\n-------------------\n4.50.6 - 2019-12-02\n-------------------\n\nThis patch removes some old debugging helpers in our Numpy extra which have\nnot been needed since :issue:`1963` and :issue:`2245`.\n\n.. _v4.50.5:\n\n-------------------\n4.50.5 - 2019-12-01\n-------------------\n\nThis patch fixes :issue:`2229`, where Numpy arrays of unsized strings would\nonly ever have strings of size one due to an interaction between our generation\nlogic and Numpy's allocation strategy.\n\n.. _v4.50.4:\n\n-------------------\n4.50.4 - 2019-12-01\n-------------------\n\nThis patch fixes a rare internal error in strategies for a list of\nunique items sampled from a short non-unique sequence (:issue:`2247`).\nThe bug was discovered via :pypi:`hypothesis-jsonschema`.\n\n.. _v4.50.3:\n\n-------------------\n4.50.3 - 2019-12-01\n-------------------\n\nThis release improves the error message when\n:func:`@settings <hypothesis.settings>` tries to inherit settings from a\n``parent`` argument that isn't a ``settings`` instance.\n\n.. _v4.50.2:\n\n-------------------\n4.50.2 - 2019-11-29\n-------------------\n\nThis release improves Hypothesis's \"Falsifying example\" output, by breaking\noutput across multiple lines where necessary, and by removing irrelevant\ninformation from the stateful testing output.\n\n.. _v4.50.1:\n\n-------------------\n4.50.1 - 2019-11-29\n-------------------\n\nThis patch adds :pypi:`flake8-comprehensions` to our linter suite.  There is no\nuser-visible change - expect perhaps via some strange microbenchmarks - but\ncertain parts of the code now have a clear and more consistent style.\n\n.. _v4.50.0:\n\n-------------------\n4.50.0 - 2019-11-28\n-------------------\n\nThis release fixes some cases where we might previously have failed to run the\nvalidation logic for some strategies. As a result tests which would previously\nhave been silently testing significantly less than they should may now start\nto raise ``InvalidArgument`` now that these errors are caught.\n\n.. _v4.49.0:\n\n-------------------\n4.49.0 - 2019-11-28\n-------------------\n\nThis release significantly improves the data distribution in :ref:`rule based stateful testing <stateful>`,\nby using a technique called `Swarm Testing (Groce, Alex, et al. \"Swarm testing.\"\nProceedings of the 2012 International Symposium on Software Testing and Analysis. ACM, 2012.) <https://agroce.github.io/issta12.pdf>`_\nto select which rules are run in any given test case. This should allow it to find many issues that it would previously have missed.\n\nThis change is likely to be especially beneficial for stateful tests with large numbers of rules.\n\n.. _v4.48.1:\n\n-------------------\n4.48.1 - 2019-11-28\n-------------------\n\nThis release adds some heuristics to test case generation that try to ensure that test cases generated early on will be relatively small.\n\nThis fixes a bug introduced in :ref:`Hypothesis 4.42.0 <v4.42.0>` which would cause occasional\n:obj:`~hypothesis.HealthCheck.too_slow` failures on some tests.\n\n.. _v4.48.0:\n\n-------------------\n4.48.0 - 2019-11-28\n-------------------\n\nThis release revokes the deprecation of ``find``, as we've now rebuilt it on top of\n``@given``, which means it has minimal maintenance burden and we're happy to support it.\n\n.. _v4.47.5:\n\n-------------------\n4.47.5 - 2019-11-28\n-------------------\n\nThis release rebuilds ``find()`` on top of ``@given`` in order to have more code in common.\nIt should have minimal user visible effect.\n\n.. _v4.47.4:\n\n-------------------\n4.47.4 - 2019-11-27\n-------------------\n\nThis patch removes an internal compatibility shim that we no longer need.\n\n.. _v4.47.3:\n\n-------------------\n4.47.3 - 2019-11-26\n-------------------\n\nThis patch fixes several typos in our docstrings and comments,\nwith no change in behaviour.  Thanks to  Dmitry Dygalo for\nidentifying and fixing them!\n\n.. _v4.47.2:\n\n-------------------\n4.47.2 - 2019-11-25\n-------------------\n\nThis release fixes an internal issue where Hypothesis would sometimes generate\ntest cases that were above its intended maximum size. This would only have\nhappened rarely and probably would not have caused major problems when it did.\n\nUsers of the new :ref:`targeted property-based testing <targeted>` might\nsee minor impact (possibly slightly faster tests and slightly worse target scores),\nbut only in the unlikely event that they were hitting this problem. Other users\nshould not see any effect at all.\n\n.. _v4.47.1:\n\n-------------------\n4.47.1 - 2019-11-24\n-------------------\n\nThis release removes some unused code from the core engine.\nThere is no user-visible change.\n\n.. _v4.47.0:\n\n-------------------\n4.47.0 - 2019-11-24\n-------------------\n\nThis release commonizes some code between running explicit examples and normal test execution.\nThe main user visible impact of this is that deadlines are now enforced when running explicit examples.\n\n.. _v4.46.1:\n\n-------------------\n4.46.1 - 2019-11-23\n-------------------\n\nThis patch ensures that a KeyboardInterrupt received during example generation\nis not treated as a mystery test failure but instead propagates to the top\nlevel, not recording the interrupted generation in the conjecture data tree.\nThanks to Anne Archibald for identifying and fixing the problem.\n\n.. _v4.46.0:\n\n-------------------\n4.46.0 - 2019-11-22\n-------------------\n\nThis release changes the behaviour of :func:`~hypothesis.strategies.floats`\nwhen excluding signed zeros - ``floats(max_value=0.0, exclude_max=True)``\ncan no longer generate ``-0.0`` nor the much rarer\n``floats(min_value=-0.0, exclude_min=True)`` generate ``+0.0``.\n\nThe correct interaction between signed zeros and exclusive endpoints was unclear;\nwe now enforce the invariant that :func:`~hypothesis.strategies.floats` will\nnever generate a value equal to an excluded endpoint (:issue:`2201`).\n\nIf you prefer the old behaviour, you can pass ``floats(max_value=-0.0)`` or\n``floats(min_value=0.0)`` which is exactly equivalent and has not changed.\nIf you had *two* endpoints equal to zero, we recommend clarifying your tests by using\n:func:`~hypothesis.strategies.just` or :func:`~hypothesis.strategies.sampled_from`\ninstead of :func:`~hypothesis.strategies.floats`.\n\n.. _v4.45.1:\n\n-------------------\n4.45.1 - 2019-11-20\n-------------------\n\nThis patch improves the error message when invalid arguments are passed\nto :func:`~hypothesis.stateful.rule` or :func:`~hypothesis.stateful.invariant`\n(:issue:`2149`).\n\nThanks to Benjamin Palmer for this bugfix!\n\n.. _v4.45.0:\n\n-------------------\n4.45.0 - 2019-11-20\n-------------------\n\nThis release supports :obj:`python:typing.Final` and :obj:`python:typing.TypedDict`\nin :func:`~hypothesis.strategies.from_type`.\n\n.. _v4.44.5:\n\n-------------------\n4.44.5 - 2019-11-20\n-------------------\n\nThis patch disables our :pypi:`pytest` plugin when running on versions\nof :pypi:`pytest` before 4.3, the oldest our plugin supports.\nNote that at time of writing the Pytest developers only support 4.6 and later!\n\nHypothesis *tests* using :func:`@given() <hypothesis.given>` work on any\ntest runner, but our integrations to e.g. avoid example database collisions\nwhen combined with ``@pytest.mark.parametrize`` eventually drop support\nfor obsolete versions.\n\n.. _v4.44.4:\n\n-------------------\n4.44.4 - 2019-11-20\n-------------------\n\nThis patch adds some internal comments and clarifications to the Hypothesis\nimplementation. There is no user-visible change.\n\n.. _v4.44.3:\n\n-------------------\n4.44.3 - 2019-11-20\n-------------------\n\nThis patch avoids importing test runners such as :pypi:`pytest`, :pypi:`unittest2`,\nor :pypi:`nose` solely to access their special \"skip test\" exception types -\nif the module is not in :obj:`sys.modules`, the exception can't be raised anyway.\n\nThis fixes a problem where importing an otherwise unused module could cause\nspurious errors due to import-time side effects (and possibly ``-Werror``).\n\n.. _v4.44.2:\n\n-------------------\n4.44.2 - 2019-11-12\n-------------------\n\nThis release fixes :func:`@given <hypothesis.given>` to only complain about\nmissing keyword-only arguments if the associated test function is actually\ncalled.\n\nThis matches the behaviour of other ``InvalidArgument`` errors produced by\n``@given``.\n\n.. _v4.44.1:\n\n-------------------\n4.44.1 - 2019-11-11\n-------------------\n\nThis patch allows Hypothesis to run in environments that do not specify\na ``__file__``, such as a :mod:`python:zipapp` (:issue:`2196`).\n\n.. _v4.44.0:\n\n-------------------\n4.44.0 - 2019-11-11\n-------------------\n\nThis release adds a ``signature`` argument to\n:func:`~hypothesis.extra.numpy.mutually_broadcastable_shapes` (:issue:`2174`),\nwhich allows us to generate shapes which are valid for functions like\n:data:`np.matmul() <numpy:numpy.matmul>` that require shapes which are not simply broadcastable.\n\nThanks to everyone who has contributed to this feature over the last year,\nand a particular shout-out to Zac Hatfield-Dodds and Ryan Soklaski for\n:func:`~hypothesis.extra.numpy.mutually_broadcastable_shapes` and to\nRyan Turner for the downstream :pypi:`hypothesis-gufunc` project.\n\n.. _v4.43.9:\n\n-------------------\n4.43.9 - 2019-11-11\n-------------------\n\nThis patch fixes :issue:`2108`, where the first test using\n:func:`~hypothesis.strategies.data` to draw from :func:`~hypothesis.strategies.characters`\nor :func:`~hypothesis.strategies.text` would be flaky due to unreliable test timings.\n\nTime taken by lazy instantiation of strategies is now counted towards drawing from\nthe strategy, rather than towards the deadline for the test function.\n\n.. _v4.43.8:\n\n-------------------\n4.43.8 - 2019-11-08\n-------------------\n\nThis release ensures that the strategies passed to\n:func:`@given <hypothesis.given>` are properly validated when applied to a test\nmethod inside a test class.\n\nThis should result in clearer error messages when some of those strategies are\ninvalid.\n\n.. _v4.43.7:\n\n-------------------\n4.43.7 - 2019-11-08\n-------------------\n\nThis release changes how Hypothesis manages its search space in cases where it\ngenerates redundant data. This should cause it to generate significantly fewer\nduplicated examples (especially with short integer ranges), and may cause it to\nproduce more useful examples in some cases (especially ones where there is a\nsignificant amount of filtering).\n\n.. _v4.43.6:\n\n-------------------\n4.43.6 - 2019-11-07\n-------------------\n\nThis patch refactors ``width`` handling in :func:`~hypothesis.strategies.floats`;\nyou may notice small performance improvements but the main purpose is to\nenable work on :issue:`1704` (improving shrinking of bounded floats).\n\n.. _v4.43.5:\n\n-------------------\n4.43.5 - 2019-11-06\n-------------------\n\nThis patch removes an unused internal flag.\nThere is no user-visible change.\n\n.. _v4.43.4:\n\n-------------------\n4.43.4 - 2019-11-05\n-------------------\n\nThis patch corrects the exception type and error message you get if you attempt\nto use :func:`~hypothesis.strategies.data` to draw from something which is not\na strategy.  This never worked, but the error is more helpful now.\n\n.. _v4.43.3:\n\n-------------------\n4.43.3 - 2019-11-05\n-------------------\n\nWe've adopted :pypi:`flake8-bugbear` to check for a few more style issues,\nand this patch implements the minor internal cleanups it suggested.\nThere is no user-visible change.\n\n.. _v4.43.2:\n\n-------------------\n4.43.2 - 2019-11-05\n-------------------\n\nThis patch fixes the formatting of some documentation,\nbut there is no change to any executed code.\n\n.. _v4.43.1:\n\n-------------------\n4.43.1 - 2019-11-04\n-------------------\n\nPython 3.8's new :obj:`python:typing.Literal` type - see :pep:`586` for\ndetails - is now  supported in :func:`~hypothesis.strategies.from_type`.\n\n.. _v4.43.0:\n\n-------------------\n4.43.0 - 2019-11-04\n-------------------\n\nThis release adds the strategy :func:`~hypothesis.extra.numpy.mutually_broadcastable_shapes`, which generates multiple array shapes that are mutually broadcast-compatible with an optional user-specified base-shape.\n\nThis is a generalisation of :func:`~hypothesis.extra.numpy.broadcastable_shapes`.\nIt relies heavily on non-public internals for performance when generating and shrinking examples.\nWe intend to support generating shapes matching a ufunc signature in a future version (:issue:`2174`).\n\nThanks to Ryan Soklaski, Zac Hatfield-Dodds, and @rdturnermtl who contributed to this new feature.\n\n.. _v4.42.10:\n\n--------------------\n4.42.10 - 2019-11-03\n--------------------\n\nThis release fixes :func:`~hypothesis.strategies.from_type` when used with\nbounded or constrained :obj:`python:typing.TypeVar` objects (:issue:`2094`).\n\nPreviously, distinct typevars with the same constraints would be treated as all\nsingle typevar, and in cases where a typevar bound was resolved to a union of\nsubclasses this could result in mixed types being generated for that typevar.\n\n.. _v4.42.9:\n\n-------------------\n4.42.9 - 2019-11-03\n-------------------\n\nThis patch ensures that the default value :func:`~hypothesis.extra.numpy.broadcastable_shapes`\nchooses for ``max_dims`` is always valid (at most 32), even if you pass ``min_dims=32``.\n\n.. _v4.42.8:\n\n-------------------\n4.42.8 - 2019-11-02\n-------------------\n\nThis patch ensures that we only add profile information to the pytest header\nif running either pytest or Hypothesis in verbose mode, matching the\n`builtin cache plugin <https://docs.pytest.org/en/latest/how-to/cache.html>`__\n(:issue:`2155`).\n\n.. _v4.42.7:\n\n-------------------\n4.42.7 - 2019-11-02\n-------------------\n\nThis patch makes stateful step printing expand the result of a step into\nmultiple variables when you return :func:`~hypothesis.stateful.multiple` (:issue:`2139`).\nThanks to Joseph Weston for reporting and fixing this bug!\n\n.. _v4.42.6:\n\n-------------------\n4.42.6 - 2019-11-02\n-------------------\n\nThis release fixes a bug (:issue:`2166`) where a Unicode character info\ncache file was generated but never used on subsequent test runs, causing tests\nto run more slowly than they should have.\n\nThanks to Robert Knight for this bugfix!\n\n.. _v4.42.5:\n\n-------------------\n4.42.5 - 2019-11-01\n-------------------\n\nThis patch corrects some internal documentation.  There is no user-visible change.\n\n.. _v4.42.4:\n\n-------------------\n4.42.4 - 2019-11-01\n-------------------\n\nThis release fixes a bug (:issue:`2160`) where decorators applied after\n:func:`@settings <hypothesis.settings>` and before\n:func:`@given <hypothesis.given>` were ignored.\n\nThanks to Tom Milligan for this bugfix!\n\n.. _v4.42.3:\n\n-------------------\n4.42.3 - 2019-10-30\n-------------------\n\nThis release updates Hypothesis's formatting to the new version of :pypi:`black`, and\nhas absolutely no user visible effect.\n\n.. _v4.42.2:\n\n-------------------\n4.42.2 - 2019-10-30\n-------------------\n\nThis release fixes a bug in :func:`~hypothesis.strategies.recursive` which would\nhave meant that in practice ``max_leaves`` was treated as if it was lower than\nit actually is - specifically it would be capped at the largest power of two\nsmaller than it. It is now handled correctly.\n\n.. _v4.42.1:\n\n-------------------\n4.42.1 - 2019-10-30\n-------------------\n\nPython 3.8's new :class:`python:typing.SupportsIndex` type - see :pep:`357`\nfor details - is now  supported in :func:`~hypothesis.strategies.from_type`.\n\nThanks to Grigorios Giannakopoulos for the patch!\n\n.. _v4.42.0:\n\n-------------------\n4.42.0 - 2019-10-27\n-------------------\n\nThis release significantly simplifies Hypothesis's internal logic for data\ngeneration, by removing a number of heuristics of questionable or unproven\nvalue.\n\nThe results of this change will vary significantly from test to test. Most\ntest suites will see significantly faster data generation and lower memory\nusage. The \"quality\" of the generated data may go up or down depending on your\nparticular test suites.\n\nIf you see any significant regressions in Hypothesis's ability to find bugs in\nyour code as a result of this release, please file an issue to let us know.\n\nUsers of the new  :ref:`targeted property-based testing <targeted>`\nfunctionality are reasonably likely to see *improvements* in data generation,\nas this release changes the search algorithm for targeted property based\ntesting to one that is more likely to be productive than the existing approach.\n\n.. _v4.41.3:\n\n-------------------\n4.41.3 - 2019-10-21\n-------------------\n\nThis patch is to ensure that our internals remain comprehensible to\n:pypi:`mypy` 0.740 - there is no user-visible change.\n\n.. _v4.41.2:\n\n-------------------\n4.41.2 - 2019-10-17\n-------------------\n\nThis patch changes some internal hashes to SHA384, to better support\nusers subject to FIPS-140. There is no user-visible API change.\n\nThanks to Paul Kehrer for this contribution!\n\n.. _v4.41.1:\n\n-------------------\n4.41.1 - 2019-10-16\n-------------------\n\nThis release makes ``--hypothesis-show-statistics`` much more useful for\ntests using a :class:`~hypothesis.stateful.RuleBasedStateMachine`, by\nsimplifying the reprs so that events are aggregated correctly.\n\n.. _v4.41.0:\n\n-------------------\n4.41.0 - 2019-10-16\n-------------------\n\nThis release upgrades the :func:`~hypothesis.strategies.fixed_dictionaries`\nstrategy to support ``optional`` keys (:issue:`1913`).\n\n.. _v4.40.2:\n\n-------------------\n4.40.2 - 2019-10-16\n-------------------\n\nThis release makes some minor internal changes in support of improving the\nHypothesis test suite. It should not have any user visible impact.\n\n.. _v4.40.1:\n\n-------------------\n4.40.1 - 2019-10-14\n-------------------\n\nThis release changes how Hypothesis checks if a parameter to a test function is a mock object.\nIt is unlikely to have any noticeable effect, but may result in a small performance improvement,\nespecially for test functions where a mock object is being passed as the first argument.\n\n.. _v4.40.0:\n\n-------------------\n4.40.0 - 2019-10-09\n-------------------\n\nThis release fixes a bug where our example database logic did not distinguish\nbetween failing examples based on arguments from a ``@pytest.mark.parametrize(...)``.\nThis could in theory cause data loss if a common failure overwrote a rare one, and\nin practice caused occasional file-access collisions in highly concurrent workloads\n(e.g. during a 300-way parametrize on 16 cores).\n\nFor internal reasons this also involves bumping the minimum supported version of\n:pypi:`pytest` to 4.3\n\nThanks to Peter C Kroon for the Hacktoberfest patch!\n\n.. _v4.39.3:\n\n-------------------\n4.39.3 - 2019-10-09\n-------------------\n\nThis patch improves our type hints on the :func:`~hypothesis.strategies.emails`,\n:func:`~hypothesis.strategies.functions`, :func:`~hypothesis.strategies.integers`,\n:func:`~hypothesis.strategies.iterables`, and :func:`~hypothesis.strategies.slices`\nstrategies, as well as the ``.filter()`` method.\n\nThere is no runtime change, but if you use :pypi:`mypy` or a similar\ntype-checker on your tests the results will be a bit more precise.\n\n.. _v4.39.2:\n\n-------------------\n4.39.2 - 2019-10-09\n-------------------\n\nThis patch improves the performance of unique collections such as\n:func:`~hypothesis.strategies.sets` of :func:`~hypothesis.strategies.just`\nor :func:`~hypothesis.strategies.booleans` strategies.  They were already\npretty good though, so you're unlikely to notice much!\n\n.. _v4.39.1:\n\n-------------------\n4.39.1 - 2019-10-09\n-------------------\n\nIf a value in a dict passed to :func:`~hypothesis.strategies.fixed_dictionaries`\nis not a strategy, Hypothesis now tells you which one.\n\n.. _v4.39.0:\n\n-------------------\n4.39.0 - 2019-10-07\n-------------------\n\nThis release adds the :func:`~hypothesis.extra.numpy.basic_indices` strategy,\nto generate `basic indexes <https://numpy.org/doc/stable/user/basics.indexing.html>`__\nfor arrays of the specified shape (:issue:`1930`).\n\nIt generates tuples containing some mix of integers, :obj:`python:slice` objects,\n``...`` (Ellipsis), and :obj:`numpy:numpy.newaxis`; which when used to index an array\nof the specified shape produce either a scalar or a shared-memory view of the array.\nNote that the index tuple may be longer or shorter than the array shape, and may\nproduce a view with another dimensionality again!\n\nThanks to Lampros Mountrakis, Ryan Soklaski, and Zac Hatfield-Dodds for their\ncollaboration on this surprisingly subtle strategy!\n\n.. _v4.38.3:\n\n-------------------\n4.38.3 - 2019-10-04\n-------------------\n\nThis patch defers creation of the ``.hypothesis`` directory until we have\nsomething to store in it, meaning that it will appear when Hypothesis is\nused rather than simply installed.\n\nThanks to Peter C Kroon for the Hacktoberfest patch!\n\n.. _v4.38.2:\n\n-------------------\n4.38.2 - 2019-10-02\n-------------------\n\nThis patch bumps our dependency on :pypi:`attrs` to ``>=19.2.0``;\nbut there are no user-visible changes to Hypothesis.\n\n.. _v4.38.1:\n\n-------------------\n4.38.1 - 2019-10-01\n-------------------\n\nThis is a comment-only patch which tells :pypi:`mypy` 0.730 to ignore\nsome internal compatibility shims we use to support older Pythons.\n\n.. _v4.38.0:\n\n-------------------\n4.38.0 - 2019-10-01\n-------------------\n\nThis release adds the :func:`hypothesis.target` function, which implements\n:ref:`targeted property-based testing <targeted>`\n(:issue:`1779`).\n\nBy calling :func:`~hypothesis.target` in your test function, Hypothesis can\ndo a hill-climbing search for bugs.  If you can calculate a suitable metric\nsuch as the load factor or length of a queue, this can help you find bugs with\ninputs that are highly improbably from unguided generation - however good our\nheuristics, example diversity, and deduplication logic might be.  After all,\nthose features are at work in targeted PBT too!\n\n.. _v4.37.0:\n\n-------------------\n4.37.0 - 2019-09-28\n-------------------\n\nThis release emits a warning if you use the ``.example()`` method of\na strategy in a non-interactive context.\n\n:func:`~hypothesis.given` is a much better choice for writing tests,\nwhether you care about performance, minimal examples, reproducing\nfailures, or even just the variety of inputs that will be tested!\n\n.. _v4.36.2:\n\n-------------------\n4.36.2 - 2019-09-20\n-------------------\n\nThis patch disables part of the :mod:`typing`-based inference for the\n:pypi:`attrs` package under Python 3.5.0, which has some incompatible\ninternal details (:issue:`2095`).\n\n.. _v4.36.1:\n\n-------------------\n4.36.1 - 2019-09-17\n-------------------\n\nThis patch fixes a bug in strategy inference for :pypi:`attrs` classes where\nHypothesis would fail to infer a strategy for attributes of a generic type\nsuch as ``Union[int, str]`` or ``List[bool]`` (:issue:`2091`).\n\nThanks to Jonathan Gayvallet for the bug report and this patch!\n\n.. _v4.36.0:\n\n-------------------\n4.36.0 - 2019-09-09\n-------------------\n\nThis patch deprecates ``min_len`` or ``max_len`` of 0 in\n:func:`~hypothesis.extra.numpy.byte_string_dtypes` and\n:func:`~hypothesis.extra.numpy.unicode_string_dtypes`.\nThe lower limit is now 1.\n\nNumpy uses a length of 0 in these dtypes to indicate an undetermined size,\nchosen from the data at array creation.\nHowever, as the :func:`~hypothesis.extra.numpy.arrays` strategy creates arrays\nbefore filling them, strings were truncated to 1 byte.\n\n.. _v4.35.1:\n\n-------------------\n4.35.1 - 2019-09-09\n-------------------\n\nThis patch improves the messaging that comes from invalid size arguments\nto collection strategies such as :func:`~hypothesis.strategies.lists`.\n\n.. _v4.35.0:\n\n-------------------\n4.35.0 - 2019-09-04\n-------------------\n\nThis release improves the :func:`~hypothesis.extra.lark.from_lark` strategy,\ntightening argument validation and adding the ``explicit`` argument to allow use\nwith terminals that use ``@declare`` instead of a string or regular expression.\n\nThis feature is required to handle features such as indent and dedent tokens\nin Python code, which can be generated with the :pypi:`hypothesmith` package.\n\n.. _v4.34.0:\n\n-------------------\n4.34.0 - 2019-08-23\n-------------------\n\nThe :func:`~hypothesis.strategies.from_type` strategy now knows to look up\nthe subclasses of abstract types, which cannot be instantiated directly.\n\nThis is very useful for :pypi:`hypothesmith` to support :pypi:`libCST <libcst>`.\n\n.. _v4.33.1:\n\n-------------------\n4.33.1 - 2019-08-21\n-------------------\n\nThis patch works around a crash when an incompatible version of Numpy\nis installed under PyPy 5.10 (Python 2.7).\n\nIf you are still using Python 2, please upgrade to Python 3 as soon\nas possible - it will be unsupported at the end of this year.\n\n.. _v4.33.0:\n\n-------------------\n4.33.0 - 2019-08-20\n-------------------\n\nThis release improves the :func:`~hypothesis.provisional.domains`\nstrategy, as well as the :func:`~hypothesis.provisional.urls` and\nthe :func:`~hypothesis.strategies.emails` strategies which use it.\nThese strategies now use the full IANA list of Top Level Domains\nand are correct as per :rfc:`1035`.\n\nPassing tests using these strategies may now fail.\n\nThanks to `TechDragon <https://github.com/techdragon>`__ for this improvement.\n\n.. _v4.32.3:\n\n-------------------\n4.32.3 - 2019-08-05\n-------------------\n\nThis patch tidies up the repr of several ``settings``-related objects,\nat runtime and in the documentation, and deprecates the undocumented\nedge case that ``phases=None`` was treated like ``phases=tuple(Phase)``.\n\nIt *also* fixes :func:`~hypothesis.extra.lark.from_lark` with\n:pypi:`lark 0.7.2 <lark-parser>` and later.\n\n.. _v4.32.2:\n\n-------------------\n4.32.2 - 2019-07-30\n-------------------\n\nThis patch updates some internal comments for :pypi:`mypy` 0.720.\nThere is no user-visible impact.\n\n.. _v4.32.1:\n\n-------------------\n4.32.1 - 2019-07-29\n-------------------\n\nThis release changes how the shrinker represents its progress internally. For large generated test cases\nthis should result in significantly less memory usage and possibly faster shrinking. Small generated\ntest cases may be slightly slower to shrink but this shouldn't be very noticeable.\n\n.. _v4.32.0:\n\n-------------------\n4.32.0 - 2019-07-28\n-------------------\n\nThis release makes :func:`~hypothesis.extra.numpy.arrays` more pedantic about\n``elements`` strategies that cannot be exactly represented as array elements.\n\nIn practice, you will see new warnings if you were using a ``float16`` or\n``float32`` dtype without passing :func:`~hypothesis.strategies.floats` the\n``width=16`` or ``width=32`` arguments respectively.\n\nThe previous behaviour could lead to silent truncation, and thus some elements\nbeing equal to an explicitly excluded bound (:issue:`1899`).\n\n.. _v4.31.1:\n\n-------------------\n4.31.1 - 2019-07-28\n-------------------\n\nThis patch changes an internal use of MD5 to SHA hashes, to better support\nusers subject to FIPS-140.  There is no user-visible or API change.\n\nThanks to Alex Gaynor for this patch.\n\n.. _v4.31.0:\n\n-------------------\n4.31.0 - 2019-07-24\n-------------------\n\nThis release simplifies the logic of the :attr:`~hypothesis.settings.print_blob` setting by removing the option to set it to ``PrintSettings.INFER``.\nAs a result the ``print_blob`` setting now takes a single boolean value, and the use of ``PrintSettings`` is deprecated.\n\n.. _v4.28.2:\n\n-------------------\n4.28.2 - 2019-07-14\n-------------------\n\nThis patch improves the docstrings of several Hypothesis strategies, by\nclarifying markup and adding cross-references.  There is no runtime change.\n\nThanks to Elizabeth Williams and Serah Njambi Rono for their contributions\nat the SciPy 2019 sprints!\n\n.. _v4.28.1:\n\n-------------------\n4.28.1 - 2019-07-12\n-------------------\n\nThis patch improves the behaviour of the :func:`~hypothesis.strategies.text`\nstrategy when passed an ``alphabet`` which is not a strategy.  The value is\nnow interpreted as ``include_characters`` to :func:`~hypothesis.strategies.characters`\ninstead of a sequence for :func:`~hypothesis.strategies.sampled_from`, which\nstandardises the distribution of examples and the shrinking behaviour.\n\nYou can get the previous behaviour by using\n``lists(sampled_from(alphabet)).map(\"\".map)`` instead.\n\n.. _v4.28.0:\n\n-------------------\n4.28.0 - 2019-07-11\n-------------------\n\nThis release deprecates ``find()``.  The ``.example()`` method is a better\nreplacement if you want *an* example, and for the rare occasions where you\nwant the *minimal* example you can get it from :func:`@given <hypothesis.given>`.\n\n:func:`@given <hypothesis.given>` has steadily outstripped ``find()`` in both\nfeatures and performance over recent years, and as we do not have the resources\nto maintain and test both we think it is better to focus on just one.\n\n.. _v4.27.0:\n\n-------------------\n4.27.0 - 2019-07-08\n-------------------\n\nThis release refactors the implementation of the ``.example()`` method,\nto more accurately represent the data which will be generated by\n:func:`@given <hypothesis.given>`.\n\nAs a result, calling ``s.example()`` on an empty strategy ``s``\n(such as :func:`~hypothesis.strategies.nothing`) now raises ``Unsatisfiable``\ninstead of the old ``NoExamples`` exception.\n\n.. _v4.26.4:\n\n-------------------\n4.26.4 - 2019-07-07\n-------------------\n\nThis patch ensures that the Pandas extra will keep working when Python 3.8\nremoves abstract base classes from the top-level :obj:`python:collections`\nnamespace.  This also fixes the relevant warning in Python 3.7, but there\nis no other difference in behaviour and you do not need to do anything.\n\n.. _v4.26.3:\n\n-------------------\n4.26.3 - 2019-07-05\n-------------------\n\nThis release fixes  :issue:`2027`, by changing the way Hypothesis tries to generate distinct examples to be more efficient.\n\nThis may result in slightly different data distribution, and should improve generation performance in general,\nbut should otherwise have minimal user impact.\n\n.. _v4.26.2:\n\n-------------------\n4.26.2 - 2019-07-04\n-------------------\n\nThis release fixes :issue:`1864`, where some simple tests would perform very slowly,\nbecause they would run many times with each subsequent run being progressively slower.\nThey will now stop after a more reasonable number of runs without hitting this problem.\n\nUnless you are hitting exactly this issue, it is unlikely that this release will have any effect,\nbut certain classes of custom generators that are currently very slow may become a bit faster,\nor start to trigger health check failures.\n\n.. _v4.26.1:\n\n-------------------\n4.26.1 - 2019-07-04\n-------------------\n\nThis release adds the strategy :func:`~hypothesis.extra.numpy.integer_array_indices`,\nwhich generates tuples of Numpy arrays that can be used for\n`advanced indexing <http://www.pythonlikeyoumeanit.com/Module3_IntroducingNumpy/AdvancedIndexing.html#Integer-Array-Indexing>`_\nto select an array of a specified shape.\n\n.. _v4.26.0:\n\n-------------------\n4.26.0 - 2019-07-04\n-------------------\n\nThis release significantly improves the performance of drawing unique collections whose\nelements are drawn from  :func:`~hypothesis.strategies.sampled_from`  strategies.\n\nAs a side effect, this detects an error condition that would previously have\npassed silently: When the ``min_size`` argument on a collection with distinct elements\nis greater than the number of elements being sampled, this will now raise an error.\n\n.. _v4.25.1:\n\n-------------------\n4.25.1 - 2019-07-03\n-------------------\n\nThis release removes some defunct internal functionality that was only being used\nfor testing. It should have no user visible impact.\n\n.. _v4.25.0:\n\n-------------------\n4.25.0 - 2019-07-03\n-------------------\n\nThis release deprecates and disables the ``buffer_size`` setting,\nwhich should have been treated as a private implementation detail\nall along.  We recommend simply deleting this settings argument.\n\n.. _v4.24.6:\n\n-------------------\n4.24.6 - 2019-06-26\n-------------------\n\nThis patch makes :func:`~hypothesis.strategies.datetimes` more efficient,\nas it now handles short months correctly by construction instead of filtering.\n\n.. _v4.24.5:\n\n-------------------\n4.24.5 - 2019-06-23\n-------------------\n\nThis patch improves the development experience by simplifying the tracebacks\nyou will see when e.g. you have used the ``.map(...)`` method of a strategy\nand the mapped function raises an exception.\n\nNo new exceptions can be raised, nor existing exceptions change anything but\ntheir traceback.  We're simply using if-statements rather than exceptions for\ncontrol flow in a certain part of the internals!\n\n.. _v4.24.4:\n\n-------------------\n4.24.4 - 2019-06-21\n-------------------\n\nThis patch fixes :issue:`2014`, where our compatibility layer broke with version\n3.7.4 of the :pypi:`typing` module backport on PyPI.\n\nThis issue only affects Python 2.  We remind users that Hypothesis, like many other\npackages, `will drop Python 2 support on 2020-01-01 <https://python3statement.github.io>`__\nand already has several features that are only available on Python 3.\n\n.. _v4.24.3:\n\n-------------------\n4.24.3 - 2019-06-07\n-------------------\n\nThis patch improves the implementation of an internal wrapper on Python 3.8\nbeta1 (and will break on the alphas; but they're not meant to be stable).\nOn other versions, there is no change at all.\n\nThanks to Daniel Hahler for the patch, and Victor Stinner for his work\non :bpo:`37032` that made it possible.\n\n.. _v4.24.2:\n\n-------------------\n4.24.2 - 2019-06-06\n-------------------\n\nDeprecation messages for functions in ``hypothesis.extra.django.models`` now\nexplicitly name the deprecated function to make it easier to track down usages.\nThanks to Kristian Glass for this contribution!\n\n.. _v4.24.1:\n\n-------------------\n4.24.1 - 2019-06-04\n-------------------\n\nThis patch fixes :issue:`1999`, a spurious bug raised when a :func:`@st.composite <hypothesis.strategies.composite>` function was passed a keyword-only argument.\n\nThanks to Jim Nicholls for his fantastic bug report.\n\n.. _v4.24.0:\n\n-------------------\n4.24.0 - 2019-05-29\n-------------------\n\nThis release deprecates ``GenericStateMachine``, in favor of\n:class:`~hypothesis.stateful.RuleBasedStateMachine`.  Rule-based stateful\ntesting is significantly faster, especially during shrinking.\n\nIf your use-case truly does not fit rule-based stateful testing,\nwe recommend writing a custom test function which drives your specific\ncontrol-flow using :func:`~hypothesis.strategies.data`.\n\n.. _v4.23.9:\n\n-------------------\n4.23.9 - 2019-05-28\n-------------------\n\nThis patch fixes a very rare example database issue with file permissions.\n\nWhen running a test that uses both :func:`@given <hypothesis.given>`\nand ``pytest.mark.parametrize``, using :pypi:`pytest-xdist` on Windows,\nwith failing examples in the database, two attempts to read a file could\noverlap and we caught ``FileNotFound`` but not other ``OSError``\\ s.\n\n.. _v4.23.8:\n\n-------------------\n4.23.8 - 2019-05-26\n-------------------\n\nThis patch has a minor cleanup of the internal engine.\nThere is no user-visible impact.\n\n.. _v4.23.7:\n\n-------------------\n4.23.7 - 2019-05-26\n-------------------\n\nThis patch clarifies some error messages when the test function signature\nis incompatible with the arguments to :func:`@given <hypothesis.given>`,\nespecially when the :obj:`@settings() <hypothesis.settings>` decorator\nis also used (:issue:`1978`).\n\n.. _v4.23.6:\n\n-------------------\n4.23.6 - 2019-05-19\n-------------------\n\nThis release adds the :pypi:`pyupgrade` fixer to our code style,\nfor consistent use of dict and set literals and comprehensions.\n\n.. _v4.23.5:\n\n-------------------\n4.23.5 - 2019-05-16\n-------------------\n\nThis release slightly simplifies a small part of the core engine.\nThere is no user-visible change.\n\n.. _v4.23.4:\n\n-------------------\n4.23.4 - 2019-05-09\n-------------------\n\nFixes a minor formatting issue the docstring of :func:`~hypothesis.strategies.from_type`\n\n.. _v4.23.3:\n\n-------------------\n4.23.3 - 2019-05-09\n-------------------\n\nAdds a recipe to the docstring of :func:`~hypothesis.strategies.from_type`\nthat describes a means for drawing values for \"everything except\" a specified type.\nThis recipe is especially useful for writing tests that perform input-type validation.\n\n.. _v4.23.2:\n\n-------------------\n4.23.2 - 2019-05-08\n-------------------\n\nThis patch uses :pypi:`autoflake` to remove some pointless ``pass`` statements,\nwhich improves our workflow but has no user-visible impact.\n\n.. _v4.23.1:\n\n-------------------\n4.23.1 - 2019-05-08\n-------------------\n\nThis patch fixes an OverflowError in\n:func:`from_type(xrange) <hypothesis.strategies.from_type>` on Python 2.\n\nIt turns out that not only do the ``start`` and ``stop`` values have to\nfit in a C long, but so does ``stop - start``.  We now handle this even\non 32bit platforms, but remind users that Python2 will not be supported\nafter 2019 without specific funding.\n\n.. _v4.23.0:\n\n-------------------\n4.23.0 - 2019-05-08\n-------------------\n\nThis release implements the :func:`~hypothesis.strategies.slices` strategy,\nto generate slices of a length-``size`` sequence.\n\nThanks to Daniel J. West for writing this patch at the PyCon 2019 sprints!\n\n.. _v4.22.3:\n\n-------------------\n4.22.3 - 2019-05-07\n-------------------\n\nThis patch exposes :class:`~hypothesis.strategies.DataObject`, *solely*\nto support more precise type hints.  Objects of this type are provided\nby :func:`~hypothesis.strategies.data`, and can be used to draw examples\nfrom strategies intermixed with your test code.\n\n.. _v4.22.2:\n\n-------------------\n4.22.2 - 2019-05-07\n-------------------\n\nThis patch fixes the very rare :issue:`1798` in\n:func:`~hypothesis.extra.numpy.array_dtypes`,\nwhich caused an internal error in our tests.\n\n.. _v4.22.1:\n\n-------------------\n4.22.1 - 2019-05-07\n-------------------\n\nThis patch fixes a rare bug in :func:`from_type(range) <hypothesis.strategies.from_type>`.\n\nThanks to Zebulun Arendsee for fixing the bug at the PyCon 2019 Sprints.\n\n.. _v4.22.0:\n\n-------------------\n4.22.0 - 2019-05-07\n-------------------\n\nThe ``unique_by`` argument to :obj:`~hypothesis.strategies.lists` now accepts a\ntuple of callables such that every element of the generated list will be unique\nwith respect to each callable in the tuple (:issue:`1916`).\n\nThanks to Marco Sirabella for this feature at the PyCon 2019 sprints!\n\n.. _v4.21.1:\n\n-------------------\n4.21.1 - 2019-05-06\n-------------------\n\nThis patch cleans up the internals of :func:`~hypothesis.strategies.one_of`.\nYou may see a slight change to the distribution of examples from this strategy\nbut there is no change to the public API.\n\nThanks to Marco Sirabella for writing this patch at the PyCon 2019 sprints!\n\n.. _v4.21.0:\n\n-------------------\n4.21.0 - 2019-05-05\n-------------------\n\nThe :func:`~hypothesis.strategies.from_type` strategy now supports\n:class:`python:slice` objects.\n\nThanks to Charlie El. Awbery for writing this feature at the\n`PyCon 2019 Mentored Sprints <https://us.pycon.org/2019/hatchery/mentoredsprints/>`__.\n\n.. _v4.20.0:\n\n-------------------\n4.20.0 - 2019-05-05\n-------------------\n\nThis release improves the :func:`~hypothesis.extra.numpy.array_shapes`\nstrategy, to choose an appropriate default for ``max_side`` based on the\n``min_side``, and ``max_dims`` based on the ``min_dims``.  An explicit\nerror is raised for dimensions greater than 32, which are not supported\nby Numpy, as for other invalid combinations of arguments.\n\nThanks to Jenny Rouleau for writing this feature at the\n`PyCon 2019 Mentored Sprints <https://us.pycon.org/2019/hatchery/mentoredsprints/>`__.\n\n.. _v4.19.0:\n\n-------------------\n4.19.0 - 2019-05-05\n-------------------\n\nThe :func:`~hypothesis.strategies.from_type` strategy now supports\n:class:`python:range` objects (or ``xrange`` on Python 2).\n\nThanks to Katrina Durance for writing this feature at the\n`PyCon 2019 Mentored Sprints <https://us.pycon.org/2019/hatchery/mentoredsprints/>`__.\n\n.. _v4.18.3:\n\n-------------------\n4.18.3 - 2019-04-30\n-------------------\n\nThis release fixes a very rare edge case in the test-case mutator,\nwhich could cause an internal error with certain unusual tests.\n\n.. _v4.18.2:\n\n-------------------\n4.18.2 - 2019-04-30\n-------------------\n\nThis patch makes Hypothesis compatible with the Python 3.8 alpha, which\nchanged the representation of code objects to support positional-only\narguments.  Note however that Hypothesis does not (yet) support such\nfunctions as e.g. arguments to :func:`~hypothesis.strategies.builds`\nor inputs to :func:`@given <hypothesis.given>`.\n\nThanks to Paul Ganssle for identifying and fixing this bug.\n\n.. _v4.18.1:\n\n-------------------\n4.18.1 - 2019-04-29\n-------------------\n\nThis patch improves the performance of unique collections such as\n:func:`~hypothesis.strategies.sets` when the elements are drawn from a\n:func:`~hypothesis.strategies.sampled_from` strategy (:issue:`1115`).\n\n.. _v4.18.0:\n\n-------------------\n4.18.0 - 2019-04-24\n-------------------\n\nThis release adds the :func:`~hypothesis.strategies.functions` strategy,\nwhich can be used to imitate your 'real' function for callbacks.\n\n.. _v4.17.2:\n\n-------------------\n4.17.2 - 2019-04-19\n-------------------\n\nThis release refactors stateful rule selection to share the new machinery\nwith :func:`~hypothesis.strategies.sampled_from` instead of using the original\nindependent implementation.\n\n.. _v4.17.1:\n\n-------------------\n4.17.1 - 2019-04-16\n-------------------\n\nThis patch allows Hypothesis to try a few more examples after finding the\nfirst bug, in hopes of reporting multiple distinct bugs.  The heuristics\ndescribed in :issue:`847` ensure that we avoid wasting time on fruitless\nsearches, while still surfacing each bug as soon as possible.\n\n.. _v4.17.0:\n\n-------------------\n4.17.0 - 2019-04-16\n-------------------\n\nThis release adds the strategy :func:`~hypothesis.extra.numpy.broadcastable_shapes`,\nwhich generates array shapes that are `broadcast-compatible <https://www.pythonlikeyoumeanit.com/Module3_IntroducingNumpy/Broadcasting.html#Rules-of-Broadcasting>`_\nwith a provided shape.\n\n.. _v4.16.0:\n\n-------------------\n4.16.0 - 2019-04-12\n-------------------\n\nThis release allows :func:`~hypothesis.strategies.register_type_strategy` to be used\nwith :obj:`python:typing.NewType` instances.  This may be useful to e.g. provide\nonly positive integers for :func:`from_type(UserId) <hypothesis.strategies.from_type>`\nwith a ``UserId = NewType('UserId', int)`` type.\n\nThanks to PJCampi for suggesting and writing the patch!\n\n.. _v4.15.0:\n\n-------------------\n4.15.0 - 2019-04-09\n-------------------\n\nThis release supports passing a :class:`~python:datetime.timedelta` as the\n:obj:`~hypothesis.settings.deadline` setting, so you no longer have to remember\nthat the number is in milliseconds (:issue:`1900`).\n\nThanks to Damon Francisco for this change!\n\n.. _v4.14.7:\n\n-------------------\n4.14.7 - 2019-04-09\n-------------------\n\nThis patch makes the type annotations on ``hypothesis.extra.dateutil``\ncompatible with :pypi:`mypy` 0.700.\n\n.. _v4.14.6:\n\n-------------------\n4.14.6 - 2019-04-07\n-------------------\n\nThis release fixes a bug introduced in :ref:`Hypothesis 4.14.3 <v4.14.3>`\nthat would sometimes cause\n:func:`sampled_from(...).filter(...) <hypothesis.strategies.sampled_from>`\nto encounter an internal assertion failure when there are three or fewer\nelements, and every element is rejected by the filter.\n\n.. _v4.14.5:\n\n-------------------\n4.14.5 - 2019-04-05\n-------------------\n\nThis patch takes the previous efficiency improvements to\n:func:`sampled_from(...).filter(...) <hypothesis.strategies.sampled_from>`\nstrategies that reject most elements, and generalises them to also apply to\n``sampled_from(...).filter(...).filter(...)`` and longer chains of filters.\n\n.. _v4.14.4:\n\n-------------------\n4.14.4 - 2019-04-05\n-------------------\n\nThis release fixes a bug that prevented\n:func:`~hypothesis.strategies.random_module`\nfrom correctly restoring the previous state of the ``random`` module.\n\nThe random state was instead being restored to a temporary deterministic\nstate, which accidentally caused subsequent tests to see the same random values\nacross multiple test runs.\n\n.. _v4.14.3:\n\n-------------------\n4.14.3 - 2019-04-03\n-------------------\n\nThis patch adds an internal special case to make\n:func:`sampled_from(...).filter(...) <hypothesis.strategies.sampled_from>`\nmuch more efficient when the filter rejects most elements (:issue:`1885`).\n\n.. _v4.14.2:\n\n-------------------\n4.14.2 - 2019-03-31\n-------------------\n\nThis patch improves the error message if the function ``f`` in\n:func:`s.flatmap(f) <hypothesis.strategies.SearchStrategy.flatmap>` does not return a strategy.\n\nThanks to Kai Chen for this change!\n\n.. _v4.14.1:\n\n-------------------\n4.14.1 - 2019-03-30\n-------------------\n\nThis release modifies how Hypothesis selects operations to run during shrinking,\nby causing it to deprioritise previously useless classes of shrink until others have reached a fixed point.\n\nThis avoids certain pathological cases where the shrinker gets very close to finishing and then takes a very long time to finish the last small changes because it tries many useless shrinks for each useful one towards the end.\nIt also should cause a more modest improvement (probably no more than about 30%) in shrinking performance for most tests.\n\n.. _v4.14.0:\n\n-------------------\n4.14.0 - 2019-03-19\n-------------------\n\nThis release blocks installation of Hypothesis on Python 3.4, which\n:PEP:`reached its end of life date on 2019-03-18 <429>`.\n\nThis should not be of interest to anyone but downstream maintainers -\nif you are affected, migrate to a secure version of Python as soon as\npossible or at least seek commercial support.\n\n.. _v4.13.0:\n\n-------------------\n4.13.0 - 2019-03-19\n-------------------\n\nThis release makes it an explicit error to call\n:func:`floats(min_value=inf, exclude_min=True) <hypothesis.strategies.floats>` or\n:func:`floats(max_value=-inf, exclude_max=True) <hypothesis.strategies.floats>`,\nas there are no possible values that can be generated (:issue:`1859`).\n\n:func:`floats(min_value=0.0, max_value=-0.0) <hypothesis.strategies.floats>`\nis now deprecated.  While ``0. == -0.`` and we could thus generate either if\ncomparing by value, violating the sequence ordering of floats is a special\ncase we don't want or need.\n\n.. _v4.12.1:\n\n-------------------\n4.12.1 - 2019-03-18\n-------------------\n\nThis release should significantly reduce the amount of memory that Hypothesis uses for representing large test cases,\nby storing information in a more compact representation and only unpacking it lazily when it is first needed.\n\n.. _v4.12.0:\n\n-------------------\n4.12.0 - 2019-03-18\n-------------------\n\nThis update adds the :obj:`~hypothesis.settings.report_multiple_bugs` setting,\nwhich you can use to disable multi-bug reporting and only raise whichever bug\nhad the smallest minimal example.  This is occasionally useful when using a\ndebugger or tools that annotate tracebacks via introspection.\n\n.. _v4.11.7:\n\n-------------------\n4.11.7 - 2019-03-18\n-------------------\n\nThis change makes a tiny improvement to the core engine's bookkeeping.\nThere is no user-visible change.\n\n.. _v4.11.6:\n\n-------------------\n4.11.6 - 2019-03-15\n-------------------\n\nThis release changes some of Hypothesis's internal shrinking behaviour in order to reduce memory usage and hopefully improve performance.\n\n.. _v4.11.5:\n\n-------------------\n4.11.5 - 2019-03-13\n-------------------\n\nThis release adds a micro-optimisation to how Hypothesis handles debug reporting internally.\nHard to shrink test may see a slight performance improvement, but in most common scenarios it is unlikely to be noticeable.\n\n.. _v4.11.4:\n\n-------------------\n4.11.4 - 2019-03-13\n-------------------\n\nThis release removes some redundant code that was no longer needed but was still running a significant amount of computation and allocation on the hot path.\nThis should result in a modest speed improvement for most tests, especially those with large test cases.\n\n.. _v4.11.3:\n\n-------------------\n4.11.3 - 2019-03-13\n-------------------\n\nThis release adds a micro-optimisation to how Hypothesis caches test cases.\nThis will cause a small improvement in speed and memory usage for large test cases,\nbut in most common scenarios it is unlikely to be noticeable.\n\n.. _v4.11.2:\n\n-------------------\n4.11.2 - 2019-03-13\n-------------------\n\nThis release removes some internal code that populates a field that is no longer used anywhere.\nThis should result in some modest performance and speed improvements and no other user visible effects.\n\n.. _v4.11.1:\n\n-------------------\n4.11.1 - 2019-03-13\n-------------------\n\nThis is a formatting-only patch, enabled by a new version of :pypi:`isort`.\n\n.. _v4.11.0:\n\n-------------------\n4.11.0 - 2019-03-12\n-------------------\n\nThis release deprecates :func:`~hypothesis.strategies.sampled_from` with empty\nsequences.  This returns :func:`~hypothesis.strategies.nothing`, which gives a\nclear error if used directly... but simply vanishes if combined with another\nstrategy.\n\nTests that silently generate less than expected are a serious problem for\nanyone relying on them to find bugs, and we think reliability more important\nthan convenience in this case.\n\n.. _v4.10.0:\n\n-------------------\n4.10.0 - 2019-03-11\n-------------------\n\nThis release improves Hypothesis's to detect flaky tests, by noticing when the behaviour of the test changes between runs.\nIn particular this will notice many new cases where data generation depends on external state (e.g. external sources of randomness) and flag those as flaky sooner and more reliably.\n\nThe basis of this feature is a considerable reengineering of how Hypothesis stores its history of test cases,\nso on top of this its memory usage should be considerably reduced.\n\n.. _v4.9.0:\n\n------------------\n4.9.0 - 2019-03-09\n------------------\n\nThis release adds the strategy :func:`~hypothesis.extra.numpy.valid_tuple_axes`,\nwhich generates tuples of axis-indices that can be passed to the ``axis`` argument\nin NumPy's sequential functions (e.g. :func:`numpy:numpy.sum`).\n\nThanks to Ryan Soklaski for this strategy.\n\n.. _v4.8.0:\n\n------------------\n4.8.0 - 2019-03-06\n------------------\n\nThis release significantly tightens validation in :class:`hypothesis.settings`.\n:obj:`~hypothesis.settings.max_examples`, ``buffer_size``,\nand :obj:`~hypothesis.settings.stateful_step_count` must be positive integers;\n:obj:`~hypothesis.settings.deadline` must be a positive number or ``None``; and\n:obj:`~hypothesis.settings.derandomize` must be either ``True`` or ``False``.\n\nAs usual, this replaces existing errors with a more helpful error and starts new\nvalidation checks as deprecation warnings.\n\n.. _v4.7.19:\n\n-------------------\n4.7.19 - 2019-03-04\n-------------------\n\nThis release makes some micro-optimisations to certain calculations performed in the shrinker.\nThese should particularly speed up large test cases where the shrinker makes many small changes.\nIt will also reduce the amount allocated, but most of this is garbage that would have been immediately thrown away,\nso you probably won't see much effect specifically from that.\n\n.. _v4.7.18:\n\n-------------------\n4.7.18 - 2019-03-03\n-------------------\n\nThis patch removes some overhead from :func:`~hypothesis.extra.numpy.arrays`\nwith a constant shape and dtype.  The resulting performance improvement is\nmodest, but worthwhile for small arrays.\n\n.. _v4.7.17:\n\n-------------------\n4.7.17 - 2019-03-01\n-------------------\n\nThis release makes some micro-optimisations within Hypothesis's internal representation of test cases.\nThis should cause heavily nested test cases to allocate less during generation and shrinking,\nwhich should speed things up slightly.\n\n.. _v4.7.16:\n\n-------------------\n4.7.16 - 2019-02-28\n-------------------\n\nThis changes the order in which Hypothesis runs certain operations during shrinking.\nThis should significantly decrease memory usage and speed up shrinking of large examples.\n\n.. _v4.7.15:\n\n-------------------\n4.7.15 - 2019-02-28\n-------------------\n\nThis release allows Hypothesis to calculate a number of attributes of generated test cases lazily.\nThis should significantly reduce memory usage and modestly improve performance,\nespecially for large test cases.\n\n.. _v4.7.14:\n\n-------------------\n4.7.14 - 2019-02-28\n-------------------\n\nThis release reduces the number of operations the shrinker will try when reordering parts of a test case.\nThis should in some circumstances significantly speed up shrinking. It *may* result in different final test cases,\nand if so usually slightly worse ones, but it should not generally have much impact on the end result as the operations removed were typically useless.\n\n.. _v4.7.13:\n\n-------------------\n4.7.13 - 2019-02-27\n-------------------\n\nThis release changes how Hypothesis reorders examples within a test case during shrinking.\nThis should make shrinking considerably faster.\n\n.. _v4.7.12:\n\n-------------------\n4.7.12 - 2019-02-27\n-------------------\n\nThis release slightly improves the shrinker's ability to replace parts of a test case with their minimal version,\nby allowing it to do so in bulk rather than one at a time. Where this is effective, shrinker performance should be modestly improved.\n\n.. _v4.7.11:\n\n-------------------\n4.7.11 - 2019-02-25\n-------------------\n\nThis release makes some micro-optimisations to common operations performed during shrinking.\nShrinking should now be slightly faster, especially for large examples with relatively fast test functions.\n\n.. _v4.7.10:\n\n-------------------\n4.7.10 - 2019-02-25\n-------------------\n\nThis release is a purely internal refactoring of Hypothesis's API for representing test cases.\nThere should be no user visible effect.\n\n.. _v4.7.9:\n\n------------------\n4.7.9 - 2019-02-24\n------------------\n\nThis release changes certain shrink passes to make them more efficient when\nthey aren't making progress.\n\n.. _v4.7.8:\n\n------------------\n4.7.8 - 2019-02-23\n------------------\n\nThis patch removes some unused code, which makes the internals\na bit easier to understand.  There is no user-visible impact.\n\n.. _v4.7.7:\n\n------------------\n4.7.7 - 2019-02-23\n------------------\n\nThis release reduces the number of operations the shrinker will try when reordering parts of a test case.\nThis should in some circumstances significantly speed up shrinking. It *may* result in different final test cases,\nand if so usually slightly worse ones, but it should not generally have much impact on the end result as the operations removed were typically useless.\n\n.. _v4.7.6:\n\n------------------\n4.7.6 - 2019-02-23\n------------------\n\nThis patch removes some unused code from the shrinker.\nThere is no user-visible change.\n\n.. _v4.7.5:\n\n------------------\n4.7.5 - 2019-02-23\n------------------\n\nThis release changes certain shrink passes to make them *adaptive* - that is,\nin cases where they are successfully making progress they may now do so significantly\nfaster.\n\n.. _v4.7.4:\n\n------------------\n4.7.4 - 2019-02-22\n------------------\n\nThis is a docs-only patch, noting that because the :pypi:`lark-parser` is under active\ndevelopment at version 0.x, ``hypothesis[lark]`` APIs may break in minor\nreleases if necessary to keep up with the upstream package.\n\n.. _v4.7.3:\n\n------------------\n4.7.3 - 2019-02-22\n------------------\n\nThis changes Hypothesis to no longer import various test frameworks by default (if they are installed).\nwhich will speed up the initial ``import hypothesis`` call.\n\n.. _v4.7.2:\n\n------------------\n4.7.2 - 2019-02-22\n------------------\n\nThis release changes Hypothesis's internal representation of a test case to calculate some expensive structural information on demand rather than eagerly.\nThis should reduce memory usage a fair bit, and may make generation somewhat faster.\n\n.. _v4.7.1:\n\n------------------\n4.7.1 - 2019-02-21\n------------------\n\nThis release refactors the internal representation of previously run test cases.\nThe main thing you should see as a result is that Hypothesis becomes somewhat less memory hungry.\n\n.. _v4.7.0:\n\n------------------\n4.7.0 - 2019-02-21\n------------------\n\nThis patch allows :func:`~hypothesis.extra.numpy.array_shapes` to generate shapes\nwith side-length or even dimension zero, though the minimum still defaults to\none.  These shapes are rare and have some odd behavior, but are particularly\nimportant to test for just that reason!\n\nIn a related bigfix, :func:`~hypothesis.extra.numpy.arrays` now supports generating\nzero-dimensional arrays with ``dtype=object`` and a strategy for iterable elements.\nPreviously, the array element would incorrectly be set to the first item in the\ngenerated iterable.\n\nThanks to Ryan Turner for continuing to improve our Numpy support.\n\n.. _v4.6.1:\n\n------------------\n4.6.1 - 2019-02-19\n------------------\n\nThis release is a trivial micro-optimisation inside Hypothesis which should result in it using significantly less memory.\n\n.. _v4.6.0:\n\n------------------\n4.6.0 - 2019-02-18\n------------------\n\nThis release changes some inconsistent behavior of :func:`~hypothesis.extra.numpy.arrays`\nfrom the Numpy extra when asked for an array of ``shape=()``.\n:func:`~hypothesis.extra.numpy.arrays` will now always return a Numpy\n:class:`~numpy:numpy.ndarray`, and the array will always be of the requested dtype.\n\nThanks to Ryan Turner for this change.\n\n.. _v4.5.12:\n\n-------------------\n4.5.12 - 2019-02-18\n-------------------\n\nThis release fixes a minor typo in an internal comment. There is no user-visible change.\n\n.. _v4.5.11:\n\n-------------------\n4.5.11 - 2019-02-15\n-------------------\n\nThis release fixes :issue:`1813`, a bug introduced in :ref:`3.59.1 <v3.59.1>`,\nwhich caused :py:meth:`~hypothesis.strategies.random_module` to no longer affect the body of the test:\nAlthough Hypothesis would claim to be seeding the random module in fact tests would always run with a seed of zero.\n\n.. _v4.5.10:\n\n-------------------\n4.5.10 - 2019-02-14\n-------------------\n\nThis patch fixes an off-by-one error in the maximum length of :func:`~hypothesis.strategies.emails`.\nThanks to Krzysztof Jurewicz for :pull:`1812`.\n\n.. _v4.5.9:\n\n------------------\n4.5.9 - 2019-02-14\n------------------\n\nThis patch removes some unused code from the shrinker.\nThere is no user-visible change.\n\n.. _v4.5.8:\n\n------------------\n4.5.8 - 2019-02-12\n------------------\n\nThis release fixes an internal ``IndexError`` in Hypothesis that could sometimes be triggered during shrinking.\n\n.. _v4.5.7:\n\n------------------\n4.5.7 - 2019-02-11\n------------------\n\nThis release modifies the shrinker to interleave different types of reduction operations,\ne.g. switching between deleting data and lowering scalar values rather than trying entirely deletions then entirely lowering.\n\nThis may slow things down somewhat in the typical case, but has the major advantage that many previously difficult to shrink examples should become much faster,\nbecause the shrinker will no longer tend to stall when trying some ineffective changes to the shrink target but will instead interleave it with other more effective operations.\n\n.. _v4.5.6:\n\n------------------\n4.5.6 - 2019-02-11\n------------------\n\nThis release makes a number of internal changes to the implementation of :func:`hypothesis.extra.lark.from_lark`.\nThese are primarily intended as a refactoring, but you may see some minor improvements to performance when generating large strings,\nand possibly to shrink quality.\n\n.. _v4.5.5:\n\n------------------\n4.5.5 - 2019-02-10\n------------------\n\nThis patch prints an explanatory note when :issue:`1798` is triggered,\nbecause the error message from Numpy is too terse to locate the problem.\n\n.. _v4.5.4:\n\n------------------\n4.5.4 - 2019-02-08\n------------------\n\nIn Python 2, ``long`` integers are not allowed in the shape argument to\n:func:`~hypothesis.extra.numpy.arrays`.  Thanks to Ryan Turner for fixing this.\n\n.. _v4.5.3:\n\n------------------\n4.5.3 - 2019-02-08\n------------------\n\nThis release makes a small internal refactoring to clarify how Hypothesis\ninstructs tests to stop running when appropriate. There is no user-visible\nchange.\n\n.. _v4.5.2:\n\n------------------\n4.5.2 - 2019-02-06\n------------------\n\nThis release standardises all of the shrinker's internal operations on running in a random order.\n\nThe main effect you will see from this that it should now be much less common for the shrinker to stall for a long time before making further progress.\nIn some cases this will correspond to shrinking more slowly, but on average it should result in faster shrinking.\n\n.. _v4.5.1:\n\n------------------\n4.5.1 - 2019-02-05\n------------------\n\nThis patch updates some docstrings, but has no runtime changes.\n\n.. _v4.5.0:\n\n------------------\n4.5.0 - 2019-02-03\n------------------\n\nThis release adds ``exclude_min`` and ``exclude_max`` arguments to\n:func:`~hypothesis.strategies.floats`, so that you can easily generate values from\n:wikipedia:`open or half-open intervals <Interval_(mathematics)>`\n(:issue:`1622`).\n\n.. _v4.4.6:\n\n------------------\n4.4.6 - 2019-02-03\n------------------\n\nThis patch fixes a bug where :func:`~hypothesis.strategies.from_regex`\ncould throw an internal error if the :obj:`python:re.IGNORECASE` flag\nwas used (:issue:`1786`).\n\n.. _v4.4.5:\n\n------------------\n4.4.5 - 2019-02-02\n------------------\n\nThis release removes two shrink passes that Hypothesis runs late in the process.\nThese were very expensive when the test function was slow and often didn't do anything useful.\n\nShrinking should get faster for most failing tests.\nIf you see any regression in example quality as a result of this release, please let us know.\n\n.. _v4.4.4:\n\n------------------\n4.4.4 - 2019-02-02\n------------------\n\nThis release modifies the way that Hypothesis deletes data during shrinking.\nIt will primarily be noticeable for very large examples, which should now shrink faster.\n\nThe shrinker is now also able to perform some deletions that it could not previously,\nbut this is unlikely to be very noticeable.\n\n.. _v4.4.3:\n\n------------------\n4.4.3 - 2019-01-25\n------------------\n\nThis release fixes an open file leak that used to cause ``ResourceWarning``\\ s.\n\n.. _v4.4.2:\n\n------------------\n4.4.2 - 2019-01-24\n------------------\n\nThis release changes Hypothesis's internal approach to caching the results of executing test cases.\nThe result should be that it is now significantly less memory hungry, especially when shrinking large test cases.\n\nSome tests may get slower or faster depending on whether the new or old caching strategy was well suited to them,\nbut any change in speed in either direction should be minor.\n\n.. _v4.4.1:\n\n------------------\n4.4.1 - 2019-01-24\n------------------\n\nThis patch tightens up some of our internal heuristics to deal with shrinking floating point numbers,\nwhich will now run in fewer circumstances.\n\nYou are fairly unlikely to see much difference from this, but if you do you are likely to see shrinking become slightly faster and/or producing slightly worse results.\n\n.. _v4.4.0:\n\n------------------\n4.4.0 - 2019-01-24\n------------------\n\nThis release adds the :func:`~hypothesis.extra.django.from_form` function, which allows automatic testing against Django forms. (:issue:`35`)\n\nThanks to Paul Stiverson for this feature, which resolves our oldest open issue!\n\n.. _v4.3.0:\n\n------------------\n4.3.0 - 2019-01-24\n------------------\n\nThis release deprecates ``HealthCheck.hung_test`` and disables the\nassociated runtime check for tests that ran for more than five minutes.\nSuch a check is redundant now that we enforce the ``deadline`` and\n``max_examples`` setting, which can be adjusted independently.\n\n.. _v4.2.0:\n\n------------------\n4.2.0 - 2019-01-23\n------------------\n\nThis release adds a new module, ``hypothesis.extra.lark``, which you\ncan use to generate strings matching a context-free grammar.\n\nIn this initial version, only :pypi:`lark-parser` EBNF grammars are supported,\nby the new :func:`hypothesis.extra.lark.from_lark` function.\n\n.. _v4.1.2:\n\n------------------\n4.1.2 - 2019-01-23\n------------------\n\nThis patch fixes a very rare overflow bug (:issue:`1748`) which could raise an\n``InvalidArgument`` error in :func:`~hypothesis.strategies.complex_numbers`\neven though the arguments were valid.\n\n.. _v4.1.1:\n\n------------------\n4.1.1 - 2019-01-23\n------------------\n\nThis release makes some improvements to internal code organisation and documentation and has no impact on behaviour.\n\n.. _v4.1.0:\n\n------------------\n4.1.0 - 2019-01-22\n------------------\n\nThis release adds :func:`~hypothesis.register_random`, which registers\n``random.Random`` instances or compatible objects to be seeded and reset\nby Hypothesis to ensure that test cases are deterministic.\n\nWe still recommend explicitly passing a ``random.Random`` instance from\n:func:`~hypothesis.strategies.randoms` if possible, but registering a\nframework-global state for Hypothesis to manage is better than flaky tests!\n\n.. _v4.0.2:\n\n------------------\n4.0.2 - 2019-01-22\n------------------\n\nThis patch fixes :issue:`1387`, where bounded :func:`~hypothesis.strategies.integers`\nwith a very large range would almost always generate very large numbers.\nNow, we usually use the same tuned distribution as unbounded\n:func:`~hypothesis.strategies.integers`.\n\n.. _v4.0.1:\n\n------------------\n4.0.1 - 2019-01-16\n------------------\n\nThis release randomizes the order in which the shrinker tries some of its initial normalization operations.\nYou are unlikely to see much difference as a result unless your generated examples are very large.\nIn this case you may see some performance improvements in shrinking.\n\n.. _v4.0.0:\n\n------------------\n4.0.0 - 2019-01-14\n------------------\n\nWelcome to the next major version of Hypothesis!\n\nThere are no new features here, as we release those in minor versions.\nInstead, 4.0 is a chance for us to remove deprecated features (many already\nconverted into no-ops), and turn a variety of warnings into errors.\n\nIf you were running on the last version of Hypothesis 3.x *without any\nHypothesis deprecation warnings* (or using private APIs), this will be\na very boring upgrade.  **In fact, nothing will change for you at all.**\nPer :ref:`our deprecation policy <deprecation-policy>`, warnings added in\nthe last six months (after 2018-07-05) have not been converted to errors.\n\n\nRemovals\n~~~~~~~~\n- ``hypothesis.extra.datetime`` has been removed, replaced by the core\n  date and time strategies.\n- ``hypothesis.extra.fakefactory`` has been removed, replaced by general\n  expansion of Hypothesis' strategies and the third-party ecosystem.\n- The SQLite example database backend has been removed.\n\nSettings\n~~~~~~~~\n- The :obj:`~hypothesis.settings.deadline` is now enforced by default, rather than just\n  emitting a warning when the default (200 milliseconds per test case) deadline is exceeded.\n- The ``database_file`` setting has been removed; use :obj:`~hypothesis.settings.database`.\n- The ``perform_health_check`` setting has been removed; use\n  :obj:`~hypothesis.settings.suppress_health_check`.\n- The ``max_shrinks`` setting has been removed; use :obj:`~hypothesis.settings.phases`\n  to disable shrinking.\n- The ``min_satisfying_examples``, ``max_iterations``, ``strict``, ``timeout``, and\n  ``use_coverage`` settings have been removed without user-configurable replacements.\n\nStrategies\n~~~~~~~~~~\n- The ``elements`` argument is now required for collection strategies.\n- The ``average_size`` argument was a no-op and has been removed.\n- Date and time strategies now only accept ``min_value`` and ``max_value`` for bounds.\n- :func:`~hypothesis.strategies.builds` now requires that the thing to build is\n  passed as the first positional argument.\n- Alphabet validation for :func:`~hypothesis.strategies.text` raises errors, not warnings,\n  as does category validation for :func:`~hypothesis.strategies.characters`.\n- The ``choices()`` strategy has been removed.  Instead, you can use\n  :func:`~hypothesis.strategies.data` with :func:`~hypothesis.strategies.sampled_from`,\n  so ``choice(elements)`` becomes ``data.draw(sampled_from(elements))``.\n- The ``streaming()`` strategy has been removed.  Instead, you can use\n  :func:`~hypothesis.strategies.data` and replace iterating over the stream with\n  ``data.draw()`` calls.\n- :func:`~hypothesis.strategies.sampled_from` and :func:`~hypothesis.strategies.permutations`\n  raise errors instead of warnings if passed a collection that is not a sequence.\n\nMiscellaneous\n~~~~~~~~~~~~~\n- Applying :func:`@given <hypothesis.given>` to a test function multiple times\n  was really inefficient, and now it's also an error.\n- Using the ``.example()`` method of a strategy (intended for interactive\n  exploration) within another strategy or a test function always weakened\n  data generation and broke shrinking, and now it's an error too.\n- The ``HYPOTHESIS_DATABASE_FILE`` environment variable is no longer\n  supported, as the ``database_file`` setting has been removed.\n- The ``HYPOTHESIS_VERBOSITY_LEVEL`` environment variable is no longer\n  supported.  You can use the ``--hypothesis-verbosity`` pytest argument instead,\n  or write your own setup code using the settings profile system to replace it.\n- Using :func:`@seed <hypothesis.seed>` or\n  :obj:`derandomize=True <hypothesis.settings.derandomize>` now forces\n  :obj:`database=None <hypothesis.settings.database>` to ensure results\n  are in fact reproducible.  If :obj:`~hypothesis.settings.database` is\n  *not* ``None``, doing so also emits a ``HypothesisWarning``.\n- Unused exception types have been removed from ``hypothesis.errors``;\n  namely ``AbnormalExit``, ``BadData``, ``BadTemplateDraw``,\n  ``DefinitelyNoSuchExample``, ``Timeout``, and ``WrongFormat``.\n\n\nHypothesis 3.x\n==============\n\n.. _v3.88.3:\n\n-------------------\n3.88.3 - 2019-01-11\n-------------------\n\nThis changes the order that the shrinker tries certain operations in its \"emergency\" phase which runs late in the process.\nThe new order should be better at avoiding long stalls where the shrinker is failing to make progress,\nwhich may be helpful if you have difficult to shrink test cases.\nHowever this will not be noticeable in the vast majority of use cases.\n\n.. _v3.88.2:\n\n-------------------\n3.88.2 - 2019-01-11\n-------------------\n\nThis is a pure refactoring release that extracts some logic from the core Hypothesis engine\ninto its own class and file. It should have no user visible impact.\n\n.. _v3.88.1:\n\n-------------------\n3.88.1 - 2019-01-11\n-------------------\n\nThis patch fixes some markup in our documentation.\n\n.. _v3.88.0:\n\n-------------------\n3.88.0 - 2019-01-10\n-------------------\n\nIntroduces :func:`hypothesis.stateful.multiple`, which allows rules in rule\nbased state machines to send multiple results at once to their target Bundle,\nor none at all.\n\n.. _v3.87.0:\n\n-------------------\n3.87.0 - 2019-01-10\n-------------------\n\nThis release contains a massive cleanup of the Hypothesis for Django extra:\n\n- ``hypothesis.extra.django.models.models()`` is deprecated in favor of\n  :func:`hypothesis.extra.django.from_model`.\n- ``hypothesis.extra.django.models.add_default_field_mapping()`` is deprecated\n  in favor of :func:`hypothesis.extra.django.register_field_strategy`.\n- :func:`~hypothesis.extra.django.from_model` does not infer a strategy for\n  nullable fields or fields with a default unless passed ``infer``, like\n  :func:`~hypothesis.strategies.builds`.\n  ``models.models()`` would usually but not always infer, and a special\n  ``default_value`` marker object was required to disable inference.\n\n.. _v3.86.9:\n\n-------------------\n3.86.9 - 2019-01-09\n-------------------\n\nThis release improves some internal logic about when a test case in Hypothesis's internal representation could lead to a valid test case.\nIn some circumstances this can lead to a significant speed up during shrinking.\nIt may have some minor negative impact on the quality of the final result due to certain shrink passes now having access to less information about test cases in some circumstances, but this should rarely matter.\n\n.. _v3.86.8:\n\n-------------------\n3.86.8 - 2019-01-09\n-------------------\n\nThis release has no user visible changes but updates our URLs to use HTTPS.\n\n.. _v3.86.7:\n\n-------------------\n3.86.7 - 2019-01-08\n-------------------\n\nHypothesis can now automatically generate values for Django models with a\n`~django.db.models.URLField`, thanks to a new provisional strategy for URLs (:issue:`1388`).\n\n.. _v3.86.6:\n\n-------------------\n3.86.6 - 2019-01-07\n-------------------\n\nThis release is a pure refactoring that extracts some internal code into its own file.\nIt should have no user visible effect.\n\n.. _v3.86.5:\n\n-------------------\n3.86.5 - 2019-01-06\n-------------------\n\nThis is a docs-only patch, which fixes some typos and removes a few hyperlinks\nfor deprecated features.\n\n.. _v3.86.4:\n\n-------------------\n3.86.4 - 2019-01-04\n-------------------\n\nThis release changes the order in which the shrinker tries to delete data.\nFor large and slow tests this may significantly improve the performance of shrinking.\n\n.. _v3.86.3:\n\n-------------------\n3.86.3 - 2019-01-04\n-------------------\n\nThis release fixes a bug where certain places Hypothesis internal errors could be\nraised during shrinking when a user exception occurred that suppressed an exception\nHypothesis uses internally in its generation.\n\nThe two known ways to trigger this problem were:\n\n* Errors raised in stateful tests' teardown function.\n* Errors raised in finally blocks that wrapped a call to ``data.draw``.\n\nThese cases will now be handled correctly.\n\n.. _v3.86.2:\n\n-------------------\n3.86.2 - 2019-01-04\n-------------------\n\nThis patch is a docs-only change to fix a broken hyperlink.\n\n.. _v3.86.1:\n\n-------------------\n3.86.1 - 2019-01-04\n-------------------\n\nThis patch fixes :issue:`1732`, where :func:`~hypothesis.strategies.integers`\nwould always return ``long`` values on Python 2.\n\n.. _v3.86.0:\n\n-------------------\n3.86.0 - 2019-01-03\n-------------------\n\nThis release ensures that infinite numbers are never generated by\n:func:`~hypothesis.strategies.floats` with ``allow_infinity=False``,\nwhich could previously happen in some cases where one bound was also\nprovided.\n\nThe trivially inconsistent ``min_value=inf, allow_infinity=False`` now\nraises an InvalidArgumentError, as does the inverse with ``max_value``.\nYou can still use :func:`just(inf) <hypothesis.strategies.just>` to\ngenerate ``inf`` without violating other constraints.\n\n.. _v3.85.3:\n\n-------------------\n3.85.3 - 2019-01-02\n-------------------\n\nHappy new year everyone!\nThis release has no user visible changes but updates our copyright headers to include 2019.\n\n.. _v3.85.2:\n\n-------------------\n3.85.2 - 2018-12-31\n-------------------\n\nThis release makes a small change to the way the shrinker works.\nYou may see some improvements to speed of shrinking on especially large and hard to shrink examples,\nbut most users are unlikely to see much difference.\n\n.. _v3.85.1:\n\n-------------------\n3.85.1 - 2018-12-30\n-------------------\n\nThis patch fixes :issue:`1700`, where a line that contained a Unicode character\nbefore a lambda definition would cause an internal exception.\n\n.. _v3.85.0:\n\n-------------------\n3.85.0 - 2018-12-29\n-------------------\n\nIntroduces the :func:`hypothesis.stateful.consumes` function. When defining\na rule in stateful testing, it can be used to mark bundles from which values\nshould be consumed, i. e. removed after use in the rule. This has been\nproposed in :issue:`136`.\n\nThanks to Jochen Müller for this long-awaited feature.\n\n.. _v3.84.6:\n\n-------------------\n3.84.6 - 2018-12-28\n-------------------\n\nThis patch makes a small internal change to fix an issue in Hypothesis's\nown coverage tests (:issue:`1718`).\n\nThere is no user-visible change.\n\n.. _v3.84.5:\n\n-------------------\n3.84.5 - 2018-12-21\n-------------------\n\nThis patch refactors the ``hypothesis.strategies`` module, so that private\nnames should no longer appear in tab-completion lists.  We previously relied\non ``__all__`` for this, but not all editors respect it.\n\n.. _v3.84.4:\n\n-------------------\n3.84.4 - 2018-12-21\n-------------------\n\nThis is a follow-up patch to ensure that the deprecation date is automatically\nrecorded for any new deprecations.  There is no user-visible effect.\n\n.. _v3.84.3:\n\n-------------------\n3.84.3 - 2018-12-20\n-------------------\n\nThis patch updates the Hypothesis pytest plugin to avoid a recently\ndeprecated hook interface.  There is no user-visible change.\n\n.. _v3.84.2:\n\n-------------------\n3.84.2 - 2018-12-19\n-------------------\n\nThis patch fixes the internals for :func:`~hypothesis.strategies.integers`\nwith one bound.  Values from this strategy now always shrink towards zero\ninstead of towards the bound, and should shrink much more efficiently too.\nOn Python 2, providing a bound incorrectly excluded ``long`` integers,\nwhich can now be generated.\n\n.. _v3.84.1:\n\n-------------------\n3.84.1 - 2018-12-18\n-------------------\n\nThis patch adds information about when features were deprecated, but this\nis only recorded internally and has no user-visible effect.\n\n.. _v3.84.0:\n\n-------------------\n3.84.0 - 2018-12-18\n-------------------\n\nThis release changes the stateful testing backend from\n``find()`` to use :func:`@given <hypothesis.given>`\n(:issue:`1300`).  This doesn't change how you create stateful tests,\nbut does make them run more like other Hypothesis tests.\n\n:func:`@reproduce_failure <hypothesis.reproduce_failure>` and\n:func:`@seed <hypothesis.seed>` now work for stateful tests.\n\nStateful tests now respect the :attr:`~hypothesis.settings.deadline`\nand :attr:`~hypothesis.settings.suppress_health_check` settings,\nthough they are disabled by default.  You can enable them by using\n:func:`@settings(...) <hypothesis.settings>` as a class decorator\nwith whatever arguments you prefer.\n\n.. _v3.83.2:\n\n-------------------\n3.83.2 - 2018-12-17\n-------------------\n\nHypothesis has adopted :pypi:`black` as our code formatter (:issue:`1686`).\nThere are no functional changes to the source, but it's prettier!\n\n.. _v3.83.1:\n\n-------------------\n3.83.1 - 2018-12-13\n-------------------\n\nThis patch increases the variety of examples generated by\n:func:`~hypothesis.strategies.from_type`.\n\n.. _v3.83.0:\n\n-------------------\n3.83.0 - 2018-12-12\n-------------------\n\nOur pytest plugin now warns you when strategy functions have been collected\nas tests, which may happen when e.g. using the\n:func:`@composite <hypothesis.strategies.composite>` decorator when you\nshould be using ``@given(st.data())`` for inline draws.\nSuch functions *always* pass when treated as tests, because the lazy creation\nof strategies mean that the function body is never actually executed!\n\n.. _v3.82.6:\n\n-------------------\n3.82.6 - 2018-12-11\n-------------------\n\nHypothesis can now :ref:`show statistics <statistics>` when running\nunder :pypi:`pytest-xdist`.  Previously, statistics were only reported\nwhen all tests were run in a single process (:issue:`700`).\n\n.. _v3.82.5:\n\n-------------------\n3.82.5 - 2018-12-08\n-------------------\n\nThis patch fixes :issue:`1667`, where passing bounds of Numpy\ndtype ``int64`` to :func:`~hypothesis.strategies.integers` could\ncause errors on Python 3 due to internal rounding.\n\n.. _v3.82.4:\n\n-------------------\n3.82.4 - 2018-12-08\n-------------------\n\nHypothesis now seeds and resets the global state of\n:mod:`np.random <numpy:numpy.random>` for each\ntest case, to ensure that tests are reproducible.\n\nThis matches and complements the existing handling of the\n:mod:`python:random` module - Numpy simply maintains an\nindependent PRNG for performance reasons.\n\n.. _v3.82.3:\n\n-------------------\n3.82.3 - 2018-12-08\n-------------------\n\nThis is a no-op release to add the new ``Framework :: Hypothesis``\n`trove classifier <https://pypi.org/classifiers/>`_ to\n:pypi:`hypothesis` on PyPI.\n\nYou can `use it as a filter <https://pypi.org/search/?c=Framework+%3A%3A+Hypothesis>`_\nto find Hypothesis-related packages such as extensions as they add the tag\nover the coming weeks, or simply visit :doc:`our curated list <reference/strategies>`.\n\n.. _v3.82.2:\n\n-------------------\n3.82.2 - 2018-12-08\n-------------------\n\nThe :ref:`Hypothesis for Pandas extension <hypothesis-pandas>` is now\nlisted in ``setup.py``, so you can ``pip install hypothesis[pandas]``.\nThanks to jmshi for this contribution.\n\n.. _v3.82.1:\n\n-------------------\n3.82.1 - 2018-10-29\n-------------------\n\nThis patch fixes :func:`~hypothesis.strategies.from_type` on Python 2\nfor classes where ``cls.__init__ is object.__init__``.\nThanks to ccxcz for reporting :issue:`1656`.\n\n.. _v3.82.0:\n\n-------------------\n3.82.0 - 2018-10-29\n-------------------\n\nThe ``alphabet`` argument for :func:`~hypothesis.strategies.text` now\nuses its default value of ``characters(exclude_categories=('Cs',))``\ndirectly, instead of hiding that behind ``alphabet=None`` and replacing\nit within the function.  Passing ``None`` is therefore deprecated.\n\n.. _v3.81.0:\n\n-------------------\n3.81.0 - 2018-10-27\n-------------------\n\n``GenericStateMachine`` and\n:class:`~hypothesis.stateful.RuleBasedStateMachine` now raise an explicit error\nwhen instances of :obj:`~hypothesis.settings` are assigned to the classes'\nsettings attribute, which is a no-op (:issue:`1643`). Instead assign to\n``SomeStateMachine.TestCase.settings``, or use ``@settings(...)`` as a class\ndecorator to handle this automatically.\n\n.. _v3.80.0:\n\n-------------------\n3.80.0 - 2018-10-25\n-------------------\n\nSince :ref:`version 3.68.0 <v3.68.0>`, :func:`~hypothesis.extra.numpy.arrays`\nchecks that values drawn from the ``elements`` and ``fill`` strategies can be\nsafely cast to the dtype of the array, and emits a warning otherwise.\n\nThis release expands the checks to cover overflow for finite ``complex64``\nelements and string truncation caused by too-long elements or trailing null\ncharacters (:issue:`1591`).\n\n.. _v3.79.4:\n\n-------------------\n3.79.4 - 2018-10-25\n-------------------\n\nTests using :func:`@given <hypothesis.given>` now shrink errors raised from\n:pypi:`pytest` helper functions, instead of reporting the first example found.\n\nThis was previously fixed in :ref:`version 3.56.0 <v3.56.0>`, but only for\nstateful testing.\n\n.. _v3.79.3:\n\n-------------------\n3.79.3 - 2018-10-23\n-------------------\n\nTraceback elision is now disabled on Python 2, to avoid an import-time\n:class:`python:SyntaxError` under Python < 2.7.9 (Python: :bpo:`21591`,\n:ref:`Hypothesis 3.79.2 <v3.79.2>`: :issue:`1648`).\n\nWe encourage all users to `upgrade to Python 3 before the end of 2019\n<https://pythonclock.org/>`_.\n\n.. _v3.79.2:\n\n-------------------\n3.79.2 - 2018-10-23\n-------------------\n\nThis patch shortens tracebacks from Hypothesis, so you can see exactly\nhappened in your code without having to skip over irrelevant details\nabout our internals (:issue:`848`).\n\nIn the example test (see :pull:`1582`), this reduces tracebacks from\nnine frames to just three - and for a test with multiple errors, from\nseven frames per error to just one!\n\nIf you *do* want to see the internal details, you can disable frame\nelision by setting :obj:`~hypothesis.settings.verbosity` to ``debug``.\n\n.. _v3.79.1:\n\n-------------------\n3.79.1 - 2018-10-22\n-------------------\n\nThe abstract number classes :class:`~python:numbers.Number`,\n:class:`~python:numbers.Complex`, :class:`~python:numbers.Real`,\n:class:`~python:numbers.Rational`, and :class:`~python:numbers.Integral`\nare now supported by the :func:`~hypothesis.strategies.from_type`\nstrategy.  Previously, you would have to use\n:func:`~hypothesis.strategies.register_type_strategy` before they\ncould be resolved (:issue:`1636`)\n\n.. _v3.79.0:\n\n-------------------\n3.79.0 - 2018-10-18\n-------------------\n\nThis release adds a CLI flag for verbosity ``--hypothesis-verbosity`` to\nthe Hypothesis pytest plugin, applied after loading the profile specified by\n``--hypothesis-profile``. Valid options are the names of verbosity settings,\nquiet, normal, verbose or debug.\n\nThanks to Bex Dunn for writing this patch at the PyCon Australia\nsprints!\n\nThe pytest header now correctly reports the current profile if\n``--hypothesis-profile`` has been used.\n\nThanks to Mathieu Paturel for the contribution at the Canberra Python\nHacktoberfest.\n\n.. _v3.78.0:\n\n-------------------\n3.78.0 - 2018-10-16\n-------------------\n\nThis release has deprecated the generation of integers, floats and fractions\nwhen the conversion of the upper and/ or lower bound is not 100% exact, e.g.\nwhen an integer gets passed a bound that is not a whole number. (:issue:`1625`)\n\nThanks to Felix Grünewald for this patch during Hacktoberfest 2018.\n\n.. _v3.77.0:\n\n-------------------\n3.77.0 - 2018-10-16\n-------------------\n\nThis minor release adds functionality to :obj:`~hypothesis.settings` allowing\nit to be used as a decorator on :obj:`~hypothesis.stateful.RuleBasedStateMachine`\nand ``GenericStateMachine``.\n\nThanks to Tyler Nickerson for this feature in #hacktoberfest!\n\n.. _v3.76.1:\n\n-------------------\n3.76.1 - 2018-10-16\n-------------------\n\nThis patch fixes some warnings added by recent releases of\n:pypi:`pydocstyle` and :pypi:`mypy`.\n\n.. _v3.76.0:\n\n-------------------\n3.76.0 - 2018-10-11\n-------------------\n\nThis release deprecates using floats for ``min_size`` and ``max_size``.\n\nThe type hint for ``average_size`` arguments has been changed from\n``Optional[int]`` to None, because non-None values are always ignored and\ndeprecated.\n\n.. _v3.75.4:\n\n-------------------\n3.75.4 - 2018-10-10\n-------------------\n\nThis patch adds more internal comments to the core engine's sequence-length\nshrinker. There should be no user-visible change.\n\n.. _v3.75.3:\n\n-------------------\n3.75.3 - 2018-10-09\n-------------------\n\nThis patch adds additional comments to some of the core engine's internal\ndata structures. There is no user-visible change.\n\n.. _v3.75.2:\n\n-------------------\n3.75.2 - 2018-10-09\n-------------------\n\nThis patch avoids caching a trivial case, fixing :issue:`493`.\n\n.. _v3.75.1:\n\n-------------------\n3.75.1 - 2018-10-09\n-------------------\n\nThis patch fixes a broken link in a docstring.\nThanks to Benjamin Lee for this contribution!\n\n.. _v3.75.0:\n\n-------------------\n3.75.0 - 2018-10-08\n-------------------\n\nThis release deprecates  the use of ``min_size=None``, setting the default\n``min_size`` to 0 (:issue:`1618`).\n\n.. _v3.74.3:\n\n-------------------\n3.74.3 - 2018-10-08\n-------------------\n\nThis patch makes some small internal changes to comply with a new lint setting\nin the build. There should be no user-visible change.\n\n.. _v3.74.2:\n\n-------------------\n3.74.2 - 2018-10-03\n-------------------\n\nThis patch fixes :issue:`1153`, where time spent reifying a strategy was\nalso counted in the time spent generating the first example.  Strategies\nare now fully constructed and validated before the timer is started.\n\n.. _v3.74.1:\n\n-------------------\n3.74.1 - 2018-10-03\n-------------------\n\nThis patch fixes some broken formatting and links in the documentation.\n\n.. _v3.74.0:\n\n-------------------\n3.74.0 - 2018-10-01\n-------------------\n\nThis release checks that the value of the\n:attr:`~hypothesis.settings.print_blob` setting is a\n``PrintSettings`` instance.\n\nBeing able to specify a boolean value was not intended, and is now deprecated.\nIn addition, specifying ``True`` will now cause the blob to always be printed,\ninstead of causing it to be suppressed.\n\nSpecifying any value that is not a ``PrintSettings``\nor a boolean is now an error.\n\n.. _v3.73.5:\n\n-------------------\n3.73.5 - 2018-10-01\n-------------------\n\nChanges the documentation for ``hypothesis.strategies.datetimes``, ``hypothesis.strategies.dates``, ``hypothesis.strategies.times`` to use the new parameter names ``min_value`` and ``max_value`` instead of the deprecated names\n\n.. _v3.73.4:\n\n-------------------\n3.73.4 - 2018-09-30\n-------------------\n\nThis patch ensures that Hypothesis deprecation warnings display the code\nthat emitted them when you're not running in ``-Werror`` mode (:issue:`652`).\n\n.. _v3.73.3:\n\n-------------------\n3.73.3 - 2018-09-27\n-------------------\n\nTracebacks involving :func:`@composite <hypothesis.strategies.composite>`\nare now slightly shorter due to some internal refactoring.\n\n.. _v3.73.2:\n\n-------------------\n3.73.2 - 2018-09-26\n-------------------\n\nThis patch fixes errors in the internal comments for one of the shrinker\npasses. There is no user-visible change.\n\n.. _v3.73.1:\n\n-------------------\n3.73.1 - 2018-09-25\n-------------------\n\nThis patch substantially improves the distribution of data generated\nwith :func:`~hypothesis.strategies.recursive`, and fixes a rare internal\nerror (:issue:`1502`).\n\n.. _v3.73.0:\n\n-------------------\n3.73.0 - 2018-09-24\n-------------------\n\nThis release adds the :func:`~hypothesis.extra.dpcontracts.fulfill` function,\nwhich is designed for testing code that uses :pypi:`dpcontracts` 0.4 or later\nfor input validation.  This provides some syntactic sugar around use of\n:func:`~hypothesis.assume`, to automatically filter out and retry calls that\ncause a precondition check to fail (:issue:`1474`).\n\n.. _v3.72.0:\n\n-------------------\n3.72.0 - 2018-09-24\n-------------------\n\nThis release makes setting attributes of the :class:`hypothesis.settings`\nclass an explicit error.  This has never had any effect, but could mislead\nusers who confused it with the current settings *instance*\n``hypothesis.settings.default`` (which is also immutable).  You can change\nthe global settings with |settings.register_profile|.\n\n.. _v3.71.11:\n\n--------------------\n3.71.11 - 2018-09-24\n--------------------\n\nThis patch factors out some common code in the shrinker for iterating\nover pairs of data blocks. There should be no user-visible change.\n\n.. _v3.71.10:\n\n--------------------\n3.71.10 - 2018-09-18\n--------------------\n\nThis patch allows :func:`~hypothesis.strategies.from_type` to handle the\nempty tuple type, :obj:`typing.Tuple[()] <python:typing.Tuple>`.\n\n.. _v3.71.9:\n\n-------------------\n3.71.9 - 2018-09-17\n-------------------\n\nThis patch updates some internal comments for :pypi:`mypy`.\nThere is no user-visible effect, even for Mypy users.\n\n.. _v3.71.8:\n\n-------------------\n3.71.8 - 2018-09-17\n-------------------\n\nThis patch fixes a rare bug that would cause a particular shrinker pass to\nraise an IndexError, if a shrink improvement changed the underlying data\nin an unexpected way.\n\n.. _v3.71.7:\n\n-------------------\n3.71.7 - 2018-09-17\n-------------------\n\nThis release fixes the broken cross-references in our docs,\nand adds a CI check so we don't add new ones.\n\n.. _v3.71.6:\n\n-------------------\n3.71.6 - 2018-09-16\n-------------------\n\nThis patch fixes two bugs (:issue:`944` and :issue:`1521`), where messages\nabout :func:`@seed <hypothesis.seed>` did not check the current verbosity\nsetting, and the wrong settings were active while executing\nexplicit examples from |@example|.\n\n.. _v3.71.5:\n\n-------------------\n3.71.5 - 2018-09-15\n-------------------\n\nThis patch fixes a ``DeprecationWarning`` added in Python 3.8 (:issue:`1576`).\n\nThanks to tirkarthi for this contribution!\n\n.. _v3.71.4:\n\n-------------------\n3.71.4 - 2018-09-14\n-------------------\n\nThis is a no-op release, which implements automatic DOI minting and code\narchival of Hypothesis via `Zenodo <https://zenodo.org/>`_. Thanks to\nCERN and the EU *Horizon 2020* programme for providing this service!\n\nCheck our :gh-file:`CITATION.cff` file for details, or head right on over to\n`doi.org/10.5281/zenodo.1412597 <https://doi.org/10.5281/zenodo.1412597>`_\n\n.. _v3.71.3:\n\n-------------------\n3.71.3 - 2018-09-10\n-------------------\n\nThis release adds the test name to some deprecation warnings,\nfor easier debugging.\n\nThanks to Sanyam Khurana for the patch!\n\n.. _v3.71.2:\n\n-------------------\n3.71.2 - 2018-09-10\n-------------------\n\nThis release makes Hypothesis's memory usage substantially smaller for tests with many\nexamples, by bounding the number of past examples it keeps around.\n\nYou will not see much difference unless you are running tests with :obj:`~hypothesis.settings.max_examples`\nset to well over ``1000``, but if you do have such tests then you should see memory usage mostly plateau\nwhere previously it would have grown linearly with time.\n\n.. _v3.71.1:\n\n-------------------\n3.71.1 - 2018-09-09\n-------------------\n\nThis patch adds internal comments to some tree traversals in the core engine.\nThere is no user-visible change.\n\n.. _v3.71.0:\n\n-------------------\n3.71.0 - 2018-09-08\n-------------------\n\nThis release deprecates the coverage-guided testing functionality,\nas it has proven brittle and does not really pull its weight.\n\nWe intend to replace it with something more useful in the future,\nbut the feature in its current form does not seem to be worth the cost of using,\nand whatever replaces it will likely look very different.\n\n.. _v3.70.4:\n\n-------------------\n3.70.4 - 2018-09-08\n-------------------\n\nThis patch changes the behaviour of :func:`~hypothesis.reproduce_failure`\nso that blobs are only printed in quiet mode when the\n:obj:`~hypothesis.settings.print_blob` setting is set to ``ALWAYS``.\n\nThanks to Cameron McGill for writing this patch at the PyCon Australia sprints!\n\n.. _v3.70.3:\n\n-------------------\n3.70.3 - 2018-09-03\n-------------------\n\nThis patch removes some unnecessary code from the internals.\nThere is no user-visible change.\n\n.. _v3.70.2:\n\n-------------------\n3.70.2 - 2018-09-03\n-------------------\n\nThis patch fixes an internal bug where a corrupted argument to\n:func:`@reproduce_failure <hypothesis.reproduce_failure>` could raise\nthe wrong type of error.  Thanks again to Paweł T. Jochym, who maintains\nHypothesis on `conda-forge <https://conda-forge.org/>`_ and consistently\nprovides excellent bug reports including :issue:`1558`.\n\n.. _v3.70.1:\n\n-------------------\n3.70.1 - 2018-09-03\n-------------------\n\nThis patch updates hypothesis to report its version and settings when run with\npytest. (:issue:`1223`).\n\nThanks to Jack Massey for this feature.\n\n.. _v3.70.0:\n\n-------------------\n3.70.0 - 2018-09-01\n-------------------\n\nThis release adds a ``fullmatch`` argument to\n:func:`~hypothesis.strategies.from_regex`.  When ``fullmatch=True``, the\nwhole example will match the regex pattern as for :func:`python:re.fullmatch`.\n\nThanks to Jakub Nabaglo for writing this patch at the PyCon Australia sprints!\n\n.. _v3.69.12:\n\n--------------------\n3.69.12 - 2018-08-30\n--------------------\n\nThis release reverts the changes to logging handling in 3.69.11,\nwhich broke test that use the :pypi:`pytest` ``caplog`` fixture\ninternally because all logging was disabled (:issue:`1546`).\n\n.. _v3.69.11:\n\n--------------------\n3.69.11 - 2018-08-29\n--------------------\n\nThis patch will hide all logging messages produced by test cases before the\nfinal, minimal, failing test case (:issue:`356`).\n\nThanks to Gary Donovan for writing this patch at the PyCon Australia sprints!\n\n.. _v3.69.10:\n\n--------------------\n3.69.10 - 2018-08-29\n--------------------\n\nThis patch fixes a bug that prevents coverage from reporting unexecuted\nPython files (:issue:`1085`).\n\nThanks to Gary Donovan for writing this patch at the PyCon Australia sprints!\n\n.. _v3.69.9:\n\n-------------------\n3.69.9 - 2018-08-28\n-------------------\n\nThis patch improves the packaging of the Python package by adding\n``LICENSE.txt`` to the sdist (:issue:`1311`), clarifying the minimum\nsupported versions of :pypi:`pytz` and :pypi:`dateutil <python-dateutil>`\n(:issue:`1383`), and adds keywords to the metadata (:issue:`1520`).\n\nThanks to Graham Williamson for writing this patch at the PyCon\nAustralia sprints!\n\n.. _v3.69.8:\n\n-------------------\n3.69.8 - 2018-08-28\n-------------------\n\nThis is an internal change which replaces pickle with json to prevent possible\nsecurity issues.\n\nThanks to Vidya Rani D G for writing this patch at the PyCon Australia sprints!\n\n.. _v3.69.7:\n\n-------------------\n3.69.7 - 2018-08-28\n-------------------\n\nThis patch ensures that :func:`~hypothesis.note` prints the note for every\ntest case when the :obj:`~hypothesis.settings.verbosity` setting is\n``Verbosity.verbose``.  At normal verbosity it only prints from the final\ntest case.\n\nThanks to Tom McDermott for writing this patch at\nthe PyCon Australia sprints!\n\n.. _v3.69.6:\n\n-------------------\n3.69.6 - 2018-08-27\n-------------------\n\nThis patch improves the testing of some internal caching.  It should have\nno user-visible effect.\n\n.. _v3.69.5:\n\n-------------------\n3.69.5 - 2018-08-27\n-------------------\n\nThis change performs a small rename and refactoring in the core engine.\nThere is no user-visible change.\n\n.. _v3.69.4:\n\n-------------------\n3.69.4 - 2018-08-27\n-------------------\n\nThis change improves the core engine's ability to avoid unnecessary work,\nby consulting its cache of previously-tried inputs in more cases.\n\n.. _v3.69.3:\n\n-------------------\n3.69.3 - 2018-08-27\n-------------------\n\nThis patch handles passing an empty :class:`python:enum.Enum` to\n:func:`~hypothesis.strategies.from_type` by returning\n:func:`~hypothesis.strategies.nothing`, instead of raising an\ninternal :class:`python:AssertionError`.\n\nThanks to Paul Amazona for writing this patch at the\nPyCon Australia sprints!\n\n.. _v3.69.2:\n\n-------------------\n3.69.2 - 2018-08-23\n-------------------\n\nThis patch fixes a small mistake in an internal comment.\nThere is no user-visible change.\n\n.. _v3.69.1:\n\n-------------------\n3.69.1 - 2018-08-21\n-------------------\n\nThis change fixes a small bug in how the core engine consults its cache\nof previously-tried inputs. There is unlikely to be any user-visible change.\n\n.. _v3.69.0:\n\n-------------------\n3.69.0 - 2018-08-20\n-------------------\n\nThis release improves argument validation for stateful testing.\n\n- If the target or targets of a :func:`~hypothesis.stateful.rule` are invalid,\n  we now raise a useful validation error rather than an internal exception.\n- Passing both the ``target`` and ``targets`` arguments is deprecated -\n  append the ``target`` bundle to the ``targets`` tuple of bundles instead.\n- Passing the name of a Bundle rather than the Bundle itself is also deprecated.\n\n.. _v3.68.3:\n\n-------------------\n3.68.3 - 2018-08-20\n-------------------\n\nThis is a docs-only patch, fixing some typos and formatting issues.\n\n.. _v3.68.2:\n\n-------------------\n3.68.2 - 2018-08-19\n-------------------\n\nThis change fixes a small bug in how the core engine caches the results of\npreviously-tried inputs. The effect is unlikely to be noticeable, but it might\navoid unnecessary work in some cases.\n\n.. _v3.68.1:\n\n-------------------\n3.68.1 - 2018-08-18\n-------------------\n\nThis patch documents the :func:`~hypothesis.extra.numpy.from_dtype` function,\nwhich infers a strategy for :class:`numpy:numpy.dtype`\\ s.  This is used in\n:func:`~hypothesis.extra.numpy.arrays`, but can also be used directly when\ncreating e.g. Pandas objects.\n\n.. _v3.68.0:\n\n-------------------\n3.68.0 - 2018-08-15\n-------------------\n\n:func:`~hypothesis.extra.numpy.arrays` now checks that integer and float\nvalues drawn from ``elements`` and ``fill`` strategies can be safely cast\nto the dtype of the array, and emits a warning otherwise (:issue:`1385`).\n\nElements in the resulting array could previously violate constraints on\nthe elements strategy due to floating-point overflow or truncation of\nintegers to fit smaller types.\n\n.. _v3.67.1:\n\n-------------------\n3.67.1 - 2018-08-14\n-------------------\n\nThis release contains a tiny refactoring of the internals.\nThere is no user-visible change.\n\n.. _v3.67.0:\n\n-------------------\n3.67.0 - 2018-08-10\n-------------------\n\nThis release adds a ``width`` argument to :func:`~hypothesis.strategies.floats`,\nto generate lower-precision floating point numbers for e.g. Numpy arrays.\n\nThe generated examples are always instances of Python's native ``float``\ntype, which is 64bit, but passing ``width=32`` will ensure that all values\ncan be exactly represented as 32bit floats.  This can be useful to avoid\noverflow (to +/- infinity), and for efficiency of generation and shrinking.\n\nHalf-precision floats (``width=16``) are also supported, but require Numpy\nif you are running Python 3.5 or earlier.\n\n.. _v3.66.33:\n\n--------------------\n3.66.33 - 2018-08-10\n--------------------\n\nThis release fixes a bug in :func:`~hypothesis.strategies.floats`, where\nsetting ``allow_infinity=False`` and exactly one of ``min_value`` and\n``max_value`` would allow infinite values to be generated.\n\n.. _v3.66.32:\n\n--------------------\n3.66.32 - 2018-08-09\n--------------------\n\nThis release adds type hints to the :obj:`@example() <hypothesis.example>` and\n:func:`~hypothesis.seed` decorators, and fixes the type hint on\n:func:`~hypothesis.strategies.register_type_strategy`. The second argument to\n:func:`~hypothesis.strategies.register_type_strategy` must either be a\n``SearchStrategy``, or a callable which takes a ``type`` and returns a\n``SearchStrategy``.\n\n.. _v3.66.31:\n\n--------------------\n3.66.31 - 2018-08-08\n--------------------\n\nAnother set of changes designed to improve the performance of shrinking on\nlarge examples. In particular the shrinker should now spend considerably less\ntime running useless shrinks.\n\n.. _v3.66.30:\n\n--------------------\n3.66.30 - 2018-08-06\n--------------------\n\n\"Bug fixes and performance improvements\".\n\nThis release is a fairly major overhaul of the shrinker designed to improve\nits behaviour on large examples, especially around stateful testing. You\nshould hopefully see shrinking become much faster, with little to no quality\ndegradation (in some cases quality may even improve).\n\n.. _v3.66.29:\n\n--------------------\n3.66.29 - 2018-08-05\n--------------------\n\nThis release fixes two very minor bugs in the core engine:\n\n* it fixes a corner case that was missing in :ref:`3.66.28 <v3.66.28>`, which\n  should cause shrinking to work slightly better.\n* it fixes some logic for how shrinking interacts with the database that was\n  causing Hypothesis to be insufficiently aggressive about clearing out old\n  keys.\n\n.. _v3.66.28:\n\n--------------------\n3.66.28 - 2018-08-05\n--------------------\n\nThis release improves how Hypothesis handles reducing the size of integers'\nrepresentation. This change should mostly be invisible as it's purely about\nthe underlying representation and not the generated value, but it may result\nin some improvements to shrink performance.\n\n.. _v3.66.27:\n\n--------------------\n3.66.27 - 2018-08-05\n--------------------\n\nThis release changes the order in which Hypothesis chooses parts of the test case\nto shrink. For typical usage this should be a significant performance improvement on\nlarge examples. It is unlikely to have a major impact on example quality, but where\nit does change the result it should usually be an improvement.\n\n.. _v3.66.26:\n\n--------------------\n3.66.26 - 2018-08-05\n--------------------\n\nThis release improves the debugging information that the shrinker emits about\nthe operations it performs, giving better summary statistics about which\npasses resulted in test executions and whether they were successful.\n\n.. _v3.66.25:\n\n--------------------\n3.66.25 - 2018-08-05\n--------------------\n\nThis release fixes several bugs that were introduced to the shrinker in\n:ref:`3.66.24 <v3.66.24>` which would have caused it to behave significantly\nless well than advertised. With any luck you should *actually* see the promised\nbenefits now.\n\n.. _v3.66.24:\n\n--------------------\n3.66.24 - 2018-08-03\n--------------------\n\nThis release changes how Hypothesis deletes data when shrinking in order to\nbetter handle deletion of large numbers of contiguous sequences. Most tests\nshould see little change, but this will hopefully provide a significant\nspeed up for :ref:`stateful testing <stateful>`.\n\n.. _v3.66.23:\n\n--------------------\n3.66.23 - 2018-08-02\n--------------------\n\nThis release makes some internal changes to enable further improvements to the\nshrinker. You may see some changes in the final shrunk examples, but they are\nunlikely to be significant.\n\n.. _v3.66.22:\n\n--------------------\n3.66.22 - 2018-08-01\n--------------------\n\nThis release adds some more internal caching to the shrinker. This should cause\na significant speed up for shrinking, especially for stateful testing and\nlarge example sizes.\n\n.. _v3.66.21:\n\n--------------------\n3.66.21 - 2018-08-01\n--------------------\n\nThis patch is for downstream packagers - our tests now pass under\n:pypi:`pytest` 3.7.0 (released 2018-07-30).  There are no changes\nto the source of Hypothesis itself.\n\n.. _v3.66.20:\n\n--------------------\n3.66.20 - 2018-08-01\n--------------------\n\nThis release removes some functionality from the shrinker that was taking a\nconsiderable amount of time and does not appear to be useful any more due to\na number of quality improvements in the shrinker.\n\nYou may see some degradation in shrink quality as a result of this, but mostly\nshrinking should just get much faster.\n\n.. _v3.66.19:\n\n--------------------\n3.66.19 - 2018-08-01\n--------------------\n\nThis release slightly changes the format of some debugging information emitted\nduring shrinking, and refactors some of the internal interfaces around that.\n\n.. _v3.66.18:\n\n--------------------\n3.66.18 - 2018-07-31\n--------------------\n\nThis release is a very small internal refactoring which should have no user\nvisible impact.\n\n.. _v3.66.17:\n\n--------------------\n3.66.17 - 2018-07-31\n--------------------\n\nThis release fixes a bug that could cause an ``IndexError`` to be raised from\ninside Hypothesis during shrinking. It is likely that it was impossible to\ntrigger this bug in practice - it was only made visible by some currently\nunreleased work.\n\n.. _v3.66.16:\n\n--------------------\n3.66.16 - 2018-07-31\n--------------------\n\nThis release is a very small internal refactoring which should have no user\nvisible impact.\n\n.. _v3.66.15:\n\n--------------------\n3.66.15 - 2018-07-31\n--------------------\n\nThis release makes Hypothesis's shrinking faster by removing some redundant\nwork that it does when minimizing values in its internal representation.\n\n.. _v3.66.14:\n\n--------------------\n3.66.14 - 2018-07-30\n--------------------\n\nThis release expands the deprecation of timeout from :ref:`3.16.0 <v3.16.0>` to\nalso emit the deprecation warning in ``find`` or :ref:`stateful testing <stateful>`.\n\n.. _v3.66.13:\n\n--------------------\n3.66.13 - 2018-07-30\n--------------------\n\nThis release adds an additional shrink pass that is able to reduce the size of\nexamples in some cases where the transformation is non-obvious. In particular\nthis will improve the quality of some examples which would have regressed in\n:ref:`3.66.12 <v3.66.12>`.\n\n.. _v3.66.12:\n\n--------------------\n3.66.12 - 2018-07-28\n--------------------\n\nThis release changes how we group data together for shrinking. It should result\nin improved shrinker performance, especially in stateful testing.\n\n.. _v3.66.11:\n\n--------------------\n3.66.11 - 2018-07-28\n--------------------\n\nThis patch modifies how which rule to run is selected during\n:ref:`rule based stateful testing <stateful>`. This should result in a slight\nperformance increase during generation and a significant performance and\nquality improvement when shrinking.\n\nAs a result of this change, some state machines which would previously have\nthrown an ``InvalidDefinition`` are no longer detected as invalid.\n\n.. _v3.66.10:\n\n--------------------\n3.66.10 - 2018-07-28\n--------------------\n\nThis release weakens some minor functionality in the shrinker that had only\nmodest benefit and made its behaviour much harder to reason about.\n\nThis is unlikely to have much user visible effect, but it is possible that in\nsome cases shrinking may get slightly slower. It is primarily to make it easier\nto work on the shrinker and pave the way for future work.\n\n.. _v3.66.9:\n\n-------------------\n3.66.9 - 2018-07-26\n-------------------\n\nThis release improves the information that Hypothesis emits about its shrinking\nwhen :obj:`~hypothesis.settings.verbosity` is set to debug.\n\n.. _v3.66.8:\n\n-------------------\n3.66.8 - 2018-07-24\n-------------------\n\nThis patch includes some minor fixes in the documentation, and updates\nthe minimum version of :pypi:`pytest` to 3.0 (released August 2016).\n\n.. _v3.66.7:\n\n-------------------\n3.66.7 - 2018-07-24\n-------------------\n\nThis release fixes a bug where difficult to shrink tests could sometimes\ntrigger an internal assertion error inside the shrinker.\n\n.. _v3.66.6:\n\n-------------------\n3.66.6 - 2018-07-23\n-------------------\n\nThis patch ensures that Hypothesis fully supports Python 3.7, by\nupgrading :func:`~hypothesis.strategies.from_type` (:issue:`1264`)\nand fixing some minor issues in our test suite (:issue:`1148`).\n\n.. _v3.66.5:\n\n-------------------\n3.66.5 - 2018-07-22\n-------------------\n\nThis patch fixes the online docs for various extras, by ensuring that\ntheir dependencies are installed on readthedocs.io (:issue:`1326`).\n\n.. _v3.66.4:\n\n-------------------\n3.66.4 - 2018-07-20\n-------------------\n\nThis release improves the shrinker's ability to reorder examples.\n\nFor example, consider the following test:\n\n.. code-block:: python\n\n    import hypothesis.strategies as st\n    from hypothesis import given\n\n    @given(st.text(), st.text())\n    def test_non_equal(x, y):\n        assert x != y\n\nPreviously this could have failed with either of ``x=\"\", y=\"0\"`` or\n``x=\"0\", y=\"\"``. Now it should always fail with ``x=\"\", y=\"0\"``.\n\nThis will allow the shrinker to produce more consistent results, especially in\ncases where test cases contain some ordered collection whose actual order does\nnot matter.\n\n.. _v3.66.3:\n\n-------------------\n3.66.3 - 2018-07-20\n-------------------\n\nThis patch fixes inference in the :func:`~hypothesis.strategies.builds`\nstrategy with subtypes of :obj:`python:typing.NamedTuple`, where the\n``__init__`` method is not useful for introspection.  We now use the\nfield types instead - thanks to James Uther for identifying this bug.\n\n.. _v3.66.2:\n\n-------------------\n3.66.2 - 2018-07-19\n-------------------\n\nThis release improves the shrinker's ability to handle situations where there\nis an additive constraint between two values.\n\nFor example, consider the following test:\n\n\n.. code-block:: python\n\n    import hypothesis.strategies as st\n    from hypothesis import given\n\n    @given(st.integers(), st.integers())\n    def test_does_not_exceed_100(m, n):\n        assert m + n < 100\n\nPreviously this could have failed with almost any pair ``(m, n)`` with\n``0 <= m <= n`` and ``m + n == 100``. Now it should almost always fail with\n``m=0, n=100``.\n\nThis is a relatively niche specialisation, but can be useful in situations\nwhere e.g. a bug is triggered by an integer overflow.\n\n.. _v3.66.1:\n\n-------------------\n3.66.1 - 2018-07-09\n-------------------\n\nThis patch fixes a rare bug where an incorrect percentage drawtime\ncould be displayed for a test, when the system clock was changed during\na test running under Python 2 (we use :func:`python:time.monotonic`\nwhere it is available to avoid such problems).  It also fixes a possible\nzero-division error that can occur when the underlying C library\ndouble-rounds an intermediate value in :func:`python:math.fsum` and\ngets the least significant bit wrong.\n\n.. _v3.66.0:\n\n-------------------\n3.66.0 - 2018-07-05\n-------------------\n\nThis release improves validation of the ``alphabet`` argument to the\n:func:`~hypothesis.strategies.text` strategy.  The following misuses\nare now deprecated, and will be an error in a future version:\n\n- passing an unordered collection (such as ``set('abc')``), which\n  violates invariants about shrinking and reproducibility\n- passing an alphabet sequence with elements that are not strings\n- passing an alphabet sequence with elements that are not of length one,\n  which violates any size constraints that may apply\n\nThanks to Sushobhit for adding these warnings (:issue:`1329`).\n\n.. _v3.65.3:\n\n-------------------\n3.65.3 - 2018-07-04\n-------------------\n\nThis release fixes a mostly theoretical bug where certain usage of the internal\nAPI could trigger an assertion error inside Hypothesis. It is unlikely that\nthis problem is even possible to trigger through the public API.\n\n.. _v3.65.2:\n\n-------------------\n3.65.2 - 2018-07-04\n-------------------\n\nThis release fixes dependency information for coverage.  Previously Hypothesis\nwould allow installing :pypi:`coverage` with any version, but it only works\nwith coverage 4.0 or later.\n\nWe now specify the correct metadata in our ``setup.py``, so Hypothesis will\nonly allow installation with compatible versions of coverage.\n\n.. _v3.65.1:\n\n-------------------\n3.65.1 - 2018-07-03\n-------------------\n\nThis patch ensures that :ref:`stateful tests <stateful>` which raise an\nerror from a :pypi:`pytest` helper still print the sequence of steps\ntaken to reach that point (:issue:`1372`).  This reporting was previously\nbroken because the helpers inherit directly from :class:`python:BaseException`, and\ntherefore require special handling to catch without breaking e.g. the use\nof ctrl-C to quit the test.\n\n.. _v3.65.0:\n\n-------------------\n3.65.0 - 2018-06-30\n-------------------\n\nThis release deprecates the ``max_shrinks`` setting\nin favor of an internal heuristic.  If you need to avoid shrinking examples,\nuse the :obj:`~hypothesis.settings.phases` setting instead.  (:issue:`1235`)\n\n.. _v3.64.2:\n\n-------------------\n3.64.2 - 2018-06-27\n-------------------\n\nThis release fixes a bug where an internal assertion error could sometimes be\ntriggered while shrinking a failing test.\n\n.. _v3.64.1:\n\n-------------------\n3.64.1 - 2018-06-27\n-------------------\n\nThis patch fixes type-checking errors in our vendored pretty-printer,\nwhich were ignored by our mypy config but visible for anyone else\n(whoops).  Thanks to Pi Delport for reporting :issue:`1359` so promptly.\n\n.. _v3.64.0:\n\n-------------------\n3.64.0 - 2018-06-26\n-------------------\n\nThis release adds :ref:`an interface <custom-function-execution>`\nwhich can be used to insert a wrapper between the original test function and\n:func:`@given <hypothesis.given>` (:issue:`1257`).  This will be particularly\nuseful for test runner extensions such as :pypi:`pytest-trio`, but is\nnot recommended for direct use by other users of Hypothesis.\n\n.. _v3.63.0:\n\n-------------------\n3.63.0 - 2018-06-26\n-------------------\n\nThis release adds a new mechanism to infer strategies for classes\ndefined using :pypi:`attrs`, based on the type, converter, or\nvalidator of each attribute.  This inference is now built in to\n:func:`~hypothesis.strategies.builds` and :func:`~hypothesis.strategies.from_type`.\n\nOn Python 2, :func:`~hypothesis.strategies.from_type` no longer generates\ninstances of ``int`` when passed ``long``, or vice-versa.\n\n.. _v3.62.0:\n\n-------------------\n3.62.0 - 2018-06-26\n-------------------\n\nThis release adds :PEP:`484` type hints to Hypothesis on a provisional\nbasis, using the comment-based syntax for Python 2 compatibility.\n\nIt *also* adds the ``py.typed`` marker specified in :PEP:`561`.\nAfter you ``pip install hypothesis``, :pypi:`mypy` 0.590 or later\nwill therefore type-check your use of our public interface!\n\n.. _v3.61.0:\n\n-------------------\n3.61.0 - 2018-06-24\n-------------------\n\nThis release deprecates the use of :class:`~hypothesis.settings` as a\ncontext manager, the use of which is somewhat ambiguous.\n\nUsers should define settings with global state or with the\n:func:`@settings(...) <hypothesis.settings>` decorator.\n\n.. _v3.60.1:\n\n-------------------\n3.60.1 - 2018-06-20\n-------------------\n\nFixed a bug in generating an instance of a Django model from a\nstrategy where the primary key is generated as part of the\nstrategy. See :ref:`details here <django-generating-primary-key>`.\n\nThanks to Tim Martin for this contribution.\n\n.. _v3.60.0:\n\n-------------------\n3.60.0 - 2018-06-20\n-------------------\n\nThis release adds the :func:`@initialize <hypothesis.stateful.initialize>`\ndecorator for stateful testing (originally discussed in :issue:`1216`).\nAll :func:`@initialize <hypothesis.stateful.initialize>` rules will be called\nonce each in an arbitrary order before any normal rule is called.\n\n.. _v3.59.3:\n\n-------------------\n3.59.3 - 2018-06-19\n-------------------\n\nThis is a no-op release to take into account some changes to the release\nprocess. It should have no user visible effect.\n\n.. _v3.59.2:\n\n-------------------\n3.59.2 - 2018-06-18\n-------------------\n\nThis adds support for partially sorting examples which cannot be fully sorted.\nFor example, [5, 4, 3, 2, 1, 0] with a constraint that the first element needs\nto be larger than the last becomes [1, 2, 3, 4, 5, 0].\n\nThanks to Luke for contributing.\n\n.. _v3.59.1:\n\n-------------------\n3.59.1 - 2018-06-16\n-------------------\n\nThis patch uses :func:`python:random.getstate` and :func:`python:random.setstate`\nto restore the PRNG state after :func:`@given <hypothesis.given>` runs\ndeterministic tests.  Without restoring state, you might have noticed problems\nsuch as :issue:`1266`.  The fix also applies to stateful testing (:issue:`702`).\n\n.. _v3.59.0:\n\n-------------------\n3.59.0 - 2018-06-14\n-------------------\n\nThis release adds the :func:`~hypothesis.strategies.emails` strategy,\nwhich generates unicode strings representing an email address.\n\nThanks to Sushobhit for moving this to the public API (:issue:`162`).\n\n.. _v3.58.1:\n\n-------------------\n3.58.1 - 2018-06-13\n-------------------\n\nThis improves the shrinker. It can now reorder examples: 3 1 2 becomes 1 2 3.\n\nThanks to Luke for contributing.\n\n.. _v3.58.0:\n\n-------------------\n3.58.0 - 2018-06-13\n-------------------\n\nThis adds a new extra :py:func:`~hypothesis.extra.dateutil.timezones` strategy\nthat generates :pypi:`dateutil timezones <python-dateutil>`.\n\nThanks to Conrad for contributing.\n\n.. _v3.57.0:\n\n-------------------\n3.57.0 - 2018-05-20\n-------------------\n\nUsing an unordered collection with the :func:`~hypothesis.strategies.permutations`\nstrategy has been deprecated because the order in which e.g. a set shrinks is\narbitrary. This may cause different results between runs.\n\n.. _v3.56.10:\n\n--------------------\n3.56.10 - 2018-05-16\n--------------------\n\nThis release makes ``hypothesis.settings.define_setting``\na private method, which has the effect of hiding it from the\ndocumentation.\n\n.. _v3.56.9:\n\n-------------------\n3.56.9 - 2018-05-11\n-------------------\n\nThis is another release with no functionality changes as part of changes to\nHypothesis's new release tagging scheme.\n\n.. _v3.56.8:\n\n-------------------\n3.56.8 - 2018-05-10\n-------------------\n\nThis is a release with no functionality changes that moves Hypothesis over to\na new release tagging scheme.\n\n.. _v3.56.7:\n\n-------------------\n3.56.7 - 2018-05-10\n-------------------\n\nThis release provides a performance improvement for most tests, but in\nparticular users of :func:`~hypothesis.strategies.sampled_from` who don't\nhave numpy installed should see a significant performance improvement.\n\n.. _v3.56.6:\n\n-------------------\n3.56.6 - 2018-05-09\n-------------------\n\nThis patch contains further internal work to support Mypy.\nThere are no user-visible changes... yet.\n\n.. _v3.56.5:\n\n-------------------\n3.56.5 - 2018-04-22\n-------------------\n\nThis patch contains some internal refactoring to run :pypi:`mypy` in CI.\nThere are no user-visible changes.\n\n.. _v3.56.4:\n\n-------------------\n3.56.4 - 2018-04-21\n-------------------\n\nThis release involves some very minor internal clean up and should have no\nuser visible effect at all.\n\n.. _v3.56.3:\n\n-------------------\n3.56.3 - 2018-04-20\n-------------------\n\nThis release fixes a problem introduced in :ref:`3.56.0 <v3.56.0>` where\nsetting the hypothesis home directory (through currently undocumented\nmeans) would no longer result in the default database location living\nin the new home directory.\n\n.. _v3.56.2:\n\n-------------------\n3.56.2 - 2018-04-20\n-------------------\n\nThis release fixes a problem introduced in :ref:`3.56.0 <v3.56.0>` where\nsetting :obj:`~hypothesis.settings.max_examples` to ``1`` would result in tests\nfailing with ``Unsatisfiable``. This problem could also occur in other harder\nto trigger circumstances (e.g. by setting it to a low value, having a hard to\nsatisfy assumption, and disabling health checks).\n\n.. _v3.56.1:\n\n-------------------\n3.56.1 - 2018-04-20\n-------------------\n\nThis release fixes a problem that was introduced in :ref:`3.56.0 <v3.56.0>`:\nUse of the ``HYPOTHESIS_VERBOSITY_LEVEL`` environment variable was, rather\nthan deprecated, actually broken due to being read before various setup\nthe deprecation path needed was done. It now works correctly (and emits a\ndeprecation warning).\n\n.. _v3.56.0:\n\n-------------------\n3.56.0 - 2018-04-17\n-------------------\n\nThis release deprecates several redundant or internally oriented\n:class:`~hypothesis.settings`, working towards an orthogonal set of\nconfiguration options that are widely useful *without* requiring any\nknowledge of our internals (:issue:`535`).\n\n- Deprecated settings that no longer have any effect are no longer\n  shown in the ``__repr__`` unless set to a non-default value.\n- ``hypothesis.settings.perform_health_check`` is deprecated, as it\n  duplicates :obj:`~hypothesis.settings.suppress_health_check`.\n- ``hypothesis.settings.max_iterations`` is deprecated and disabled,\n  because we can usually get better behaviour from an internal heuristic\n  than a user-controlled setting.\n- ``hypothesis.settings.min_satisfying_examples`` is deprecated and\n  disabled, due to overlap with the\n  :obj:`~hypothesis.HealthCheck.filter_too_much` healthcheck\n  and poor interaction with :obj:`~hypothesis.settings.max_examples`.\n- ``HYPOTHESIS_VERBOSITY_LEVEL`` is now deprecated.  Set\n  :obj:`~hypothesis.settings.verbosity` through the profile system instead.\n- Examples tried by ``find()`` are now reported at ``debug``\n  verbosity level (as well as ``verbose`` level).\n\n.. _v3.55.6:\n\n-------------------\n3.55.6 - 2018-04-14\n-------------------\n\nThis release fixes a somewhat obscure condition (:issue:`1230`) under which you\ncould occasionally see a failing test trigger an assertion error inside\nHypothesis instead of failing normally.\n\n.. _v3.55.5:\n\n-------------------\n3.55.5 - 2018-04-14\n-------------------\n\nThis patch fixes one possible cause of :issue:`966`.  When running\nPython 2 with hash randomisation, passing a :obj:`python:bytes` object\nto :func:`python:random.seed` would use ``version=1``, which broke\n:obj:`~hypothesis.settings.derandomize` (because the seed depended on\na randomised hash).  If :obj:`~hypothesis.settings.derandomize` is\n*still* nondeterministic for you, please open an issue.\n\n.. _v3.55.4:\n\n-------------------\n3.55.4 - 2018-04-13\n-------------------\n\nThis patch makes a variety of minor improvements to the documentation,\nand improves a few validation messages for invalid inputs.\n\n.. _v3.55.3:\n\n-------------------\n3.55.3 - 2018-04-12\n-------------------\n\nThis release updates the URL metadata associated with the PyPI package (again).\nIt has no other user visible effects.\n\n.. _v3.55.2:\n\n-------------------\n3.55.2 - 2018-04-11\n-------------------\n\nThis release updates the URL metadata associated with the PyPI package.\nIt has no other user visible effects.\n\n.. _v3.55.1:\n\n-------------------\n3.55.1 - 2018-04-06\n-------------------\n\nThis patch relaxes constraints in our tests on the expected values returned\nby the standard library function :func:`~python:math.hypot` and the internal\nhelper function ``cathetus``, to fix near-exact\ntest failures on some 32-bit systems used by downstream packagers.\n\n.. _v3.55.0:\n\n-------------------\n3.55.0 - 2018-04-05\n-------------------\n\nThis release includes several improvements to the handling of the\n:obj:`~hypothesis.settings.database` setting.\n\n- The ``database_file`` setting was a historical\n  artefact, and you should just use :obj:`~hypothesis.settings.database`\n  directly.\n- The ``HYPOTHESIS_DATABASE_FILE`` environment variable is\n  deprecated, in favor of :meth:`~hypothesis.settings.load_profile` and\n  the :obj:`~hypothesis.settings.database` setting.\n- If you have not configured the example database at all and the default\n  location is not usable (due to e.g. permissions issues), Hypothesis\n  will fall back to an in-memory database.  This is not persisted between\n  sessions, but means that the defaults work on read-only filesystems.\n\n.. _v3.54.0:\n\n-------------------\n3.54.0 - 2018-04-04\n-------------------\n\nThis release improves the :func:`~hypothesis.strategies.complex_numbers`\nstrategy, which now supports ``min_magnitude`` and ``max_magnitude``\narguments, along with ``allow_nan`` and ``allow_infinity`` like for\n:func:`~hypothesis.strategies.floats`.\n\nThanks to J.J. Green for this feature.\n\n.. _v3.53.0:\n\n-------------------\n3.53.0 - 2018-04-01\n-------------------\n\nThis release removes support for Django 1.8, which reached end of life on\n2018-04-01.  You can see Django's release and support schedule\n`on the Django Project website <https://www.djangoproject.com/download/#supported-versions>`_.\n\n.. _v3.52.3:\n\n-------------------\n3.52.3 - 2018-04-01\n-------------------\n\nThis patch fixes the ``min_satisfying_examples`` settings\ndocumentation, by explaining that example shrinking is tracked at the level\nof the underlying bytestream rather than the output value.\n\nThe output from ``find()`` in verbose mode has also been\nadjusted - see the example session for |Verbosity| - to avoid\nduplicating lines when the example repr is constant, even if the underlying\nrepresentation has been shrunken.\n\n.. _v3.52.2:\n\n-------------------\n3.52.2 - 2018-03-30\n-------------------\n\nThis release improves the output of failures with\n:ref:`rule based stateful testing <stateful>` in two ways:\n\n* The output from it is now usually valid Python code.\n* When the same value has two different names because it belongs to two different\n  bundles, it will now display with the name associated with the correct bundle\n  for a rule argument where it is used.\n\n.. _v3.52.1:\n\n-------------------\n3.52.1 - 2018-03-29\n-------------------\n\nThis release improves the behaviour of  :ref:`stateful testing <stateful>`\nin two ways:\n\n* Previously some runs would run no steps (:issue:`376`). This should no longer\n  happen.\n* RuleBasedStateMachine tests which used bundles extensively would often shrink\n  terribly. This should now be significantly improved, though there is likely\n  a lot more room for improvement.\n\nThis release also involves a low level change to how ranges of integers are\nhandles which may result in other improvements to shrink quality in some cases.\n\n.. _v3.52.0:\n\n-------------------\n3.52.0 - 2018-03-24\n-------------------\n\nThis release deprecates use of :func:`@settings(...) <hypothesis.settings>`\nas a decorator, on functions or methods that are not also decorated with\n:func:`@given <hypothesis.given>`.  You can still apply these decorators\nin any order, though you should only do so once each.\n\nApplying :func:`@given <hypothesis.given>` twice was already deprecated, and\napplying :func:`@settings(...) <hypothesis.settings>` twice is deprecated in\nthis release and will become an error in a future version. Neither could ever\nbe used twice to good effect.\n\nUsing :func:`@settings(...) <hypothesis.settings>` as the sole decorator on\na test is completely pointless, so this common usage error will become an\nerror in a future version of Hypothesis.\n\n.. _v3.51.0:\n\n-------------------\n3.51.0 - 2018-03-24\n-------------------\n\nThis release deprecates the ``average_size`` argument to\n:func:`~hypothesis.strategies.lists` and other collection strategies.\nYou should simply delete it wherever it was used in your tests, as it\nno longer has any effect.\n\nIn early versions of Hypothesis, the ``average_size`` argument was treated\nas a hint about the distribution of examples from a strategy.  Subsequent\nimprovements to the conceptual model and the engine for generating and\nshrinking examples mean it is more effective to simply describe what\nconstitutes a valid example, and let our internals handle the distribution.\n\n.. _v3.50.3:\n\n-------------------\n3.50.3 - 2018-03-24\n-------------------\n\nThis patch contains some internal refactoring so that we can run\nwith warnings as errors in CI.\n\n.. _v3.50.2:\n\n-------------------\n3.50.2 - 2018-03-20\n-------------------\n\nThis has no user-visible changes except one slight formatting change to one docstring, to avoid a deprecation warning.\n\n.. _v3.50.1:\n\n-------------------\n3.50.1 - 2018-03-20\n-------------------\n\nThis patch fixes an internal error introduced in :ref:`3.48.0 <v3.48.0>`, where a check\nfor the Django test runner would expose import-time errors in Django\nconfiguration (:issue:`1167`).\n\n.. _v3.50.0:\n\n-------------------\n3.50.0 - 2018-03-19\n-------------------\n\nThis release improves validation of numeric bounds for some strategies.\n\n- :func:`~hypothesis.strategies.integers` and :func:`~hypothesis.strategies.floats`\n  now raise ``InvalidArgument`` if passed a ``min_value`` or ``max_value``\n  which is not an instance of :class:`~python:numbers.Real`, instead of\n  various internal errors.\n- :func:`~hypothesis.strategies.floats` now converts its bounding values to\n  the nearest float above or below the min or max bound respectively, instead\n  of just casting to float.  The old behaviour was incorrect in that you could\n  generate ``float(min_value)``, even when this was less than ``min_value``\n  itself (possible with eg. fractions).\n- When both bounds are provided to :func:`~hypothesis.strategies.floats` but\n  there are no floats in the interval, such as ``[(2**54)+1 .. (2**55)-1]``,\n  InvalidArgument is raised.\n- :func:`~hypothesis.strategies.decimals` gives a more useful error message\n  if passed a string that cannot be converted to :class:`~python:decimal.Decimal`\n  in a context where this error is not trapped.\n\nCode that previously **seemed** to work may be explicitly broken if there\nwere no floats between ``min_value`` and ``max_value`` (only possible with\nnon-float bounds), or if a bound was not a :class:`~python:numbers.Real`\nnumber but still allowed in :obj:`python:math.isnan` (some custom classes\nwith a ``__float__`` method).\n\n.. _v3.49.1:\n\n-------------------\n3.49.1 - 2018-03-15\n-------------------\n\nThis patch fixes our tests for Numpy dtype strategies on big-endian platforms,\nwhere the strategy behaved correctly but the test assumed that the native byte\norder was little-endian.\n\nThere is no user impact unless you are running our test suite on big-endian\nplatforms.  Thanks to Graham Inggs for reporting :issue:`1164`.\n\n.. _v3.49.0:\n\n-------------------\n3.49.0 - 2018-03-12\n-------------------\n\nThis release deprecates passing ``elements=None`` to collection strategies,\nsuch as :func:`~hypothesis.strategies.lists`.\n\nRequiring ``lists(nothing())`` or ``builds(list)`` instead of ``lists()``\nmeans slightly more typing, but also improves the consistency and\ndiscoverability of our API - as well as showing how to compose or\nconstruct strategies in ways that still work in more complex situations.\n\nPassing a nonzero max_size to a collection strategy where the elements\nstrategy contains no values is now deprecated, and will be an error in a\nfuture version.  The equivalent with ``elements=None`` is already an error.\n\n.. _v3.48.1:\n\n-------------------\n3.48.1 - 2018-03-05\n-------------------\n\nThis patch will minimize examples that would come out non-minimal in previous versions. Thanks to Kyle Reeve for this patch.\n\n.. _v3.48.0:\n\n-------------------\n3.48.0 - 2018-03-05\n-------------------\n\nThis release improves some \"unhappy paths\" when using Hypothesis\nwith the standard library :mod:`python:unittest` module:\n\n- Applying :func:`@given <hypothesis.given>` to a non-test method which is\n  overridden from :class:`python:unittest.TestCase`, such as ``setUp``,\n  raises :attr:`a new health check <hypothesis.HealthCheck.not_a_test_method>`.\n  (:issue:`991`)\n- Using :meth:`~python:unittest.TestCase.subTest` within a test decorated\n  with :func:`@given <hypothesis.given>` would leak intermediate results\n  when tests were run under the :mod:`python:unittest` test runner.\n  Individual reporting of failing subtests is now disabled during a test\n  using :func:`@given <hypothesis.given>`.  (:issue:`1071`)\n- :func:`@given <hypothesis.given>` is still not a class decorator, but the\n  error message if you try using it on a class has been improved.\n\nAs a related improvement, using :class:`django:django.test.TestCase` with\n:func:`@given <hypothesis.given>` instead of\n:class:`hypothesis.extra.django.TestCase` raises an explicit error instead\nof running all examples in a single database transaction.\n\n.. _v3.47.0:\n\n-------------------\n3.47.0 - 2018-03-02\n-------------------\n\n:obj:`~hypothesis.settings.register_profile` now accepts keyword arguments\nfor specific settings, and the parent settings object is now optional.\nUsing a ``name`` for a registered profile which is not a string was never\nsuggested, but it is now also deprecated and will eventually be an error.\n\n.. _v3.46.2:\n\n-------------------\n3.46.2 - 2018-03-01\n-------------------\n\nThis release removes an unnecessary branch from the code, and has no user-visible impact.\n\n.. _v3.46.1:\n\n-------------------\n3.46.1 - 2018-03-01\n-------------------\n\nThis changes only the formatting of our docstrings and should have no user-visible effects.\n\n.. _v3.46.0:\n\n-------------------\n3.46.0 - 2018-02-26\n-------------------\n\n:func:`~hypothesis.strategies.characters` has improved docs about\nwhat arguments are valid, and additional validation logic to raise a\nclear error early (instead of e.g. silently ignoring a bad argument).\nCategories may be specified as the Unicode 'general category'\n(eg ``'Nd'``), or as the 'major category' (eg ``['N', 'Lu']``\nis equivalent to ``['Nd', 'Nl', 'No', 'Lu']``).\n\nIn previous versions, general categories were supported and all other\ninput was silently ignored.  Now, major categories are supported in\naddition to general categories (which may change the behaviour of some\nexisting code), and all other input is deprecated.\n\n.. _v3.45.5:\n\n-------------------\n3.45.5 - 2018-02-26\n-------------------\n\nThis patch improves strategy inference in ``hypothesis.extra.django``\nto account for some validators in addition to field type - see\n:issue:`1116` for ongoing work in this space.\n\nSpecifically, if a :class:`~django:django.db.models.CharField` or\n:class:`~django:django.db.models.TextField` has an attached\n:class:`~django:django.core.validators.RegexValidator`, we now use\n:func:`~hypothesis.strategies.from_regex` instead of\n:func:`~hypothesis.strategies.text` as the underlying strategy.\nThis allows us to generate examples of the default\n:class:`~django:django.contrib.auth.models.User` model, closing :issue:`1112`.\n\n.. _v3.45.4:\n\n-------------------\n3.45.4 - 2018-02-25\n-------------------\n\nThis patch improves some internal debugging information, fixes\na typo in a validation error message, and expands the documentation\nfor new contributors.\n\n.. _v3.45.3:\n\n-------------------\n3.45.3 - 2018-02-23\n-------------------\n\nThis patch may improve example shrinking slightly for some strategies.\n\n.. _v3.45.2:\n\n-------------------\n3.45.2 - 2018-02-18\n-------------------\n\nThis release makes our docstring style more consistent, thanks to\n:pypi:`flake8-docstrings`.  There are no user-visible changes.\n\n.. _v3.45.1:\n\n-------------------\n3.45.1 - 2018-02-17\n-------------------\n\nThis fixes an indentation issue in docstrings for\n:func:`~hypothesis.strategies.datetimes`, :func:`~hypothesis.strategies.dates`,\n:func:`~hypothesis.strategies.times`, and\n:func:`~hypothesis.strategies.timedeltas`.\n\n.. _v3.45.0:\n\n-------------------\n3.45.0 - 2018-02-13\n-------------------\n\nThis release fixes :func:`~hypothesis.strategies.builds` so that ``target``\ncan be used as a keyword argument for passing values to the target. The target\nitself can still be specified as a keyword argument, but that behavior is now\ndeprecated. The target should be provided as the first positional argument.\n\n.. _v3.44.26:\n\n--------------------\n3.44.26 - 2018-02-06\n--------------------\n\nThis release fixes some formatting issues in the Hypothesis source code.\nIt should have no externally visible effects.\n\n.. _v3.44.25:\n\n--------------------\n3.44.25 - 2018-02-05\n--------------------\n\nThis release changes the way in which Hypothesis tries to shrink the size of\nexamples. It probably won't have much impact, but might make shrinking faster\nin some cases. It is unlikely but not impossible that it will change the\nresulting examples.\n\n.. _v3.44.24:\n\n--------------------\n3.44.24 - 2018-01-27\n--------------------\n\nThis release fixes dependency information when installing Hypothesis\nfrom a binary \"wheel\" distribution.\n\n- The ``install_requires`` for :pypi:`enum34` is resolved at install\n  time, rather than at build time (with potentially different results).\n- Django has fixed their ``python_requires`` for versions 2.0.0 onward,\n  simplifying Python2-compatible constraints for downstream projects.\n\n.. _v3.44.23:\n\n--------------------\n3.44.23 - 2018-01-24\n--------------------\n\nThis release improves shrinking in a class of pathological examples that you\nare probably never hitting in practice. If you *are* hitting them in practice\nthis should be a significant speed up in shrinking. If you are not, you are\nvery unlikely to notice any difference. You might see a slight slow down and/or\nslightly better falsifying examples.\n\n.. _v3.44.22:\n\n--------------------\n3.44.22 - 2018-01-23\n--------------------\n\nThis release fixes a dependency problem.  It was possible to install\nHypothesis with an old version of :pypi:`attrs`, which would throw a\n``TypeError`` as soon as you tried to import hypothesis.  Specifically, you\nneed attrs 16.0.0 or newer.\n\nHypothesis will now require the correct version of attrs when installing.\n\n.. _v3.44.21:\n\n--------------------\n3.44.21 - 2018-01-22\n--------------------\n\nThis change adds some additional structural information that Hypothesis will\nuse to guide its search.\n\nYou mostly shouldn't see much difference from this. The two most likely effects\nyou would notice are:\n\n1. Hypothesis stores slightly more examples in its database for passing tests.\n2. Hypothesis *may* find new bugs that it was previously missing, but it\n   probably won't (this is a basic implementation of the feature that is\n   intended to support future work. Although it is useful on its own, it's not\n   *very* useful on its own).\n\n.. _v3.44.20:\n\n--------------------\n3.44.20 - 2018-01-21\n--------------------\n\nThis is a small refactoring release that changes how Hypothesis tracks some\ninformation about the boundary of examples in its internal representation.\n\nYou are unlikely to see much difference in behaviour, but memory usage and\nrun time may both go down slightly during normal test execution, and when\nfailing Hypothesis might print its failing example slightly sooner.\n\n.. _v3.44.19:\n\n--------------------\n3.44.19 - 2018-01-21\n--------------------\n\nThis changes how we compute the default ``average_size`` for all collection\nstrategies. Previously setting a ``max_size`` without setting an\n``average_size`` would have the seemingly paradoxical effect of making data\ngeneration *slower*, because it would raise the average size from its default.\nNow setting ``max_size`` will either leave the default unchanged or lower it\nfrom its default.\n\nIf you are currently experiencing this problem, this may make your tests\nsubstantially faster. If you are not, this will likely have no effect on you.\n\n.. _v3.44.18:\n\n--------------------\n3.44.18 - 2018-01-20\n--------------------\n\nThis is a small refactoring release that changes how Hypothesis detects when\nthe structure of data generation depends on earlier values generated (e.g. when\nusing |.flatmap| or :func:`~hypothesis.strategies.composite`).\nIt should not have any observable effect on behaviour.\n\n.. _v3.44.17:\n\n--------------------\n3.44.17 - 2018-01-15\n--------------------\n\nThis release fixes a typo in internal documentation, and has no user-visible impact.\n\n.. _v3.44.16:\n\n--------------------\n3.44.16 - 2018-01-13\n--------------------\n\nThis release improves test case reduction for recursive data structures.\nHypothesis now guarantees that whenever a strategy calls itself recursively\n(usually this will happen because you are using :func:`~hypothesis.strategies.deferred`),\nany recursive call may replace the top level value. e.g. given a tree structure,\nHypothesis will always try replacing it with a subtree.\n\nAdditionally this introduces a new heuristic that may in some circumstances\nsignificantly speed up test case reduction - Hypothesis should be better at\nimmediately replacing elements drawn inside another strategy with their minimal\npossible value.\n\n.. _v3.44.15:\n\n--------------------\n3.44.15 - 2018-01-13\n--------------------\n\n:func:`~hypothesis.strategies.from_type` can now resolve recursive types\nsuch as binary trees (:issue:`1004`).  Detection of non-type arguments has\nalso improved, leading to better error messages in many cases involving\n:pep:`forward references <484#forward-references>`.\n\n.. _v3.44.14:\n\n--------------------\n3.44.14 - 2018-01-08\n--------------------\n\nThis release fixes a bug in the shrinker that prevented the optimisations in\n:ref:`3.44.6 <v3.44.6>` from working in some cases. It would not have worked correctly when\nfiltered examples were nested (e.g. with a set of integers in some range).\n\nThis would not have resulted in any correctness problems, but shrinking may\nhave been slower than it otherwise could be.\n\n.. _v3.44.13:\n\n--------------------\n3.44.13 - 2018-01-08\n--------------------\n\nThis release changes the average bit length of values drawn from\n:func:`~hypothesis.strategies.integers` to be much smaller. Additionally it\nchanges the shrinking order so that now size is considered before sign - e.g.\n-1 will be preferred to +10.\n\nThe new internal format for integers required some changes to the minimizer to\nmake work well, so you may also see some improvements to example quality in\nunrelated areas.\n\n.. _v3.44.12:\n\n--------------------\n3.44.12 - 2018-01-07\n--------------------\n\nThis changes Hypothesis's internal implementation of weighted sampling. This\nwill affect example distribution and quality, but you shouldn't see any other\neffects.\n\n.. _v3.44.11:\n\n--------------------\n3.44.11 - 2018-01-06\n--------------------\n\nThis is a change to some internals around how Hypothesis handles avoiding\ngenerating duplicate examples and seeking out novel regions of the search\nspace.\n\nYou are unlikely to see much difference as a result of it, but it fixes\na bug where an internal assertion could theoretically be triggered and has some\nminor effects on the distribution of examples so could potentially find bugs\nthat have previously been missed.\n\n.. _v3.44.10:\n\n--------------------\n3.44.10 - 2018-01-06\n--------------------\n\nThis patch avoids creating debug statements when debugging is disabled.\nProfiling suggests this is a 5-10% performance improvement (:issue:`1040`).\n\n.. _v3.44.9:\n\n-------------------\n3.44.9 - 2018-01-06\n-------------------\n\nThis patch blacklists null characters (``'\\x00'``) in automatically created\nstrategies for Django :obj:`~django:django.db.models.CharField` and\n:obj:`~django:django.db.models.TextField`, due to a database issue which\n`was recently fixed upstream <https://code.djangoproject.com/ticket/28201>`_\n(Hypothesis :issue:`1045`).\n\n.. _v3.44.8:\n\n-------------------\n3.44.8 - 2018-01-06\n-------------------\n\nThis release makes the Hypothesis shrinker slightly less greedy in order to\navoid local minima - when it gets stuck, it makes a small attempt to search\naround the final example it would previously have returned to find a new\nstarting point to shrink from. This should improve example quality in some\ncases, especially ones where the test data has dependencies among parts of it\nthat make it difficult for Hypothesis to proceed.\n\n.. _v3.44.7:\n\n-------------------\n3.44.7 - 2018-01-04\n-------------------\n\nThis release adds support for `Django 2\n<https://www.djangoproject.com/weblog/2017/dec/02/django-20-released/>`_ in\nthe hypothesis-django extra.\n\nThis release drops support for Django 1.10, as it is no longer supported by\nthe Django team.\n\n.. _v3.44.6:\n\n-------------------\n3.44.6 - 2018-01-02\n-------------------\n\nThis release speeds up test case reduction in many examples by being better at\ndetecting large shrinks it can use to discard redundant parts of its input.\nThis will be particularly noticeable in examples that make use of filtering\nand for some integer ranges.\n\n.. _v3.44.5:\n\n-------------------\n3.44.5 - 2018-01-02\n-------------------\n\nHappy new year!\n\nThis is a no-op release that updates the year range on all of\nthe copyright headers in our source to include 2018.\n\n.. _v3.44.4:\n\n-------------------\n3.44.4 - 2017-12-23\n-------------------\n\nThis release fixes :issue:`1041`, which slowed tests by up to 6%\ndue to broken caching.\n\n.. _v3.44.3:\n\n-------------------\n3.44.3 - 2017-12-21\n-------------------\n\nThis release improves the shrinker in cases where examples drawn earlier can\naffect how much data is drawn later (e.g. when you draw a length parameter in\na composite and then draw that many elements). Examples found in cases like\nthis should now be much closer to minimal.\n\n.. _v3.44.2:\n\n-------------------\n3.44.2 - 2017-12-20\n-------------------\n\nThis is a pure refactoring release which changes how Hypothesis manages its\nset of examples internally. It should have no externally visible effects.\n\n.. _v3.44.1:\n\n-------------------\n3.44.1 - 2017-12-18\n-------------------\n\nThis release fixes :issue:`997`, in which under some circumstances the body of\ntests run under Hypothesis would not show up when run under coverage even\nthough the tests were run and the code they called outside of the test file\nwould show up normally.\n\n.. _v3.44.0:\n\n-------------------\n3.44.0 - 2017-12-17\n-------------------\n\nThis release adds a new feature: The :func:`@reproduce_failure <hypothesis.reproduce_failure>` decorator,\ndesigned to make it easy to use Hypothesis's binary format for examples to\nreproduce a problem locally without having to share your example database\nbetween machines.\n\nThis also changes when seeds are printed:\n\n* They will no longer be printed for\n  normal falsifying examples, as there are now adequate ways of reproducing those\n  for all cases, so it just contributes noise.\n* They will once again be printed when reusing examples from the database, as\n  health check failures should now be more reliable in this scenario so it will\n  almost always work in this case.\n\nThis work was funded by `Smarkets <https://smarkets.com/>`_.\n\n.. _v3.43.1:\n\n-------------------\n3.43.1 - 2017-12-17\n-------------------\n\nThis release fixes a bug with Hypothesis's database management - examples that\nwere found in the course of shrinking were saved in a way that indicated that\nthey had distinct causes, and so they would all be retried on the start of the\nnext test. The intended behaviour, which is now what is implemented, is that\nonly a bounded subset of these examples would be retried.\n\n.. _v3.43.0:\n\n-------------------\n3.43.0 - 2017-12-17\n-------------------\n\n:exc:`~hypothesis.errors.HypothesisDeprecationWarning` now inherits from\n:exc:`python:FutureWarning` instead of :exc:`python:DeprecationWarning`,\nas recommended by :pep:`565` for user-facing warnings (:issue:`618`).\nIf you have not changed the default warnings settings, you will now see\neach distinct :exc:`~hypothesis.errors.HypothesisDeprecationWarning`\ninstead of only the first.\n\n.. _v3.42.2:\n\n-------------------\n3.42.2 - 2017-12-12\n-------------------\n\nThis patch fixes :issue:`1017`, where instances of a list or tuple subtype\nused as an argument to a strategy would be coerced to tuple.\n\n.. _v3.42.1:\n\n-------------------\n3.42.1 - 2017-12-10\n-------------------\n\nThis release has some internal cleanup, which makes reading the code\nmore pleasant and may shrink large examples slightly faster.\n\n.. _v3.42.0:\n\n-------------------\n3.42.0 - 2017-12-09\n-------------------\n\nThis release deprecates ``faker-extra``, which was designed as a transition\nstrategy but does not support example shrinking or coverage-guided discovery.\n\n.. _v3.41.0:\n\n-------------------\n3.41.0 - 2017-12-06\n-------------------\n\n:func:`~hypothesis.strategies.sampled_from` can now sample from\none-dimensional numpy ndarrays. Sampling from multi-dimensional\nndarrays still results in a deprecation warning. Thanks to Charlie\nTanksley for this patch.\n\n.. _v3.40.1:\n\n-------------------\n3.40.1 - 2017-12-04\n-------------------\n\nThis release makes two changes:\n\n* It makes the calculation of some of the metadata that Hypothesis uses for\n  shrinking occur lazily. This should speed up performance of test case\n  generation a bit because it no longer calculates information it doesn't need.\n* It improves the shrinker for certain classes of nested examples. e.g. when\n  shrinking lists of lists, the shrinker is now able to concatenate two\n  adjacent lists together into a single list. As a result of this change,\n  shrinking may get somewhat slower when the minimal example found is large.\n\n.. _v3.40.0:\n\n-------------------\n3.40.0 - 2017-12-02\n-------------------\n\nThis release improves how various ways of seeding Hypothesis interact with the\nexample database:\n\n* Using the example database with :func:`~hypothesis.seed` is now deprecated.\n  You should set ``database=None`` if you are doing that. This will only warn\n  if you actually load examples from the database while using ``@seed``.\n* The :attr:`~hypothesis.settings.derandomize` will behave the same way as\n  ``@seed``.\n* Using ``--hypothesis-seed`` will disable use of the database.\n* If a test used examples from the database, it will not suggest using a seed\n  to reproduce it, because that won't work.\n\nThis work was funded by `Smarkets <https://smarkets.com/>`_.\n\n.. _v3.39.0:\n\n-------------------\n3.39.0 - 2017-12-01\n-------------------\n\nThis release adds a new health check that checks if the smallest \"natural\"\npossible example of your test case is very large - this will tend to cause\nHypothesis to generate bad examples and be quite slow.\n\nThis work was funded by `Smarkets <https://smarkets.com/>`_.\n\n.. _v3.38.9:\n\n-------------------\n3.38.9 - 2017-11-29\n-------------------\n\nThis is a documentation release to improve the documentation of shrinking\nbehaviour for Hypothesis's strategies.\n\n.. _v3.38.8:\n\n-------------------\n3.38.8 - 2017-11-29\n-------------------\n\nThis release improves the performance of\n:func:`~hypothesis.strategies.characters` when using ``exclude_characters``\nand :func:`~hypothesis.strategies.from_regex` when using negative character\nclasses.\n\nThe problems this fixes were found in the course of work funded by\n`Smarkets <https://smarkets.com/>`_.\n\n.. _v3.38.7:\n\n-------------------\n3.38.7 - 2017-11-29\n-------------------\n\nThis is a patch release for :func:`~hypothesis.strategies.from_regex`, which\nhad a bug in handling of the :obj:`python:re.VERBOSE` flag (:issue:`992`).\nFlags are now handled correctly when parsing regex.\n\n.. _v3.38.6:\n\n-------------------\n3.38.6 - 2017-11-28\n-------------------\n\nThis patch changes a few byte-string literals from double to single quotes,\nthanks to an update in :pypi:`unify`.  There are no user-visible changes.\n\n.. _v3.38.5:\n\n-------------------\n3.38.5 - 2017-11-23\n-------------------\n\nThis fixes the repr of strategies using lambda that are defined inside\ndecorators to include the lambda source.\n\nThis would mostly have been visible when using the\n:ref:`statistics <statistics>` functionality - lambdas used for e.g. filtering\nwould have shown up with a ``<unknown>`` as their body. This can still happen,\nbut it should happen less often now.\n\n.. _v3.38.4:\n\n-------------------\n3.38.4 - 2017-11-22\n-------------------\n\nThis release updates the reported :ref:`statistics <statistics>` so that they\nshow approximately what fraction of your test run time is spent in data\ngeneration (as opposed to test execution).\n\nThis work was funded by `Smarkets <https://smarkets.com/>`_.\n\n.. _v3.38.3:\n\n-------------------\n3.38.3 - 2017-11-21\n-------------------\n\nThis is a documentation release, which ensures code examples are up to date\nby running them as doctests in CI (:issue:`711`).\n\n.. _v3.38.2:\n\n-------------------\n3.38.2 - 2017-11-21\n-------------------\n\nThis release changes the behaviour of the :attr:`~hypothesis.settings.deadline`\nsetting when used with :func:`~hypothesis.strategies.data`: Time spent inside\ncalls to ``data.draw`` will no longer be counted towards the deadline time.\n\nAs a side effect of some refactoring required for this work, the way flaky\ntests are handled has changed slightly. You are unlikely to see much difference\nfrom this, but some error messages will have changed.\n\nThis work was funded by `Smarkets <https://smarkets.com/>`_.\n\n.. _v3.38.1:\n\n-------------------\n3.38.1 - 2017-11-21\n-------------------\n\nThis patch has a variety of non-user-visible refactorings, removing various\nminor warts ranging from indirect imports to typos in comments.\n\n.. _v3.38.0:\n\n-------------------\n3.38.0 - 2017-11-18\n-------------------\n\nThis release overhauls the |HealthCheck| system\nin a variety of small ways.\nIt adds no new features, but is nevertheless a minor release because it changes\nwhich tests are likely to fail health checks.\n\nThe most noticeable effect is that some tests that used to fail health checks\nwill now pass, and some that used to pass will fail. These should all be\nimprovements in accuracy. In particular:\n\n* New failures will usually be because they are now taking into account things\n  like use of :func:`~hypothesis.strategies.data` and\n  :func:`~hypothesis.assume` inside the test body.\n* New failures *may* also be because for some classes of example the way data\n  generation performance was measured was artificially faster than real data\n  generation (for most examples that are hitting performance health checks the\n  opposite should be the case).\n* Tests that used to fail health checks and now pass do so because the health\n  check system used to run in a way that was subtly different than the main\n  Hypothesis data generation and lacked some of its support for e.g. large\n  examples.\n\nIf your data generation is especially slow, you may also see your tests get\nsomewhat faster, as there is no longer a separate health check phase. This will\nbe particularly noticeable when rerunning test failures.\n\nThis work was funded by `Smarkets <https://smarkets.com/>`_.\n\n.. _v3.37.0:\n\n-------------------\n3.37.0 - 2017-11-12\n-------------------\n\nThis is a deprecation release for some health check related features.\n\nThe following are now deprecated:\n\n* Passing ``HealthCheck.exception_in_generation`` to\n  :attr:`~hypothesis.settings.suppress_health_check`. This no longer does\n  anything even when passed -  All errors that occur during data generation\n  will now be immediately reraised rather than going through the health check\n  mechanism.\n* Passing ``HealthCheck.random_module`` to\n  :attr:`~hypothesis.settings.suppress_health_check`. This hasn't done anything\n  for a long time, but was never explicitly deprecated. Hypothesis always seeds\n  the random module when running :func:`@given <hypothesis.given>` tests, so this\n  is no longer an error and suppressing it doesn't do anything.\n* Passing non-:class:`~hypothesis.HealthCheck` values in\n  :attr:`~hypothesis.settings.suppress_health_check`. This was previously\n  allowed but never did anything useful.\n\nIn addition, passing a non-iterable value as :attr:`~hypothesis.settings.suppress_health_check`\nwill now raise an error immediately (it would never have worked correctly, but\nit would previously have failed later). Some validation error messages have\nalso been updated.\n\nThis work was funded by `Smarkets <https://smarkets.com/>`_.\n\n.. _v3.36.1:\n\n-------------------\n3.36.1 - 2017-11-10\n-------------------\n\nThis is a yak shaving release, mostly concerned with our own tests.\n\nWhile :func:`~python:inspect.getfullargspec` was documented as deprecated\nin Python 3.5, it never actually emitted a warning.  Our code to silence\nthis (nonexistent) warning has therefore been removed.\n\nWe now run our tests with ``DeprecationWarning`` as an error, and made some\nminor changes to our own tests as a result.  This required similar upstream\nupdates to :pypi:`coverage` and :pypi:`execnet` (a test-time dependency via\n:pypi:`pytest-xdist`).\n\nThere is no user-visible change in Hypothesis itself, but we encourage you\nto consider enabling deprecations as errors in your own tests.\n\n.. _v3.36.0:\n\n-------------------\n3.36.0 - 2017-11-06\n-------------------\n\nThis release adds a setting to the public API, and does some internal cleanup:\n\n- The :attr:`~hypothesis.settings.derandomize` setting is now documented (:issue:`890`)\n- Removed - and disallowed - all 'bare excepts' in Hypothesis (:issue:`953`)\n- Documented the ``strict`` setting as deprecated, and\n  updated the build so our docs always match deprecations in the code.\n\n.. _v3.35.0:\n\n-------------------\n3.35.0 - 2017-11-06\n-------------------\n\nThis minor release supports constraining :func:`~hypothesis.strategies.uuids`\nto generate a particular version of :class:`~python:uuid.UUID` (:issue:`721`).\n\nThanks to Dion Misic for this feature.\n\n.. _v3.34.1:\n\n-------------------\n3.34.1 - 2017-11-02\n-------------------\n\nThis patch updates the documentation to suggest\n:func:`builds(callable) <hypothesis.strategies.builds>` instead of\n:func:`just(callable()) <hypothesis.strategies.just>`.\n\n.. _v3.34.0:\n\n-------------------\n3.34.0 - 2017-11-02\n-------------------\n\nHypothesis now emits deprecation warnings if you apply\n:func:`@given <hypothesis.given>` more than once to a target.\n\nApplying :func:`@given <hypothesis.given>` repeatedly wraps the target multiple\ntimes. Each wrapper will search the space of possible parameters separately.\nThis is equivalent but will be much more inefficient than doing it with a\nsingle call to :func:`@given <hypothesis.given>`.\n\nFor example, instead of\n``@given(booleans()) @given(integers())``, you could write\n``@given(booleans(), integers())``\n\n.. _v3.33.1:\n\n-------------------\n3.33.1 - 2017-11-02\n-------------------\n\nThis is a bugfix release:\n\n- :func:`~hypothesis.strategies.builds` would try to infer a strategy for\n  required positional arguments of the target from type hints, even if they\n  had been given to :func:`~hypothesis.strategies.builds` as positional\n  arguments (:issue:`946`).  Now it only infers missing required arguments.\n- An internal introspection function wrongly reported ``self`` as a required\n  argument for bound methods, which might also have affected\n  :func:`~hypothesis.strategies.builds`.  Now it knows better.\n\n.. _v3.33.0:\n\n-------------------\n3.33.0 - 2017-10-16\n-------------------\n\nThis release supports strategy inference for more Django field types - you can now omit an argument for\nDate, Time, Duration, Slug, IP Address, and UUID fields.  (:issue:`642`)\n\nStrategy generation for fields with grouped choices now selects choices from\neach group, instead of selecting from the group names.\n\n.. _v3.32.2:\n\n-------------------\n3.32.2 - 2017-10-15\n-------------------\n\nThis patch removes the ``mergedb`` tool, introduced in Hypothesis 1.7.1\non an experimental basis.  It has never actually worked, and the new\n:ref:`Hypothesis example database <database>` is designed to make such a\ntool unnecessary.\n\n.. _v3.32.1:\n\n-------------------\n3.32.1 - 2017-10-13\n-------------------\n\nThis patch has two improvements for strategies based on enumerations.\n\n- :func:`~hypothesis.strategies.from_type` now handles enumerations correctly,\n  delegating to :func:`~hypothesis.strategies.sampled_from`.  Previously it\n  noted that ``Enum.__init__`` has no required arguments and therefore delegated\n  to :func:`~hypothesis.strategies.builds`, which would subsequently fail.\n- When sampling from an :class:`python:enum.Flag`, we also generate combinations\n  of members. Eg for ``Flag('Permissions', 'READ, WRITE, EXECUTE')`` we can now\n  generate, ``Permissions.READ``, ``Permissions.READ|WRITE``, and so on.\n\n.. _v3.32.0:\n\n-------------------\n3.32.0 - 2017-10-09\n-------------------\n\nThis changes the default value of\nthe ``use_coverage`` setting to True when\nrunning on pypy (it was already True on CPython).\n\nIt was previously set to False because we expected it to be too slow, but\nrecent benchmarking shows that actually performance of the feature on pypy is\nfairly acceptable - sometimes it's slower than on CPython, sometimes it's\nfaster, but it's generally within a factor of two either way.\n\n.. _v3.31.6:\n\n-------------------\n3.31.6 - 2017-10-08\n-------------------\n\nThis patch improves the quality of strategies inferred from Numpy dtypes:\n\n* Integer dtypes generated examples with the upper half of their (non-sign) bits\n  set to zero.  The inferred strategies can now produce any representable integer.\n* Fixed-width unicode- and byte-string dtypes now cap the internal example\n  length, which should improve example and shrink quality.\n* Numpy arrays can only store fixed-size strings internally, and allow shorter\n  strings by right-padding them with null bytes.  Inferred string strategies\n  no longer generate such values, as they can never be retrieved from an array.\n  This improves shrinking performance by skipping useless values.\n\nThis has already been useful in Hypothesis - we found an overflow bug in our\nPandas support, and as a result :func:`~hypothesis.extra.pandas.indexes` and\n:func:`~hypothesis.extra.pandas.range_indexes` now check that ``min_size``\nand ``max_size`` are at least zero.\n\n.. _v3.31.5:\n\n-------------------\n3.31.5 - 2017-10-08\n-------------------\n\nThis release fixes a performance problem in tests where\nthe ``use_coverage`` setting is True.\n\nTests experience a slow-down proportionate to the amount of code they cover.\nThis is still the case, but the factor is now low enough that it should be\nunnoticeable. Previously it was large and became much larger in :ref:`3.30.4 <v3.30.4>`.\n\n.. _v3.31.4:\n\n-------------------\n3.31.4 - 2017-10-08\n-------------------\n\n:func:`~hypothesis.strategies.from_type` failed with a very confusing error\nif passed a :obj:`~typing.NewType` (:issue:`901`).  These pseudo-types\nare now unwrapped correctly, and strategy inference works as expected.\n\n.. _v3.31.3:\n\n-------------------\n3.31.3 - 2017-10-06\n-------------------\n\nThis release makes some small optimisations to our use of coverage that should\nreduce constant per-example overhead. This is probably only noticeable on\nexamples where the test itself is quite fast. On no-op tests that don't test\nanything you may see up to a fourfold speed increase (which is still\nsignificantly slower than without coverage). On more realistic tests the speed\nup is likely to be less than that.\n\n.. _v3.31.2:\n\n-------------------\n3.31.2 - 2017-09-30\n-------------------\n\nThis release fixes some formatting and small typos/grammar issues in the\ndocumentation, specifically the page docs/settings.rst, and the inline docs\nfor the various settings.\n\n.. _v3.31.1:\n\n-------------------\n3.31.1 - 2017-09-30\n-------------------\n\nThis release improves the handling of deadlines so that they act better with\nthe shrinking process. This fixes :issue:`892`.\n\nThis involves two changes:\n\n1. The deadline is raised during the initial generation and shrinking, and then\n   lowered to the set value for final replay. This restricts our attention to\n   examples which exceed the deadline by a more significant margin, which\n   increases their reliability.\n2. When despite the above a test still becomes flaky because it is\n   significantly faster on rerun than it was on its first run, the error\n   message is now more explicit about the nature of this problem, and includes\n   both the initial test run time and the new test run time.\n\nIn addition, this release also clarifies the documentation of the deadline\nsetting slightly to be more explicit about where it applies.\n\nThis work was funded by `Smarkets <https://smarkets.com/>`_.\n\n.. _v3.31.0:\n\n-------------------\n3.31.0 - 2017-09-29\n-------------------\n\nThis release blocks installation of Hypothesis on Python 3.3, which\n:PEP:`reached its end of life date on 2017-09-29 <398>`.\n\nThis should not be of interest to anyone but downstream maintainers -\nif you are affected, migrate to a secure version of Python as soon as\npossible or at least seek commercial support.\n\n.. _v3.30.4:\n\n-------------------\n3.30.4 - 2017-09-27\n-------------------\n\nThis release makes several changes:\n\n1. It significantly improves Hypothesis's ability to use coverage information\n   to find interesting examples.\n2. It reduces the default :attr:`~hypothesis.settings.max_examples` setting from 200 to 100. This takes\n   advantage of the improved algorithm meaning fewer examples are typically\n   needed to get the same testing and is sufficiently better at covering\n   interesting behaviour, and offsets some of the performance problems of\n   running under coverage.\n3. Hypothesis will always try to start its testing with an example that is near\n   minimized.\n\nThe new algorithm for 1 also makes some changes to Hypothesis's low level data\ngeneration which apply even with coverage turned off. They generally reduce the\ntotal amount of data generated, which should improve test performance somewhat.\nBetween this and 3 you should see a noticeable reduction in test runtime (how\nmuch so depends on your tests and how much example size affects their\nperformance. On our benchmarks, where data generation dominates, we saw up to\na factor of two performance improvement, but it's unlikely to be that large.\n\n.. _v3.30.3:\n\n-------------------\n3.30.3 - 2017-09-25\n-------------------\n\nThis release fixes some formatting and small typos/grammar issues in the\ndocumentation, specifically the page docs/details.rst, and some inline\ndocs linked from there.\n\n.. _v3.30.2:\n\n-------------------\n3.30.2 - 2017-09-24\n-------------------\n\nThis release changes Hypothesis's caching approach for functions in\n``hypothesis.strategies``. Previously it would have cached extremely\naggressively and cache entries would never be evicted. Now it adopts a\nleast-frequently used, least recently used key invalidation policy, and is\nsomewhat more conservative about which strategies it caches.\n\nWorkloads which create strategies based on dynamic values, e.g. by using\n|.flatmap| or :func:`~hypothesis.strategies.composite`,\nwill use significantly less memory.\n\n.. _v3.30.1:\n\n-------------------\n3.30.1 - 2017-09-22\n-------------------\n\nThis release fixes a bug where when running with\nthe ``use_coverage=True`` setting inside an\nexisting running instance of coverage, Hypothesis would frequently put files\nthat the coveragerc excluded in the report for the enclosing coverage.\n\n.. _v3.30.0:\n\n-------------------\n3.30.0 - 2017-09-20\n-------------------\n\nThis release introduces two new features:\n\n* When a test fails, either with a health check failure or a falsifying example,\n  Hypothesis will print out a seed that led to that failure, if the test is not\n  already running with a fixed seed. You can then recreate that failure using either\n  the :func:`@seed <hypothesis.seed>` decorator or (if you are running pytest) with ``--hypothesis-seed``.\n* :pypi:`pytest` users can specify a seed to use for :func:`@given <hypothesis.given>` based tests by passing\n  the ``--hypothesis-seed`` command line argument.\n\nThis work was funded by `Smarkets <https://smarkets.com/>`_.\n\n.. _v3.29.0:\n\n-------------------\n3.29.0 - 2017-09-19\n-------------------\n\nThis release makes Hypothesis coverage aware. Hypothesis now runs all test\nbodies under coverage, and uses this information to guide its testing.\n\nThe ``use_coverage`` setting can be used to disable\nthis behaviour if you want to test code that is sensitive to coverage being\nenabled (either because of performance or interaction with the trace function).\n\nThe main benefits of this feature are:\n\n* Hypothesis now observes when examples it discovers cover particular lines\n  or branches and stores them in the database for later.\n* Hypothesis will make some use of this information to guide its exploration of\n  the search space and improve the examples it finds (this is currently used\n  only very lightly and will likely improve significantly in future releases).\n\nThis also has the following side-effects:\n\n* Hypothesis now has an install time dependency on the :pypi:`coverage` package.\n* Tests that are already running Hypothesis under coverage will likely get\n  faster.\n* Tests that are not running under coverage now run their test bodies under\n  coverage by default.\n\n\nThis feature is only partially supported under pypy. It is significantly slower\nthan on CPython and is turned off by default as a result, but it should still\nwork correctly if you want to use it.\n\n.. _v3.28.3:\n\n-------------------\n3.28.3 - 2017-09-18\n-------------------\n\nThis release is an internal change that affects how Hypothesis handles\ncalculating certain properties of strategies.\n\nThe primary effect of this is that it fixes a bug where use of\n:func:`~hypothesis.strategies.deferred` could sometimes trigger an internal assertion\nerror. However the fix for this bug involved some moderately deep changes to\nhow Hypothesis handles certain constructs so you may notice some additional\nknock-on effects.\n\nIn particular the way Hypothesis handles drawing data from strategies that\ncannot generate any values has changed to bail out sooner than it previously\ndid. This may speed up certain tests, but it is unlikely to make much of a\ndifference in practice for tests that were not already failing with\nUnsatisfiable.\n\n.. _v3.28.2:\n\n-------------------\n3.28.2 - 2017-09-18\n-------------------\n\nThis is a patch release that fixes a bug in the :mod:`hypothesis.extra.pandas`\ndocumentation where it incorrectly referred to :func:`~hypothesis.extra.pandas.column`\ninstead of :func:`~hypothesis.extra.pandas.columns`.\n\n.. _v3.28.1:\n\n-------------------\n3.28.1 - 2017-09-16\n-------------------\n\nThis is a refactoring release. It moves a number of internal uses\nof :func:`~python:collections.namedtuple` over to using attrs based classes, and removes a couple\nof internal namedtuple classes that were no longer in use.\n\nIt should have no user visible impact.\n\n.. _v3.28.0:\n\n-------------------\n3.28.0 - 2017-09-15\n-------------------\n\nThis release adds support for testing :pypi:`pandas` via the :ref:`hypothesis.extra.pandas <hypothesis-pandas>`\nmodule.\n\nIt also adds a dependency on :pypi:`attrs`.\n\nThis work was funded by `Stripe <https://stripe.com/>`_.\n\n.. _v3.27.1:\n\n-------------------\n3.27.1 - 2017-09-14\n-------------------\n\nThis release fixes some formatting and broken cross-references in the\ndocumentation, which includes editing docstrings - and thus a patch release.\n\n.. _v3.27.0:\n\n-------------------\n3.27.0 - 2017-09-13\n-------------------\n\nThis release introduces a :attr:`~hypothesis.settings.deadline`\nsetting to Hypothesis.\n\nWhen set this turns slow tests into errors. By default it is unset but will\nwarn if you exceed 200ms, which will become the default value in a future\nrelease.\n\nThis work was funded by `Smarkets <https://smarkets.com/>`_.\n\n.. _v3.26.0:\n\n-------------------\n3.26.0 - 2017-09-12\n-------------------\n\nHypothesis now emits deprecation warnings if you are using the legacy\nSQLite example database format, or the tool for merging them. These were\nalready documented as deprecated, so this doesn't change their deprecation\nstatus, only that we warn about it.\n\n.. _v3.25.1:\n\n-------------------\n3.25.1 - 2017-09-12\n-------------------\n\nThis release fixes a bug with generating :doc:`numpy datetime and timedelta types <numpy:reference/arrays.datetime>`:\nWhen inferring the strategy from the dtype, datetime and timedelta dtypes with\nsub-second precision would always produce examples with one second resolution.\nInferring a strategy from a time dtype will now always produce example with the\nsame precision.\n\n.. _v3.25.0:\n\n-------------------\n3.25.0 - 2017-09-12\n-------------------\n\nThis release changes how Hypothesis shrinks and replays examples to take into\naccount that it can encounter new bugs while shrinking the bug it originally\nfound. Previously it would end up replacing the originally found bug with the\nnew bug and show you only that one. Now it is (often) able to recognise when\ntwo bugs are distinct and when it finds more than one will show both.\n\n.. _v3.24.2:\n\n-------------------\n3.24.2 - 2017-09-11\n-------------------\n\nThis release removes the (purely internal and no longer useful)\n``strategy_test_suite`` function and the corresponding strategytests module.\n\n.. _v3.24.1:\n\n-------------------\n3.24.1 - 2017-09-06\n-------------------\n\nThis release improves the reduction of examples involving floating point\nnumbers to produce more human readable examples.\n\nIt also has some general purpose changes to the way the minimizer works\ninternally, which may see some improvement in quality and slow down of test\ncase reduction in cases that have nothing to do with floating point numbers.\n\n.. _v3.24.0:\n\n-------------------\n3.24.0 - 2017-09-05\n-------------------\n\nHypothesis now emits deprecation warnings if you use ``some_strategy.example()`` inside a\ntest function or strategy definition (this was never intended to be supported,\nbut is sufficiently widespread that it warrants a deprecation path).\n\n.. _v3.23.3:\n\n-------------------\n3.23.3 - 2017-09-05\n-------------------\n\nThis is a bugfix release for :func:`~hypothesis.strategies.decimals`\nwith the ``places`` argument.\n\n- No longer fails health checks (:issue:`725`, due to internal filtering)\n- Specifying a ``min_value`` and ``max_value`` without any decimals with\n  ``places`` places between them gives a more useful error message.\n- Works for any valid arguments, regardless of the decimal precision context.\n\n.. _v3.23.2:\n\n-------------------\n3.23.2 - 2017-09-01\n-------------------\n\nThis is a small refactoring release that removes a now-unused parameter to an\ninternal API. It shouldn't have any user visible effect.\n\n.. _v3.23.1:\n\n-------------------\n3.23.1 - 2017-09-01\n-------------------\n\nHypothesis no longer propagates the dynamic scope of settings into strategy\ndefinitions.\n\nThis release is a small change to something that was never part of the public\nAPI and you will almost certainly not notice any effect unless you're doing\nsomething surprising, but for example the following code will now give a\ndifferent answer in some circumstances:\n\n.. code-block:: python\n\n    import hypothesis.strategies as st\n    from hypothesis import settings\n\n    CURRENT_SETTINGS = st.builds(lambda: settings.default)\n\n(We don't actually encourage you writing code like this)\n\nPreviously this would have generated the settings that were in effect at the\npoint of definition of ``CURRENT_SETTINGS``. Now it will generate the settings\nthat are used for the current test.\n\nIt is very unlikely to be significant enough to be visible, but you may also\nnotice a small performance improvement.\n\n.. _v3.23.0:\n\n-------------------\n3.23.0 - 2017-08-31\n-------------------\n\nThis release adds a ``unique`` argument to :func:`~hypothesis.extra.numpy.arrays`\nwhich behaves the same ways as the corresponding one for\n:func:`~hypothesis.strategies.lists`, requiring all of the elements in the\ngenerated array to be distinct.\n\n.. _v3.22.2:\n\n-------------------\n3.22.2 - 2017-08-29\n-------------------\n\nThis release fixes an issue where Hypothesis would raise a ``TypeError`` when\nusing the datetime-related strategies if running with ``PYTHONOPTIMIZE=2``.\nThis bug was introduced in :ref:`3.20.0 <v3.20.0>`.  (See :issue:`822`)\n\n.. _v3.22.1:\n\n-------------------\n3.22.1 - 2017-08-28\n-------------------\n\nHypothesis now transparently handles problems with an internal unicode cache,\nincluding file truncation or read-only filesystems (:issue:`767`).\nThanks to Sam Hames for the patch.\n\n.. _v3.22.0:\n\n-------------------\n3.22.0 - 2017-08-26\n-------------------\n\nThis release provides what should be a substantial performance improvement to\nnumpy arrays generated using :ref:`provided numpy support <hypothesis-numpy>`,\nand adds a new ``fill_value`` argument to :func:`~hypothesis.extra.numpy.arrays`\nto control this behaviour.\n\nThis work was funded by `Stripe <https://stripe.com/>`_.\n\n.. _v3.21.3:\n\n-------------------\n3.21.3 - 2017-08-26\n-------------------\n\nThis release fixes some extremely specific circumstances that probably have\nnever occurred in the wild where users of\n:func:`~hypothesis.strategies.deferred` might have seen a :class:`python:RuntimeError` from\ntoo much recursion, usually in cases where no valid example could have been\ngenerated anyway.\n\n.. _v3.21.2:\n\n-------------------\n3.21.2 - 2017-08-25\n-------------------\n\nThis release fixes some minor bugs in argument validation:\n\n    * :ref:`hypothesis.extra.numpy <hypothesis-numpy>` dtype strategies would raise an internal error\n      instead of an InvalidArgument exception when passed an invalid\n      endianness specification.\n    * :func:`~hypothesis.strategies.fractions` would raise an internal error instead of an InvalidArgument\n      if passed ``float(\"nan\")`` as one of its bounds.\n    * The error message for passing ``float(\"nan\")`` as a bound to various\n      strategies has been improved.\n    * Various bound arguments will now raise InvalidArgument in cases where\n      they would previously have raised an internal TypeError or\n      ValueError from the relevant conversion function.\n    * ``streaming()`` would not have emitted a\n      deprecation warning when called with an invalid argument.\n\n.. _v3.21.1:\n\n-------------------\n3.21.1 - 2017-08-24\n-------------------\n\nThis release fixes a bug where test failures that were the result of\nan :obj:`@example <hypothesis.example>` would print an extra stack trace before re-raising the\nexception.\n\n.. _v3.21.0:\n\n-------------------\n3.21.0 - 2017-08-23\n-------------------\n\nThis release deprecates Hypothesis's strict mode, which turned Hypothesis's\ndeprecation warnings into errors. Similar functionality can be achieved\nby using :func:`simplefilter('error', HypothesisDeprecationWarning) <python:warnings.simplefilter>`.\n\n.. _v3.20.0:\n\n-------------------\n3.20.0 - 2017-08-22\n-------------------\n\nThis release renames the relevant arguments on the\n:func:`~hypothesis.strategies.datetimes`, :func:`~hypothesis.strategies.dates`,\n:func:`~hypothesis.strategies.times`, and :func:`~hypothesis.strategies.timedeltas`\nstrategies to ``min_value`` and ``max_value``, to make them consistent with the\nother strategies in the module.\n\nThe old argument names are still supported but will emit a deprecation warning\nwhen used explicitly as keyword arguments. Arguments passed positionally will\ngo to the new argument names and are not deprecated.\n\n.. _v3.19.3:\n\n-------------------\n3.19.3 - 2017-08-22\n-------------------\n\nThis release provides a major overhaul to the internals of how Hypothesis\nhandles shrinking.\n\nThis should mostly be visible in terms of getting better examples for tests\nwhich make heavy use of :func:`~hypothesis.strategies.composite`,\n:func:`~hypothesis.strategies.data` or |.flatmap| where the data\ndrawn depends a lot on previous choices, especially where size parameters are\naffected. Previously Hypothesis would have struggled to reliably produce\ngood examples here. Now it should do much better. Performance should also be\nbetter for examples with a non-zero ``min_size``.\n\nYou may see slight changes to example generation (e.g. improved example\ndiversity) as a result of related changes to internals, but they are unlikely\nto be significant enough to notice.\n\n.. _v3.19.2:\n\n-------------------\n3.19.2 - 2017-08-21\n-------------------\n\nThis release fixes two bugs in :mod:`hypothesis.extra.numpy`:\n\n* :func:`~hypothesis.extra.numpy.unicode_string_dtypes` didn't work at all due\n  to an incorrect dtype specifier. Now it does.\n* Various impossible conditions would have been accepted but would error when\n  they fail to produced any example. Now they raise an explicit InvalidArgument\n  error.\n\n.. _v3.19.1:\n\n-------------------\n3.19.1 - 2017-08-21\n-------------------\n\nThis is a bugfix release for :issue:`739`, where bounds for\n:func:`~hypothesis.strategies.fractions` or floating-point\n:func:`~hypothesis.strategies.decimals` were not properly converted to\nintegers before passing them to the integers strategy.\nThis excluded some values that should have been possible, and could\ntrigger internal errors if the bounds lay between adjacent integers.\n\nYou can now bound :func:`~hypothesis.strategies.fractions` with two\narbitrarily close fractions.\n\nIt is now an explicit error to supply a min_value, max_value, and\nmax_denominator to :func:`~hypothesis.strategies.fractions` where the value\nbounds do not include a fraction with denominator at most max_denominator.\n\n.. _v3.19.0:\n\n-------------------\n3.19.0 - 2017-08-20\n-------------------\n\nThis release adds the :func:`~hypothesis.strategies.from_regex` strategy,\nwhich generates strings that contain a match of a regular expression.\n\nThanks to Maxim Kulkin for creating the\n`hypothesis-regex <https://github.com/maximkulkin/hypothesis-regex>`_\npackage and then helping to upstream it! (:issue:`662`)\n\n.. _v3.18.5:\n\n-------------------\n3.18.5 - 2017-08-18\n-------------------\n\nThis is a bugfix release for :func:`~hypothesis.strategies.integers`.\nPreviously the strategy would hit an internal assertion if passed non-integer\nbounds for ``min_value`` and ``max_value`` that had no integers between them.\nThe strategy now raises InvalidArgument instead.\n\n.. _v3.18.4:\n\n-------------------\n3.18.4 - 2017-08-18\n-------------------\n\nRelease to fix a bug where mocks can be used as test runners under certain\nconditions. Specifically, if a mock is injected into a test via pytest\nfixtures or patch decorators, and that mock is the first argument in the\nlist, hypothesis will think it represents self and turns the mock\ninto a test runner.  If this happens, the affected test always passes\nbecause the mock is executed instead of the test body. Sometimes, it\nwill also fail health checks.\n\nFixes :issue:`491` and a section of :issue:`198`.\nThanks to Ben Peterson for this bug fix.\n\n.. _v3.18.3:\n\n-------------------\n3.18.3 - 2017-08-17\n-------------------\n\nThis release should improve the performance of some tests which\nexperienced a slow down as a result of the :ref:`3.13.0 <v3.13.0>` release.\n\nTests most likely to benefit from this are ones that make extensive\nuse of ``min_size`` parameters, but others may see some improvement\nas well.\n\n.. _v3.18.2:\n\n-------------------\n3.18.2 - 2017-08-16\n-------------------\n\nThis release fixes a bug introduced in :ref:`3.18.0 <v3.18.0>`. If the arguments\n``include_characters`` and ``exclude_characters`` to\n:func:`~hypothesis.strategies.characters` contained overlapping elements, then an\n``InvalidArgument`` exception would be raised.\n\nThanks to Zac Hatfield-Dodds for reporting and fixing this.\n\n.. _v3.18.1:\n\n-------------------\n3.18.1 - 2017-08-14\n-------------------\n\nThis is a bug fix release to fix :issue:`780`, where\n:func:`~hypothesis.strategies.sets` and similar would trigger health check\nerrors if their element strategy could only produce one element (e.g.\nif it was :func:`~hypothesis.strategies.just`).\n\n.. _v3.18.0:\n\n-------------------\n3.18.0 - 2017-08-13\n-------------------\n\nThis is a feature release:\n\n* :func:`~hypothesis.strategies.characters` now accepts\n  ``include_characters``, particular characters which will be added to those\n  it produces. (:issue:`668`)\n* A bug fix for the internal function ``_union_interval_lists()``, and a rename\n  to ``_union_intervals()``. It now correctly handles all cases where intervals\n  overlap, and it always returns the result as a tuple for tuples.\n\nThanks to Alex Willmer for these.\n\n.. _v3.17.0:\n\n-------------------\n3.17.0 - 2017-08-07\n-------------------\n\nThis release documents the previously undocumented phases feature in |Phase|,\nmaking it part of the public API. It also updates how the example\ndatabase is used. Principally:\n\n* The :obj:`~hypothesis.Phase.reuse` phase will now correctly control whether examples\n  from the database are run (it previously did exactly the wrong thing and\n  controlled whether examples would be *saved*).\n* Hypothesis will no longer try to rerun *all* previously failing examples.\n  Instead it will replay the smallest previously failing example and a\n  selection of other examples that are likely to trigger any other bugs that\n  will found. This prevents a previous failure from dominating your tests\n  unnecessarily.\n* As a result of the previous change, Hypothesis will be slower about clearing\n  out old examples from the database that are no longer failing (because it can\n  only clear out ones that it actually runs).\n\n.. _v3.16.1:\n\n-------------------\n3.16.1 - 2017-08-07\n-------------------\n\nThis release makes an implementation change to how Hypothesis handles certain\ninternal constructs.\n\nThe main effect you should see is improvement to the behaviour and performance\nof collection types, especially ones with a ``min_size`` parameter. Many cases\nthat would previously fail due to being unable to generate enough valid\nexamples will now succeed, and other cases should run slightly faster.\n\n.. _v3.16.0:\n\n-------------------\n3.16.0 - 2017-08-04\n-------------------\n\nThis release introduces a deprecation of the timeout feature. This results in\nthe following changes:\n\n* Creating a settings object with an explicit timeout will emit a deprecation\n  warning.\n* If your test stops because it hits the timeout (and has not found a bug) then\n  it will emit a deprecation warning.\n* There is a new value ``unlimited`` which you can import from hypothesis.\n  ``settings(timeout=unlimited)`` will *not* cause a deprecation warning.\n* There is a new health check, ``hung_test``, which will trigger after a test\n  has been running for five minutes if it is not suppressed.\n\n.. _v3.15.0:\n\n-------------------\n3.15.0 - 2017-08-04\n-------------------\n\nThis release deprecates two strategies, ``choices()`` and ``streaming()``.\n\nBoth of these are somewhat confusing to use and are entirely redundant since the\nintroduction of the :func:`~hypothesis.strategies.data` strategy for interactive\ndrawing in tests, and their use should be replaced with direct use of\n:func:`~hypothesis.strategies.data` instead.\n\n.. _v3.14.2:\n\n-------------------\n3.14.2 - 2017-08-03\n-------------------\n\nThis fixes a bug where Hypothesis would not work correctly on Python 2.7 if you\nhad the :mod:`python:typing` module :pypi:`backport <typing>` installed.\n\n.. _v3.14.1:\n\n-------------------\n3.14.1 - 2017-08-02\n-------------------\n\nThis raises the maximum depth at which Hypothesis starts cutting off data\ngeneration to a more reasonable value which it is harder to hit by accident.\n\nThis resolves (:issue:`751`), in which some examples which previously worked\nwould start timing out, but it will also likely improve the data generation\nquality for complex data types.\n\n.. _v3.14.0:\n\n-------------------\n3.14.0 - 2017-07-23\n-------------------\n\nHypothesis now understands inline type annotations (:issue:`293`):\n\n- If the target of :func:`~hypothesis.strategies.builds` has type annotations,\n  a default strategy for missing required arguments is selected based on the\n  type.  Type-based strategy selection will only override a default if you\n  pass :const:`hypothesis.infer` as a keyword argument.\n\n- If :func:`@given <hypothesis.given>` wraps a function with type annotations,\n  you can pass :const:`~hypothesis.infer` as a keyword argument and the\n  appropriate strategy will be substituted.\n\n- You can check what strategy will be inferred for a type with the new\n  :func:`~hypothesis.strategies.from_type` function.\n\n- :func:`~hypothesis.strategies.register_type_strategy` teaches Hypothesis\n  which strategy to infer for custom or unknown types.  You can provide a\n  strategy, or for more complex cases a function which takes the type and\n  returns a strategy.\n\n.. _v3.13.1:\n\n-------------------\n3.13.1 - 2017-07-20\n-------------------\n\nThis is a bug fix release for :issue:`514` - Hypothesis would continue running\nexamples after a :class:`~python:unittest.SkipTest` exception was raised,\nincluding printing a falsifying example.  Skip exceptions from the standard\n:mod:`python:unittest` module, and ``pytest``, ``nose``, or ``unittest2``\nmodules now abort the test immediately without printing output.\n\n.. _v3.13.0:\n\n-------------------\n3.13.0 - 2017-07-16\n-------------------\n\nThis release has two major aspects to it: The first is the introduction of\n:func:`~hypothesis.strategies.deferred`, which allows more natural definition\nof recursive (including mutually recursive) strategies.\n\nThe second is a number of engine changes designed to support this sort of\nstrategy better. These should have a knock-on effect of also improving the\nperformance of any existing strategies that currently generate a lot of data\nor involve heavy nesting by reducing their typical example size.\n\n.. _v3.12.0:\n\n-------------------\n3.12.0 - 2017-07-07\n-------------------\n\nThis release makes some major internal changes to how Hypothesis represents\ndata internally, as a prelude to some major engine changes that should improve\ndata quality. There are no API changes, but it's a significant enough internal\nchange that a minor version bump seemed warranted.\n\nUser facing impact should be fairly mild, but includes:\n\n* All existing examples in the database will probably be invalidated. Hypothesis\n  handles this automatically, so you don't need to do anything, but if you see\n  all your examples disappear that's why.\n* Almost all data distributions have changed significantly. Possibly for the better,\n  possibly for the worse. This may result in new bugs being found, but it may\n  also result in Hypothesis being unable to find bugs it previously did.\n* Data generation may be somewhat faster if your existing bottleneck was in\n  draw_bytes (which is often the case for large examples).\n* Shrinking will probably be slower, possibly significantly.\n\nIf you notice any effects you consider to be a significant regression, please\nopen an issue about them.\n\n.. _v3.11.6:\n\n-------------------\n3.11.6 - 2017-06-19\n-------------------\n\nThis release involves no functionality changes, but is the first to ship wheels\nas well as an sdist.\n\n.. _v3.11.5:\n\n-------------------\n3.11.5 - 2017-06-18\n-------------------\n\nThis release provides a performance improvement to shrinking. For cases where\nthere is some non-trivial \"boundary\" value (e.g. the bug happens for all values\ngreater than some other value), shrinking should now be substantially faster.\nOther types of bug will likely see improvements too.\n\nThis may also result in some changes to the quality of the final examples - it\nmay sometimes be better, but is more likely to get slightly worse in some edge\ncases. If you see any examples where this happens in practice, please report\nthem.\n\n.. _v3.11.4:\n\n-------------------\n3.11.4 - 2017-06-17\n-------------------\n\nThis is a bugfix release: Hypothesis now prints explicit examples when\nrunning in verbose mode.  (:issue:`313`)\n\n.. _v3.11.3:\n\n-------------------\n3.11.3 - 2017-06-11\n-------------------\n\nThis is a bugfix release: Hypothesis no longer emits a warning if you try to\nuse :func:`~hypothesis.strategies.sampled_from` with\n:class:`python:collections.OrderedDict`.  (:issue:`688`)\n\n.. _v3.11.2:\n\n-------------------\n3.11.2 - 2017-06-10\n-------------------\n\nThis is a documentation release.  Several outdated snippets have been updated\nor removed, and many cross-references are now hyperlinks.\n\n.. _v3.11.1:\n\n-------------------\n3.11.1 - 2017-05-28\n-------------------\n\nThis is a minor ergonomics release.  Tracebacks shown by pytest no longer\ninclude Hypothesis internals for test functions decorated with :func:`@given <hypothesis.given>`.\n\n.. _v3.11.0:\n\n-------------------\n3.11.0 - 2017-05-23\n-------------------\n\nThis is a feature release, adding datetime-related strategies to the core strategies.\n\n:func:`~hypothesis.extra.pytz.timezones` allows you to sample pytz timezones from\nthe Olsen database.  Use directly in a recipe for tz-aware datetimes, or\ncompose with :func:`~hypothesis.strategies.none` to allow a mix of aware and naive output.\n\nThe new :func:`~hypothesis.strategies.dates`, :func:`~hypothesis.strategies.times`,\n:func:`~hypothesis.strategies.datetimes`, and :func:`~hypothesis.strategies.timedeltas`\nstrategies are all constrained by objects of their type.\nThis means that you can generate dates bounded by a single day\n(i.e. a single date), or datetimes constrained to the microsecond.\n\n:func:`~hypothesis.strategies.times` and :func:`~hypothesis.strategies.datetimes`\ntake an optional ``timezones=`` argument, which\ndefaults to :func:`~hypothesis.strategies.none` for naive times.  You can use our extra strategy\nbased on pytz, or roll your own timezones strategy with dateutil or even\nthe standard library.\n\nThe old ``dates``, ``times``, and ``datetimes`` strategies in\n``hypothesis.extra.datetimes`` are deprecated in favor of the new\ncore strategies, which are more flexible and have no dependencies.\n\n.. _v3.10.0:\n\n-------------------\n3.10.0 - 2017-05-22\n-------------------\n\nHypothesis now uses :func:`python:inspect.getfullargspec` internally.\nOn Python 2, there are no visible changes.\n\nOn Python 3 :func:`@given <hypothesis.given>` and :func:`@composite <hypothesis.strategies.composite>`\nnow preserve :pep:`3107` annotations on the\ndecorated function.  Keyword-only arguments are now either handled correctly\n(e.g. :func:`@composite <hypothesis.strategies.composite>`), or caught in validation instead of silently discarded\nor raising an unrelated error later (e.g. :func:`@given <hypothesis.given>`).\n\n.. _v3.9.1:\n\n------------------\n3.9.1 - 2017-05-22\n------------------\n\nThis is a bugfix release: the default field mapping for a DateTimeField in the\nDjango extra now respects the ``USE_TZ`` setting when choosing a strategy.\n\n.. _v3.9.0:\n\n------------------\n3.9.0 - 2017-05-19\n------------------\n\nThis is feature release, expanding the capabilities of the\n:func:`~hypothesis.strategies.decimals` strategy.\n\n* The new (optional) ``places`` argument allows you to generate decimals with\n  a certain number of places (e.g. cents, thousandths, satoshis).\n* If allow_infinity is None, setting min_bound no longer excludes positive\n  infinity and setting max_value no longer excludes negative infinity.\n* All of ``NaN``, ``-Nan``, ``sNaN``, and ``-sNaN`` may now be drawn if\n  allow_nan is True, or if allow_nan is None and min_value or max_value is None.\n* min_value and max_value may be given as decimal strings, e.g. ``\"1.234\"``.\n\n\n.. _v3.8.5:\n\n------------------\n3.8.5 - 2017-05-16\n------------------\n\nHypothesis now imports :mod:`python:sqlite3` when a SQLite database is used, rather\nthan at module load, improving compatibility with Python implementations\ncompiled without SQLite support (such as BSD or Jython).\n\n.. _v3.8.4:\n\n------------------\n3.8.4 - 2017-05-16\n------------------\n\nThis is a compatibility bugfix release.  :func:`~hypothesis.strategies.sampled_from`\nno longer raises a deprecation warning when sampling from an\n:class:`python:enum.Enum`, as all enums have a reliable iteration order.\n\n.. _v3.8.3:\n\n------------------\n3.8.3 - 2017-05-09\n------------------\n\nThis release removes a version check for older versions of :pypi:`pytest` when using\nthe Hypothesis pytest plugin. The pytest plugin will now run unconditionally\non all versions of pytest. This breaks compatibility with any version of pytest\nprior to 2.7.0 (which is more than two years old).\n\nThe primary reason for this change is that the version check was a frequent\nsource of breakage when pytest change their versioning scheme. If you are not\nworking on pytest itself and are not running a very old version of it, this\nrelease probably doesn't affect you.\n\n.. _v3.8.2:\n\n------------------\n3.8.2 - 2017-04-26\n------------------\n\nThis is a code reorganisation release that moves some internal test helpers\nout of the main source tree so as to not have changes to them trigger releases\nin future.\n\n.. _v3.8.1:\n\n------------------\n3.8.1 - 2017-04-26\n------------------\n\nThis is a documentation release.  Almost all code examples are now doctests\nchecked in CI, eliminating stale examples.\n\n.. _v3.8.0:\n\n------------------\n3.8.0 - 2017-04-23\n------------------\n\nThis is a feature release, adding the :func:`~hypothesis.strategies.iterables` strategy, equivalent\nto ``lists(...).map(iter)`` but with a much more useful repr.  You can use\nthis strategy to check that code doesn't accidentally depend on sequence\nproperties such as indexing support or repeated iteration.\n\n.. _v3.7.4:\n\n------------------\n3.7.4 - 2017-04-22\n------------------\n\nThis patch fixes a bug in :ref:`3.7.3 <v3.7.3>`, where using\n:obj:`@example <hypothesis.example>` and a pytest fixture in the same test\ncould cause the test to fail to fill the arguments, and throw a TypeError.\n\n.. _v3.7.3:\n\n------------------\n3.7.3 - 2017-04-21\n------------------\n\nThis release should include no user visible changes and is purely a refactoring\nrelease. This modularises the behaviour of the core :func:`~hypothesis.given` function, breaking\nit up into smaller and more accessible parts, but its actual behaviour should\nremain unchanged.\n\n.. _v3.7.2:\n\n------------------\n3.7.2 - 2017-04-21\n------------------\n\nThis reverts an undocumented change in :ref:`3.7.1 <v3.7.1>` which broke installation on\ndebian stable: The specifier for the hypothesis[django] extra\\_requires had\nintroduced a wild card, which was not supported on the default version of pip.\n\n.. _v3.7.1:\n\n------------------\n3.7.1 - 2017-04-21\n------------------\n\nThis is a bug fix and internal improvements release.\n\n* In particular Hypothesis now tracks a tree of where it has already explored.\n  This allows it to avoid some classes of duplicate examples, and significantly\n  improves the performance of shrinking failing examples by allowing it to\n  skip some shrinks that it can determine can't possibly work.\n* Hypothesis will no longer seed the global random arbitrarily unless you have\n  asked it to using :py:meth:`~hypothesis.strategies.random_module`\n* Shrinking would previously have not worked correctly in some special cases\n  on Python 2, and would have resulted in suboptimal examples.\n\n.. _v3.7.0:\n\n------------------\n3.7.0 - 2017-03-20\n------------------\n\nThis is a feature release.\n\nNew features:\n\n* Rule based stateful testing now has an :func:`@invariant <hypothesis.stateful.invariant>` decorator that specifies\n  methods that are run after init and after every step, allowing you to\n  encode properties that should be true at all times. Thanks to Tom Prince for\n  this feature.\n* The :func:`~hypothesis.strategies.decimals` strategy now supports ``allow_nan`` and ``allow_infinity`` flags.\n* There are :ref:`significantly more strategies available for numpy <hypothesis-numpy>`, including for\n  generating arbitrary data types. Thanks to Zac Hatfield Dodds for this\n  feature.\n* When using the :func:`~hypothesis.strategies.data` strategy you can now add a label as an argument to\n  ``draw()``, which will be printed along with the value when an example fails.\n  Thanks to Peter Inglesby for this feature.\n\nBug fixes:\n\n* Bug fix: :func:`~hypothesis.strategies.composite` now preserves functions' docstrings.\n* The build is now reproducible and doesn't depend on the path you build it\n  from. Thanks to Chris Lamb for this feature.\n* numpy strategies for the void data type did not work correctly. Thanks to\n  Zac Hatfield Dodds for this fix.\n\nThere have also been a number of performance optimizations:\n\n* The :func:`~hypothesis.strategies.permutations` strategy is now significantly faster to use for large\n  lists (the underlying algorithm has gone from O(n^2) to O(n)).\n* Shrinking of failing test cases should have got significantly faster in\n  some circumstances where it was previously struggling for a long time.\n* Example generation now involves less indirection, which results in a small\n  speedup in some cases (small enough that you won't really notice it except in\n  pathological cases).\n\n\n.. _v3.6.1:\n\n------------------\n3.6.1 - 2016-12-20\n------------------\n\nThis release fixes a dependency problem and makes some small behind the scenes\nimprovements.\n\n* The fake-factory dependency was renamed to faker. If you were depending on\n  it through hypothesis[django] or hypothesis[fake-factory] without pinning it\n  yourself then it would have failed to install properly. This release changes\n  it so that hypothesis[fakefactory] (which can now also be installed as\n  hypothesis[faker]) will install the renamed faker package instead.\n* This release also removed the dependency of hypothesis[django] on\n  hypothesis[fakefactory] - it was only being used for emails. These now use\n  a custom strategy that isn't from fakefactory. As a result you should also\n  see performance improvements of tests which generated User objects or other\n  things with email fields, as well as better shrinking of email addresses.\n* The distribution of code using nested calls to :func:`~hypothesis.strategies.one_of` or the ``|`` operator for\n  combining strategies has been improved, as branches are now flattened to give\n  a more uniform distribution.\n* Examples using :func:`~hypothesis.strategies.composite` or |.flatmap| should now shrink better. In particular\n  this will affect things which work by first generating a length and then\n  generating that many items, which have historically not shrunk very well.\n\n.. _v3.6.0:\n\n------------------\n3.6.0 - 2016-10-31\n------------------\n\nThis release reverts Hypothesis to its old pretty printing of lambda functions\nbased on attempting to extract the source code rather than decompile the bytecode.\nThis is unfortunately slightly inferior in some cases and may result in you\noccasionally seeing things like ``lambda x: <unknown>`` in statistics reports and\nstrategy reprs.\n\nThis removes the dependencies on uncompyle6, xdis and spark-parser.\n\nThe reason for this is that the new functionality was based on uncompyle6, which\nturns out to introduce a hidden GPLed dependency - it in turn depended on xdis,\nand although the library was licensed under the MIT license, it contained some\nGPL licensed source code and thus should have been released under the GPL.\n\nMy interpretation is that Hypothesis itself was never in violation of the GPL\n(because the license it is under, the Mozilla Public License v2, is fully\ncompatible with being included in a GPL licensed work), but I have not consulted\na lawyer on the subject. Regardless of the answer to this question, adding a\nGPLed dependency will likely cause a lot of users of Hypothesis to inadvertently\nbe in violation of the GPL.\n\nAs a result, if you are running Hypothesis 3.5.x you really should upgrade to\nthis release immediately.\n\n.. _v3.5.3:\n\n------------------\n3.5.3 - 2016-10-05\n------------------\n\nThis is a bug fix release.\n\nBugs fixed:\n\n* If the same test was running concurrently in two processes and there were\n  examples already in the test database which no longer failed, Hypothesis\n  would sometimes fail with a FileNotFoundError (IOError on Python 2) because\n  an example it was trying to read was deleted before it was read. (:issue:`372`).\n* Drawing from an :func:`~hypothesis.strategies.integers` strategy with both a min_value and a max_value\n  would reject too many examples needlessly. Now it repeatedly redraws until\n  satisfied. (:pull:`366`.  Thanks to Calen Pennington for the contribution).\n\n.. _v3.5.2:\n\n------------------\n3.5.2 - 2016-09-24\n------------------\n\nThis is a bug fix release.\n\n* The Hypothesis pytest plugin broke pytest support for doctests. Now it doesn't.\n\n.. _v3.5.1:\n\n------------------\n3.5.1 - 2016-09-23\n------------------\n\nThis is a bug fix release.\n\n* Hypothesis now runs cleanly in -B and -BB modes, avoiding mixing bytes and unicode.\n* :class:`python:unittest.TestCase` tests would not have shown up in the new statistics mode. Now they\n  do.\n* Similarly, stateful tests would not have shown up in statistics and now they do.\n* Statistics now print with pytest node IDs (the names you'd get in pytest verbose mode).\n\n.. _v3.5.0:\n\n------------------\n3.5.0 - 2016-09-22\n------------------\n\nThis is a feature release.\n\n* :func:`~hypothesis.strategies.fractions` and :func:`~hypothesis.strategies.decimals` strategies now support min_value and max_value\n  parameters. Thanks go to Anne Mulhern for the development of this feature.\n* The Hypothesis pytest plugin now supports a ``--hypothesis-show-statistics`` parameter\n  that gives detailed statistics about the tests that were run. Huge thanks to\n  Jean-Louis Fuchs and Adfinis-SyGroup for funding the development of this feature.\n* There is a new :func:`~hypothesis.event` function that can be used to add custom statistics.\n\nAdditionally there have been some minor bug fixes:\n\n* In some cases Hypothesis should produce fewer duplicate examples (this will mostly\n  only affect cases with a single parameter).\n* :pypi:`pytest` command line parameters are now under an option group for Hypothesis (thanks\n  to David Keijser for fixing this)\n* Hypothesis would previously error if you used :pep:`3107` function annotations on your tests under\n  Python 3.4.\n* The repr of many strategies using lambdas has been improved to include the lambda body\n  (this was previously supported in many but not all cases).\n\n.. _v3.4.2:\n\n------------------\n3.4.2 - 2016-07-13\n------------------\n\nThis is a bug fix release, fixing a number of problems with the settings system:\n\n* Test functions defined using :func:`@given <hypothesis.given>` can now be called from other threads\n  (:issue:`337`)\n* Attempting to delete a settings property would previously have silently done\n  the wrong thing. Now it raises an AttributeError.\n* Creating a settings object with a custom database_file parameter was silently\n  getting ignored and the default was being used instead. Now it's not.\n\n.. _v3.4.1:\n\n------------------\n3.4.1 - 2016-07-07\n------------------\n\nThis is a bug fix release for a single bug:\n\n* On Windows when running two Hypothesis processes in parallel (e.g. using\n  :pypi:`pytest-xdist`) they could race with each other and one would raise an exception\n  due to the non-atomic nature of file renaming on Windows and the fact that you\n  can't rename over an existing file. This is now fixed.\n\n.. _v3.4.0:\n\n------------------\n3.4.0 - 2016-05-27\n------------------\n\nThis release is entirely provided by `Lucas Wiman <https://github.com/lucaswiman>`_:\n\nStrategies constructed by the Django extra\nwill now respect much more of Django's validations out of the box.\nWherever possible, :meth:`~django:django.db.models.Model.full_clean` should\nsucceed.\n\nIn particular:\n\n* The max_length, blank and choices kwargs are now respected.\n* Add support for DecimalField.\n* If a field includes validators, the list of validators are used to filter the field strategy.\n\n.. _v3.3.0:\n\n------------------\n3.3.0 - 2016-05-27\n------------------\n\nThis release went wrong and is functionally equivalent to :ref:`3.2.0 <v3.2.0>`. Ignore it.\n\n.. _v3.2.0:\n\n------------------\n3.2.0 - 2016-05-19\n------------------\n\nThis is a small single-feature release:\n\n* All tests using :func:`@given <hypothesis.given>` now fix the global random seed. This removes the health\n  check for that. If a non-zero seed is required for the final falsifying\n  example, it will be reported. Otherwise Hypothesis will assume randomization\n  was not a significant factor for the test and be silent on the subject. If you\n  use :func:`~hypothesis.strategies.random_module` this will continue to work and will always\n  display the seed.\n\n.. _v3.1.3:\n\n------------------\n3.1.3 - 2016-05-01\n------------------\n\nSingle bug fix release\n\n* Another charmap problem. In :ref:`3.1.2 <v3.1.2>` :func:`~hypothesis.strategies.text` and\n  :func:`~hypothesis.strategies.characters` would break on systems\n  which had ``/tmp`` mounted on a different partition than the Hypothesis storage\n  directory (usually in home). This fixes that.\n\n.. _v3.1.2:\n\n------------------\n3.1.2 - 2016-04-30\n------------------\n\nSingle bug fix release:\n\n* Anything which used a :func:`~hypothesis.strategies.text` or\n  :func:`~hypothesis.strategies.characters` strategy was broken on Windows\n  and I hadn't updated appveyor to use the new repository location so I didn't\n  notice. This is now fixed and windows support should work correctly.\n\n.. _v3.1.1:\n\n------------------\n3.1.1 - 2016-04-29\n------------------\n\nMinor bug fix release.\n\n* Fix concurrency issue when running tests that use :func:`~hypothesis.strategies.text` from multiple\n  processes at once (:issue:`302`, thanks to Alex Chan).\n* Improve performance of code using :func:`~hypothesis.strategies.lists` with max_size (thanks to\n  Cristi Cobzarenco).\n* Fix install on Python 2 with ancient versions of pip so that it installs the\n  :pypi:`enum34` backport (thanks to Donald Stufft for telling me how to do this).\n* Remove duplicated __all__ exports from hypothesis.strategies (thanks to\n  Piët Delport).\n* Update headers to point to new repository location.\n* Allow use of strategies that can't be used in ``find()``\n  (e.g. ``choices()``) in stateful testing.\n\n\n.. _v3.1.0:\n\n------------------\n3.1.0 - 2016-03-06\n------------------\n\n* Add a :func:`~hypothesis.strategies.nothing` strategy that never successfully generates values.\n* :func:`~hypothesis.strategies.sampled_from` and :func:`~hypothesis.strategies.one_of`\n  can both now be called with an empty argument\n  list, in which case they also never generate any values.\n* :func:`~hypothesis.strategies.one_of` may now be called with a single argument that is a collection of strategies\n  as well as varargs.\n* Add a :func:`~hypothesis.strategies.runner` strategy which returns the instance of the current test object\n  if there is one.\n* 'Bundle' for RuleBasedStateMachine is now a normal(ish) strategy and can be used\n  as such.\n* Tests using RuleBasedStateMachine should now shrink significantly better.\n* Hypothesis now uses a pretty-printing library internally, compatible with IPython's\n  pretty printing protocol (actually using the same code). This may improve the quality\n  of output in some cases.\n* Add a 'phases' setting that allows more fine grained control over which parts of the\n  process Hypothesis runs\n* Add a suppress_health_check setting which allows you to turn off specific health checks\n  in a fine grained manner.\n* Fix a bug where lists of non fixed size would always draw one more element than they\n  included. This mostly didn't matter, but if would cause problems with empty strategies\n  or ones with side effects.\n* Add a mechanism to the Django model generator to allow you to explicitly request the\n  default value (thanks to Jeremy Thurgood for this one).\n\n.. _v3.0.5:\n\n------------------\n3.0.5 - 2016-02-25\n------------------\n\n* Fix a bug where Hypothesis would now error on :pypi:`pytest` development versions.\n\n.. _v3.0.4:\n\n------------------\n3.0.4 - 2016-02-24\n------------------\n\n* Fix a bug where Hypothesis would error when running on Python 2.7.3 or\n  earlier because it was trying to pass a :class:`python:bytearray` object\n  to :func:`python:struct.unpack` (which is only supported since 2.7.4).\n\n.. _v3.0.3:\n\n------------------\n3.0.3 - 2016-02-23\n------------------\n\n* Fix version parsing of pytest to work with pytest release candidates\n* More general handling of the health check problem where things could fail because\n  of a cache miss - now one \"free\" example is generated before the start of the\n  health check run.\n\n.. _v3.0.2:\n\n------------------\n3.0.2 - 2016-02-18\n------------------\n\n* Under certain circumstances, strategies involving :func:`~hypothesis.strategies.text` buried inside some\n  other strategy (e.g. ``text().filter(...)`` or ``recursive(text(), ...))`` would cause\n  a test to fail its health checks the first time it ran. This was caused by having\n  to compute some related data and cache it to disk. On travis or anywhere else\n  where the ``.hypothesis`` directory was recreated this would have caused the tests\n  to fail their health check on every run. This is now fixed for all the known cases,\n  although there could be others lurking.\n\n.. _v3.0.1:\n\n------------------\n3.0.1 - 2016-02-18\n------------------\n\n* Fix a case where it was possible to trigger an \"Unreachable\" assertion when\n  running certain flaky stateful tests.\n* Improve shrinking of large stateful tests by eliminating a case where it was\n  hard to delete early steps.\n* Improve efficiency of drawing :func:`binary(min_size=n, max_size=n) <hypothesis.strategies.binary>` significantly by\n  provide a custom implementation for fixed size blocks that can bypass a lot\n  of machinery.\n* Set default home directory based on the current working directory at the\n  point Hypothesis is imported, not whenever the function first happens to be\n  called.\n\n.. _v3.0.0:\n\n------------------\n3.0.0 - 2016-02-17\n------------------\n\nCodename: This really should have been 2.1.\n\nExternally this looks like a very small release. It has one small breaking change\nthat probably doesn't affect anyone at all (some behaviour that never really worked\ncorrectly is now outright forbidden) but necessitated a major version bump and one\nvisible new feature.\n\nInternally this is a complete rewrite. Almost nothing other than the public API is\nthe same.\n\nNew features:\n\n* Addition of :func:`~hypothesis.strategies.data` strategy which allows you to draw arbitrary data interactively\n  within the test.\n* New \"exploded\" database format which allows you to more easily check the example\n  database into a source repository while supporting merging.\n* Better management of how examples are saved in the database.\n* Health checks will now raise as errors when they fail. It was too easy to have\n  the warnings be swallowed entirely.\n\nNew limitations:\n\n* ``choices()`` and ``streaming()``\n  strategies may no longer be used with ``find()``. Neither may\n  :func:`~hypothesis.strategies.data` (this is the change that necessitated a major version bump).\n\nFeature removal:\n\n* The ForkingTestCase executor has gone away. It may return in some more working\n  form at a later date.\n\nPerformance improvements:\n\n* A new model which allows flatmap, composite strategies and stateful testing to\n  perform *much* better. They should also be more reliable.\n* Filtering may in some circumstances have improved significantly. This will\n  help especially in cases where you have lots of values with individual filters\n  on them, such as lists(x.filter(...)).\n* Modest performance improvements to the general test runner by avoiding expensive\n  operations\n\nIn general your tests should have got faster. If they've instead got significantly\nslower, I'm interested in hearing about it.\n\nData distribution:\n\nThe data distribution should have changed significantly. This may uncover bugs the\nprevious version missed. It may also miss bugs the previous version could have\nuncovered. Hypothesis is now producing less strongly correlated data than it used\nto, but the correlations are extended over more of the structure.\n\nShrinking:\n\nShrinking quality should have improved. In particular Hypothesis can now perform\nsimultaneous shrinking of separate examples within a single test (previously it\nwas only able to do this for elements of a single collection). In some cases\nperformance will have improved, in some cases it will have got worse but generally\nshouldn't have by much.\n\n\nOlder versions\n==============\n\n.. _v2.0.0:\n\n------------------\n2.0.0 - 2016-01-10\n------------------\n\nCodename: A new beginning\n\nThis release cleans up all of the legacy that accrued in the course of\nHypothesis 1.0. These are mostly things that were emitting deprecation warnings\nin 1.19.0, but there were a few additional changes.\n\nIn particular:\n\n* non-strategy values will no longer be converted to strategies when used in\n  given or find.\n* FailedHealthCheck is now an error and not a warning.\n* Handling of non-ascii reprs in user types have been simplified by using raw\n  strings in more places in Python 2.\n* given no longer allows mixing positional and keyword arguments.\n* given no longer works with functions with defaults.\n* given no longer turns provided arguments into defaults - they will not appear\n  in the argspec at all.\n* the basic() strategy no longer exists.\n* the n_ary_tree strategy no longer exists.\n* the average_list_length setting no longer exists. Note: If you're using\n  using recursive() this will cause you a significant slow down. You should\n  pass explicit average_size parameters to collections in recursive calls.\n* @rule can no longer be applied to the same method twice.\n* Python 2.6 and 3.3 are no longer officially supported, although in practice\n  they still work fine.\n\nThis also includes two non-deprecation changes:\n\n* given's keyword arguments no longer have to be the rightmost arguments and\n  can appear anywhere in the method signature.\n* The max_shrinks setting would sometimes not have been respected.\n\n\n.. _v1.19.0:\n\n-------------------\n1.19.0 - 2016-01-09\n-------------------\n\nCodename: IT COMES\n\nThis release heralds the beginning of a new and terrible age of Hypothesis 2.0.\n\nIt's primary purpose is some final deprecations prior to said release. The goal\nis that if your code emits no warnings under this release then it will probably run\nunchanged under Hypothesis 2.0 (there are some caveats to this: 2.0 will drop\nsupport for some Python versions, and if you're using internal APIs then as usual\nthat may break without warning).\n\nIt does have two new features:\n\n* New @seed() decorator which allows you to manually seed a test. This may be\n  harmlessly combined with and overrides the derandomize setting.\n* settings objects may now be used as a decorator to fix those settings to a\n  particular @given test.\n\nAPI changes (old usage still works but is deprecated):\n\n* Settings has been renamed to settings (lower casing) in order to make the\n  decorator usage more natural.\n* Functions for the storage directory that were in hypothesis.settings are now\n  in a new hypothesis.configuration module.\n\nAdditional deprecations:\n\n* the average_list_length setting has been deprecated in favour of being\n  explicit.\n* the basic() strategy has been deprecated as it is impossible to support\n  it under a Conjecture based model, which will hopefully be implemented at\n  some point in the 2.x series.\n* the n_ary_tree strategy (which was never actually part of the public API)\n  has been deprecated.\n* Passing settings or random as keyword arguments to given is deprecated (use\n  the new functionality instead)\n\n\nBug fixes:\n\n* No longer emit PendingDeprecationWarning for __iter__ and StopIteration in\n  streaming() values.\n* When running in health check mode with non strict, don't print quite so\n  many errors for an exception in reify.\n* When an assumption made in a test or a filter is flaky, tests will now\n  raise Flaky instead of UnsatisfiedAssumption.\n\n\n.. _v1.18.1:\n\n-------------------\n1.18.1 - 2015-12-22\n-------------------\n\nTwo behind the scenes changes:\n\n* Hypothesis will no longer write generated code to the file system. This\n  will improve performance on some systems (e.g. if you're using\n  `PythonAnywhere <https://www.pythonanywhere.com/>`_ which is running your\n  code from NFS) and prevent some annoying interactions with auto-restarting\n  systems.\n* Hypothesis will cache the creation of some strategies. This can significantly\n  improve performance for code that uses flatmap or composite and thus has to\n  instantiate strategies a lot.\n\n.. _v1.18.0:\n\n-------------------\n1.18.0 - 2015-12-21\n-------------------\n\nFeatures:\n\n* Tests and find are now explicitly seeded off the global random module. This\n  means that if you nest one inside the other you will now get a health check\n  error. It also means that you can control global randomization by seeding\n  random.\n* There is a new random_module() strategy which seeds the global random module\n  for you and handles things so that you don't get a health check warning if\n  you use it inside your tests.\n* floats() now accepts two new arguments: allow\\_nan and allow\\_infinity. These\n  default to the old behaviour, but when set to False will do what the names\n  suggest.\n\nBug fixes:\n\n* Fix a bug where tests that used text() on Python 3.4+ would not actually be\n  deterministic even when explicitly seeded or using the derandomize mode,\n  because generation depended on dictionary iteration order which was affected\n  by hash randomization.\n* Fix a bug where with complicated strategies the timing of the initial health\n  check could affect the seeding of the subsequent test, which would also\n  render supposedly deterministic tests non-deterministic in some scenarios.\n* In some circumstances flatmap() could get confused by two structurally\n  similar things it could generate and would produce a flaky test where the\n  first time it produced an error but the second time it produced the other\n  value, which was not an error. The same bug was presumably also possible in\n  composite().\n* flatmap() and composite() initial generation should now be moderately faster.\n  This will be particularly noticeable when you have many values drawn from the\n  same strategy in a single run, e.g. constructs like lists(s.flatmap(f)).\n  Shrinking performance *may* have suffered, but this didn't actually produce\n  an interestingly worse result in any of the standard scenarios tested.\n\n.. _v1.17.1:\n\n-------------------\n1.17.1 - 2015-12-16\n-------------------\n\nA small bug fix release, which fixes the fact that the 'note' function could\nnot be used on tests which used the @example decorator to provide explicit\nexamples.\n\n.. _v1.17.0:\n\n-------------------\n1.17.0 - 2015-12-15\n-------------------\n\nThis is actually the same release as 1.16.1, but 1.16.1 has been pulled because\nit contains the following additional change that was not intended to be in a\npatch  release (it's perfectly stable, but is a larger change that should have\nrequired a minor version bump):\n\n* Hypothesis will now perform a series of \"health checks\" as part of running\n  your tests. These detect and warn about some common error conditions that\n  people often run into which wouldn't necessarily have caused the test to fail\n  but would cause e.g. degraded performance or confusing results.\n\n.. _v1.16.1:\n\n-------------------\n1.16.1 - 2015-12-14\n-------------------\n\nNote: This release has been removed.\n\nA small bugfix release that allows bdists for Hypothesis to be built\nunder 2.7 - the compat3.py file which had Python 3 syntax wasn't intended\nto be loaded under Python 2, but when building a bdist it was. In particular\nthis would break running setup.py test.\n\n.. _v1.16.0:\n\n-------------------\n1.16.0 - 2015-12-08\n-------------------\n\nThere are no public API changes in this release but it includes a behaviour\nchange that I wasn't comfortable putting in a patch release.\n\n* Functions from hypothesis.strategies will no longer raise InvalidArgument\n  on bad arguments. Instead the same errors will be raised when a test\n  using such a strategy is run. This may improve startup time in some\n  cases, but the main reason for it is so that errors in strategies\n  won't cause errors in loading, and it can interact correctly with things\n  like pytest.mark.skipif.\n* Errors caused by accidentally invoking the legacy API are now much less\n  confusing, although still throw NotImplementedError.\n* hypothesis.extra.django is 1.9 compatible.\n* When tests are run with max_shrinks=0 this will now still rerun the test\n  on failure and will no longer print \"Trying example:\" before each run.\n  Additionally note() will now work correctly when used with max_shrinks=0.\n\n.. _v1.15.0:\n\n-------------------\n1.15.0 - 2015-11-24\n-------------------\n\nA release with two new features.\n\n* A 'characters' strategy for more flexible generation of text with particular\n  character ranges and types, kindly contributed by `Alexander Shorin <https://github.com/kxepal>`_.\n* Add support for preconditions to the rule based stateful testing. Kindly\n  contributed by `Christopher Armstrong <https://github.com/radix>`_\n\n\n.. _v1.14.0:\n\n-------------------\n1.14.0 - 2015-11-01\n-------------------\n\n\nNew features:\n\n* Add 'note' function which lets you include additional information in the\n  final test run's output.\n* Add 'choices' strategy which gives you a choice function that emulates\n  random.choice.\n* Add 'uuid' strategy that generates UUIDs'\n* Add 'shared' strategy that lets you create a strategy that just generates a\n  single shared value for each test run\n\nBugs:\n\n* Using strategies of the form streaming(x.flatmap(f)) with find or in stateful\n  testing would have caused InvalidArgument errors when the resulting values\n  were used (because code that expected to only be called within a test context\n  would be invoked).\n\n\n.. _v1.13.0:\n\n-------------------\n1.13.0 - 2015-10-29\n-------------------\n\nThis is quite a small release, but deprecates some public API functions\nand removes some internal API functionality so gets a minor version bump.\n\n* All calls to the 'strategy' function are now deprecated, even ones which\n  pass just a SearchStrategy instance (which is still a no-op).\n* Never documented hypothesis.extra entry_points mechanism has now been removed (\n  it was previously how hypothesis.extra packages were loaded and has been deprecated\n  and unused for some time)\n* Some corner cases that could previously have produced an OverflowError when simplifying\n  failing cases using hypothesis.extra.datetimes (or dates or times) have now been fixed.\n* Hypothesis load time for first import has been significantly reduced - it used to be\n  around 250ms (on my SSD laptop) and now is around 100-150ms. This almost never\n  matters but was slightly annoying when using it in the console.\n* hypothesis.strategies.randoms was previously missing from \\_\\_all\\_\\_.\n\n.. _v1.12.0:\n\n-------------------\n1.12.0 - 2015-10-18\n-------------------\n\n* Significantly improved performance of creating strategies using the functions\n  from the hypothesis.strategies module by deferring the calculation of their\n  repr until it was needed. This is unlikely to have been an performance issue\n  for you unless you were using flatmap, composite or stateful testing, but for\n  some cases it could be quite a significant impact.\n* A number of cases where the repr of strategies build from lambdas is improved\n* Add dates() and times() strategies to hypothesis.extra.datetimes\n* Add new 'profiles' mechanism to the settings system\n* Deprecates mutability of Settings, both the Settings.default top level property\n  and individual settings.\n* A Settings object may now be directly initialized from a parent Settings.\n* @given should now give a better error message if you attempt to use it with a\n  function that uses destructuring arguments (it still won't work, but it will\n  error more clearly),\n* A number of spelling corrections in error messages\n* :pypi:`pytest` should no longer display the intermediate modules Hypothesis generates\n  when running in verbose mode\n* Hypothesis should now correctly handle printing objects with non-ascii reprs\n  on python 3 when running in a locale that cannot handle ascii printing to\n  stdout.\n* Add a unique=True argument to lists(). This is equivalent to\n  unique_by=lambda x: x, but offers a more convenient syntax.\n\n\n.. _v1.11.4:\n\n-------------------\n1.11.4 - 2015-09-27\n-------------------\n\n* Hide modifications Hypothesis needs to make to sys.path by undoing them\n  after we've imported the relevant modules. This is a workaround for issues\n  cryptography experienced on windows.\n* Slightly improved performance of drawing from sampled_from on large lists\n  of alternatives.\n* Significantly improved performance of drawing from one_of or strategies\n  using \\| (note this includes a lot of strategies internally - floats()\n  and integers() both fall into this category). There turned out to be a\n  massive performance regression introduced in 1.10.0 affecting these which\n  probably would have made tests using Hypothesis significantly slower than\n  they should have been.\n\n.. _v1.11.3:\n\n-------------------\n1.11.3 - 2015-09-23\n-------------------\n\n* Better argument validation for datetimes() strategy - previously setting\n  max_year < datetime.MIN_YEAR or min_year > datetime.MAX_YEAR would not have\n  raised an InvalidArgument error and instead would have behaved confusingly.\n* Compatibility with being run on pytest < 2.7 (achieved by disabling the\n  plugin).\n\n.. _v1.11.2:\n\n-------------------\n1.11.2 - 2015-09-23\n-------------------\n\nBug fixes:\n\n* Settings(database=my_db) would not be correctly inherited when used as a\n  default setting, so that newly created settings would use the database_file\n  setting and create an SQLite example database.\n* Settings.default.database = my_db would previously have raised an error and\n  now works.\n* Timeout could sometimes be significantly exceeded if during simplification\n  there were a lot of examples tried that didn't trigger the bug.\n* When loading a heavily simplified example using a basic() strategy from the\n  database this could cause Python to trigger a recursion error.\n* Remove use of deprecated API in pytest plugin so as to not emit warning\n\nMisc:\n\n* hypothesis-pytest is now part of hypothesis core. This should have no\n  externally visible consequences, but you should update your dependencies to\n  remove hypothesis-pytest and depend on only Hypothesis.\n* Better repr for hypothesis.extra.datetimes() strategies.\n* Add .close() method to abstract base class for Backend (it was already present\n  in the main implementation).\n\n.. _v1.11.1:\n\n-------------------\n1.11.1 - 2015-09-16\n-------------------\n\nBug fixes:\n\n* When running Hypothesis tests in parallel (e.g. using pytest-xdist) there was a race\n  condition caused by code generation.\n* Example databases are now cached per thread so as to not use sqlite connections from\n  multiple threads. This should make Hypothesis now entirely thread safe.\n* floats() with only min_value or max_value set would have had a very bad distribution.\n* Running on 3.5, Hypothesis would have emitted deprecation warnings because of use of\n  inspect.getargspec\n\n.. _v1.11.0:\n\n-------------------\n1.11.0 - 2015-08-31\n-------------------\n\n* text() with a non-string alphabet would have used the repr() of the alphabet\n  instead of its contexts. This is obviously silly. It now works with any sequence\n  of things convertible to unicode strings.\n* @given will now work on methods whose definitions contains no explicit positional\n  arguments, only varargs (:issue:`118`).\n  This may have some knock on effects because it means that @given no longer changes the\n  argspec of functions other than by adding defaults.\n* Introduction of new @composite feature for more natural definition of strategies you'd\n  previously have used flatmap for.\n\n.. _v1.10.6:\n\n-------------------\n1.10.6 - 2015-08-26\n-------------------\n\nFix support for fixtures on Django 1.7.\n\n.. _v1.10.4:\n\n-------------------\n1.10.4 - 2015-08-21\n-------------------\n\nTiny bug fix release:\n\n* If the database_file setting is set to None, this would have resulted in\n  an error when running tests. Now it does the same as setting database to\n  None.\n\n.. _v1.10.3:\n\n-------------------\n1.10.3 - 2015-08-19\n-------------------\n\nAnother small bug fix release.\n\n* lists(elements, unique_by=some_function, min_size=n) would have raised a\n  ValidationError if n > Settings.default.average_list_length because it would\n  have wanted to use an average list length shorter than the minimum size of\n  the list, which is impossible. Now it instead defaults to twice the minimum\n  size in these circumstances.\n* basic() strategy would have only ever produced at most ten distinct values\n  per run of the test (which is bad if you e.g. have it inside a list). This\n  was obviously silly. It will now produce a much better distribution of data,\n  both duplicated and non duplicated.\n\n\n.. _v1.10.2:\n\n-------------------\n1.10.2 - 2015-08-19\n-------------------\n\nThis is a small bug fix release:\n\n* star imports from hypothesis should now work correctly.\n* example quality for examples using flatmap will be better, as the way it had\n  previously been implemented was causing problems where Hypothesis was\n  erroneously labelling some examples as being duplicates.\n\n.. _v1.10.0:\n\n-------------------\n1.10.0 - 2015-08-04\n-------------------\n\nThis is just a bugfix and performance release, but it changes some\nsemi-public APIs, hence the minor version bump.\n\n* Significant performance improvements for strategies which are one\\_of()\n  many branches. In particular this included recursive() strategies. This\n  should take the case where you use one recursive() strategy as the base\n  strategy of another from unusably slow (tens of seconds per generated\n  example) to reasonably fast.\n* Better handling of just() and sampled_from() for values which have an\n  incorrect \\_\\_repr\\_\\_ implementation that returns non-ASCII unicode\n  on Python 2.\n* Better performance for flatmap from changing the internal morpher API\n  to be significantly less general purpose.\n* Introduce a new semi-public BuildContext/cleanup API. This allows\n  strategies to register cleanup activities that should run once the\n  example is complete. Note that this will interact somewhat weirdly with\n  find.\n* Better simplification behaviour for streaming strategies.\n* Don't error on lambdas which use destructuring arguments in Python 2.\n* Add some better reprs for a few strategies that were missing good ones.\n* The Random instances provided by randoms() are now copyable.\n* Slightly more debugging information about simplify when using a debug\n  verbosity level.\n* Support using given for functions with varargs, but not passing arguments\n  to it as positional.\n\n.. _v1.9.0:\n\n------------------\n1.9.0 - 2015-07-27\n------------------\n\nCodename: The great bundling.\n\nThis release contains two fairly major changes.\n\nThe first is the deprecation of the hypothesis-extra mechanism. From\nnow on all the packages that were previously bundled under it other\nthan hypothesis-pytest (which is a different beast and will remain\nseparate). The functionality remains unchanged and you can still import\nthem from exactly the same location, they just are no longer separate\npackages.\n\nThe second is that this introduces a new way of building strategies\nwhich lets you build up strategies recursively from other strategies.\n\nIt also contains the minor change that calling .example() on a\nstrategy object will give you examples that are more representative of\nthe actual data you'll get. There used to be some logic in there to make\nthe examples artificially simple but this proved to be a bad idea.\n\n.. _v1.8.5:\n\n------------------\n1.8.5 - 2015-07-24\n------------------\n\nThis contains no functionality changes but fixes a mistake made with\nbuilding the previous package that would have broken installation on\nWindows.\n\n.. _v1.8.4:\n\n------------------\n1.8.4 - 2015-07-20\n------------------\n\nBugs fixed:\n\n* When a call to floats() had endpoints which were not floats but merely\n  convertible to one (e.g. integers), these would be included in the generated\n  data which would cause it to generate non-floats.\n* Splitting lambdas used in the definition of flatmap, map or filter over\n  multiple lines would break the repr, which would in turn break their usage.\n\n\n.. _v1.8.3:\n\n------------------\n1.8.3 - 2015-07-20\n------------------\n\n\"Falsifying example\" would not have been printed when the failure came from an\nexplicit example.\n\n.. _v1.8.2:\n\n------------------\n1.8.2 - 2015-07-18\n------------------\n\nAnother small bugfix release:\n\n* When using ForkingTestCase you would usually not get the falsifying example\n  printed if the process exited abnormally (e.g. due to os._exit).\n* Improvements to the distribution of characters when using text() with a\n  default alphabet. In particular produces a better distribution of ascii and\n  whitespace in the alphabet.\n\n.. _v1.8.1:\n\n------------------\n1.8.1 - 2015-07-17\n------------------\n\nThis is a small release that contains a workaround for people who have\nbad reprs returning non ascii text on Python 2.7. This is not a bug fix\nfor Hypothesis per se because that's not a thing that is actually supposed\nto work, but Hypothesis leans more heavily on repr than is typical so it's\nworth having a workaround for.\n\n.. _v1.8.0:\n\n------------------\n1.8.0 - 2015-07-16\n------------------\n\nNew features:\n\n* Much more sensible reprs for strategies, especially ones that come from\n  hypothesis.strategies. These should now have as reprs python code that\n  would produce the same strategy.\n* lists() accepts a unique_by argument which forces the generated lists to be\n  only contain elements unique according to some function key (which must\n  return a hashable value).\n* Better error messages from flaky tests to help you debug things.\n\nMostly invisible implementation details that may result in finding new bugs\nin your code:\n\n* Sets and dictionary generation should now produce a better range of results.\n* floats with bounds now focus more on 'critical values', trying to produce\n  values at edge cases.\n* flatmap should now have better simplification for complicated cases, as well\n  as generally being (I hope) more reliable.\n\nBug fixes:\n\n* You could not previously use assume() if you were using the forking executor.\n\n\n.. _v1.7.2:\n\n------------------\n1.7.2 - 2015-07-10\n------------------\n\nThis is purely a bug fix release:\n\n* When using floats() with stale data in the database you could sometimes get\n  values in your tests that did not respect min_value or max_value.\n* When getting a Flaky error from an unreliable test it would have incorrectly\n  displayed the example that caused it.\n* 2.6 dependency on backports was incorrectly specified. This would only have\n  caused you problems if you were building a universal wheel from Hypothesis,\n  which is not how Hypothesis ships, so unless you're explicitly building wheels\n  for your dependencies and support Python 2.6 plus a later version of Python\n  this probably would never have affected you.\n* If you use flatmap in a way that the strategy on the right hand side depends\n  sensitively on the left hand side you may have occasionally seen Flaky errors\n  caused by producing unreliable examples when minimizing a bug. This use case\n  may still be somewhat fraught to be honest. This code is due a major rearchitecture\n  for 1.8, but in the meantime this release fixes the only source of this error that\n  I'm aware of.\n\n.. _v1.7.1:\n\n------------------\n1.7.1 - 2015-06-29\n------------------\n\nCodename: There is no 1.7.0.\n\nA slight technical hitch with a premature upload means there's was a yanked\n1.7.0 release. Oops.\n\nThe major feature of this release is Python 2.6 support. Thanks to Jeff Meadows\nfor doing most of the work there.\n\nOther minor features\n\n* strategies now has a permutations() function which returns a strategy\n  yielding permutations of values from a given collection.\n* if you have a flaky test it will print the exception that it last saw before\n  failing with Flaky, even if you do not have verbose reporting on.\n* Slightly experimental git merge script available as \"python -m\n  hypothesis.tools.mergedbs\". Instructions on how to use it in the docstring\n  of that file.\n\nBug fixes:\n\n* Better performance from use of filter. In particular tests which involve large\n  numbers of heavily filtered strategies should perform a lot better.\n* floats() with a negative min_value would not have worked correctly (worryingly,\n  it would have just silently failed to run any examples). This is now fixed.\n* tests using sampled\\_from would error if the number of sampled elements was smaller\n  than min\\_satisfying\\_examples.\n\n\n.. _v1.6.2:\n\n------------------\n1.6.2 - 2015-06-08\n------------------\n\nThis is just a few small bug fixes:\n\n* Size bounds were not validated for values for a binary() strategy when\n  reading examples from the database.\n* sampled\\_from is now in __all__ in hypothesis.strategies\n* floats no longer consider negative integers to be simpler than positive\n  non-integers\n* Small floating point intervals now correctly count members, so if you have a\n  floating point interval so narrow there are only a handful of values in it,\n  this will no longer cause an error when Hypothesis runs out of values.\n\n.. _v1.6.1:\n\n------------------\n1.6.1 - 2015-05-21\n------------------\n\nThis is a small patch release that fixes a bug where 1.6.0 broke the use\nof flatmap with the deprecated API and assumed the passed in function returned\na SearchStrategy instance rather than converting it to a strategy.\n\n.. _v1.6.0:\n\n------------------\n1.6.0 - 2015-05-21\n------------------\n\n\nThis is a smallish release designed to fix a number of bugs and smooth out\nsome weird behaviours.\n\n* Fix a critical bug in flatmap where it would reuse old strategies. If all\n  your flatmap code was pure you're fine. If it's not, I'm surprised it's\n  working at all. In particular if you want to use flatmap with django models,\n  you desperately need to upgrade to this version.\n* flatmap simplification performance should now be better in some cases where\n  it previously had to redo work.\n* Fix for a bug where invalid unicode data with surrogates could be generated\n  during simplification (it was already filtered out during actual generation).\n* The Hypothesis database is now keyed off the name of the test instead of the\n  type of data. This makes much more sense now with the new strategies API and\n  is generally more robust. This means you will lose old examples on upgrade.\n* The database will now not delete values which fail to deserialize correctly,\n  just skip them. This is to handle cases where multiple incompatible strategies\n  share the same key.\n* find now also saves and loads values from the database, keyed off a hash of the\n  function you're finding from.\n* Stateful tests now serialize and load values from the database. They should have\n  before, really. This was a bug.\n* Passing a different verbosity level into a test would not have worked entirely\n  correctly, leaving off some messages. This is now fixed.\n* Fix a bug where derandomized tests with unicode characters in the function\n  body would error on Python 2.7.\n\n\n.. _v1.5.0:\n\n------------------\n1.5.0 - 2015-05-14\n------------------\n\n\nCodename: Strategic withdrawal.\n\nThe purpose of this release is a radical simplification of the API for building\nstrategies. Instead of the old approach of @strategy.extend and things that\nget converted to strategies, you just build strategies directly.\n\nThe old method of defining strategies will still work until Hypothesis 2.0,\nbecause it's a major breaking change, but will now emit deprecation warnings.\n\nThe new API is also a lot more powerful as the functions for defining strategies\ngive you a lot of dials to turn. See :doc:`the updated data section </reference/strategies>` for\ndetails.\n\nOther changes:\n\n  * Mixing keyword and positional arguments in a call to @given is deprecated as well.\n  * There is a new setting called 'strict'. When set to True, Hypothesis will raise\n    warnings instead of merely printing them. Turning it on by default is inadvisable because\n    it means that Hypothesis minor releases can break your code, but it may be useful for\n    making sure you catch all uses of deprecated APIs.\n  * max_examples in settings is now interpreted as meaning the maximum number\n    of unique (ish) examples satisfying assumptions. A new setting max_iterations\n    which defaults to a larger value has the old interpretation.\n  * Example generation should be significantly faster due to a new faster parameter\n    selection algorithm. This will mostly show up for simple data types - for complex\n    ones the parameter selection is almost certainly dominated.\n  * Simplification has some new heuristics that will tend to cut down on cases\n    where it could previously take a very long time.\n  * timeout would previously not have been respected in cases where there were a lot\n    of duplicate examples. You probably wouldn't have previously noticed this because\n    max_examples counted duplicates, so this was very hard to hit in a way that mattered.\n  * A number of internal simplifications to the SearchStrategy API.\n  * You can now access the current Hypothesis version as hypothesis.__version__.\n  * A top level function is provided for running the stateful tests without the\n    TestCase infrastructure.\n\n.. _v1.4.0:\n\n------------------\n1.4.0 - 2015-05-04\n------------------\n\nCodename: What a state.\n\nThe *big* feature of this release is the new and slightly experimental\nstateful testing API. You can read more about that in :ref:`the appropriate section <stateful>`.\n\nTwo minor features the were driven out in the course of developing this:\n\n* You can now set settings.max_shrinks to limit the number of times\n  Hypothesis will try to shrink arguments to your test. If this is set to\n  <= 0 then Hypothesis will not rerun your test and will just raise the\n  failure directly. Note that due to technical limitations if max_shrinks\n  is <= 0 then Hypothesis will print *every* example it calls your test\n  with rather than just the failing one. Note also that I don't consider\n  settings max_shrinks to zero a sensible way to run your tests and it\n  should really be considered a debug feature.\n* There is a new debug level of verbosity which is even *more* verbose than\n  verbose. You probably don't want this.\n\nBreakage of semi-public SearchStrategy API:\n\n* It is now a required invariant of SearchStrategy that if u simplifies to\n  v then it is not the case that strictly_simpler(u, v). i.e. simplifying\n  should not *increase* the complexity even though it is not required to\n  decrease it. Enforcing this invariant lead to finding some bugs where\n  simplifying of integers, floats and sets was suboptimal.\n* Integers in basic data are now required to fit into 64 bits. As a result\n  python integer types are now serialized as strings, and some types have\n  stopped using quite so needlessly large random seeds.\n\nHypothesis Stateful testing was then turned upon Hypothesis itself, which lead\nto an amazing number of minor bugs being found in Hypothesis itself.\n\nBugs fixed (most but not all from the result of stateful testing) include:\n\n* Serialization of streaming examples was flaky in a way that you would\n  probably never notice: If you generate a template, simplify it, serialize\n  it, deserialize it, serialize it again and then deserialize it you would\n  get the original stream instead of the simplified one.\n* If you reduced max_examples below the number of examples already saved in\n  the database, you would have got a ValueError. Additionally, if you had\n  more than max_examples in the database all of them would have been\n  considered.\n* @given will no longer count duplicate examples (which it never called\n  your function with) towards max_examples. This may result in your tests\n  running slower, but that's probably just because they're trying more\n  examples.\n* General improvements to example search which should result in better\n  performance and higher quality examples. In particular parameters which\n  have a history of producing useless results will be more aggressively\n  culled. This is useful both because it decreases the chance of useless\n  examples and also because it's much faster to not check parameters which\n  we were unlikely to ever pick!\n* integers_from and lists of types with only one value (e.g. [None]) would\n  previously have had a very high duplication rate so you were probably\n  only getting a handful of examples. They now have a much lower\n  duplication rate, as well as the improvements to search making this\n  less of a problem in the first place.\n* You would sometimes see simplification taking significantly longer than\n  your defined timeout. This would happen because timeout was only being\n  checked after each *successful* simplification, so if Hypothesis was\n  spending a lot of time unsuccessfully simplifying things it wouldn't\n  stop in time. The timeout is now applied for unsuccessful simplifications\n  too.\n* In Python 2.7, integers_from strategies would have failed during\n  simplification with an OverflowError if their starting point was at or\n  near to the maximum size of a 64-bit integer.\n* flatmap and map would have failed if called with a function without a\n  __name__ attribute.\n* If max_examples was less than min_satisfying_examples this would always\n  error. Now min_satisfying_examples is capped to max_examples. Note that\n  if you have assumptions to satisfy here this will still cause an error.\n\nSome minor quality improvements:\n\n* Lists of streams, flatmapped strategies and basic strategies should now\n  now have slightly better simplification.\n\n.. _v1.3.0:\n\n------------------\n1.3.0 - 2015-05-22\n------------------\n\nNew features:\n\n* New verbosity level API for printing intermediate results and exceptions.\n* New specifier for strings generated from a specified alphabet.\n* Better error messages for tests that are failing because of a lack of enough\n  examples.\n\nBug fixes:\n\n* Fix error where use of ForkingTestCase would sometimes result in too many\n  open files.\n* Fix error where saving a failing example that used flatmap could error.\n* Implement simplification for sampled_from, which apparently never supported\n  it previously. Oops.\n\n\nGeneral improvements:\n\n* Better range of examples when using one_of or sampled_from.\n* Fix some pathological performance issues when simplifying lists of complex\n  values.\n* Fix some pathological performance issues when simplifying examples that\n  require unicode strings with high codepoints.\n* Random will now simplify to more readable examples.\n\n\n.. _v1.2.1:\n\n------------------\n1.2.1 - 2015-04-16\n------------------\n\nA small patch release for a bug in the new executors feature. Tests which require\ndoing something to their result in order to fail would have instead reported as\nflaky.\n\n.. _v1.2.0:\n\n------------------\n1.2.0 - 2015-04-15\n------------------\n\nCodename: Finders keepers.\n\nA bunch of new features and improvements.\n\n* Provide a mechanism for customizing how your tests are executed.\n* Provide a test runner that forks before running each example. This allows\n  better support for testing native code which might trigger a segfault or a C\n  level assertion failure.\n* Support for using Hypothesis to find examples directly rather than as just as\n  a test runner.\n* New streaming type which lets you generate infinite lazily loaded streams of\n  data - perfect for if you need a number of examples but don't know how many.\n* Better support for large integer ranges. You can now use integers_in_range\n  with ranges of basically any size. Previously large ranges would have eaten\n  up all your memory and taken forever.\n* Integers produce a wider range of data than before - previously they would\n  only rarely produce integers which didn't fit into a machine word. Now it's\n  much more common. This percolates to other numeric types which build on\n  integers.\n* Better validation of arguments to @given. Some situations that would\n  previously have caused silently wrong behaviour will now raise an error.\n* Include +/- sys.float_info.max in the set of floating point edge cases that\n  Hypothesis specifically tries.\n* Fix some bugs in floating point ranges which happen when given\n  +/- sys.float_info.max as one of the endpoints... (really any two floats that\n  are sufficiently far apart so that x, y are finite but y - x is infinite).\n  This would have resulted in generating infinite values instead of ones inside\n  the range.\n\n.. _v1.1.1:\n\n------------------\n1.1.1 - 2015-04-07\n------------------\n\nCodename: Nothing to see here\n\nThis is just a patch release put out because it fixed some internal bugs that would\nblock the Django integration release but did not actually affect anything anyone could\npreviously have been using. It also contained a minor quality fix for floats that\nI'd happened to have finished in time.\n\n* Fix some internal bugs with object lifecycle management that were impossible to\n  hit with the previously released versions but broke hypothesis-django.\n* Bias floating point numbers somewhat less aggressively towards very small numbers\n\n\n.. _v1.1.0:\n\n------------------\n1.1.0 - 2015-04-06\n------------------\n\nCodename: No-one mention the M word.\n\n* Unicode strings are more strongly biased towards ascii characters. Previously they\n  would generate all over the space. This is mostly so that people who try to\n  shape their unicode strings with assume() have less of a bad time.\n* A number of fixes to data deserialization code that could theoretically have\n  caused mysterious bugs when using an old version of a Hypothesis example\n  database with a newer version. To the best of my knowledge a change that could\n  have triggered this bug has never actually been seen in the wild. Certainly\n  no-one ever reported a bug of this nature.\n* Out of the box support for Decimal and Fraction.\n* new dictionary specifier for dictionaries with variable keys.\n* Significantly faster and higher quality simplification, especially for\n  collections of data.\n* New filter() and flatmap() methods on Strategy for better ways of building\n  strategies out of other strategies.\n* New BasicStrategy class which allows you to define your own strategies from\n  scratch without needing an existing matching strategy or being exposed to the\n  full horror or non-public nature of the SearchStrategy interface.\n\n\n.. _v1.0.0:\n\n------------------\n1.0.0 - 2015-03-27\n------------------\n\nCodename: Blast-off!\n\nThere are no code changes in this release. This is precisely the 0.9.2 release\nwith some updated documentation.\n\n.. _v0.9.2:\n\n------------------\n0.9.2 - 2015-03-26\n------------------\n\nCodename: T-1 days.\n\n* floats_in_range would not actually have produced floats_in_range unless that\n  range happened to be (0, 1). Fix this.\n\n.. _v0.9.1:\n\n------------------\n0.9.1 - 2015-03-25\n------------------\n\nCodename: T-2 days.\n\n* Fix a bug where if you defined a strategy using map on a lambda then the results would not be saved in the database.\n* Significant performance improvements when simplifying examples using lists, strings or bounded integer ranges.\n\n.. _v0.9.0:\n\n------------------\n0.9.0 - 2015-03-23\n------------------\n\nCodename: The final countdown\n\nThis release could also be called 1.0-RC1.\n\nIt contains a teeny tiny bugfix, but the real point of this release is to declare\nfeature freeze. There will be zero functionality changes between 0.9.0 and 1.0 unless\nsomething goes really really wrong. No new features will be added, no breaking API changes\nwill occur, etc. This is the final shakedown before I declare Hypothesis stable and ready\nto use and throw a party to celebrate.\n\nBug bounty for any bugs found between now and 1.0: I will buy you a drink (alcoholic,\ncaffeinated, or otherwise) and shake your hand should we ever find ourselves in the\nsame city at the same time.\n\nThe one tiny bugfix:\n\n* Under pypy, databases would fail to close correctly when garbage collected, leading to a memory leak and a confusing error message if you were repeatedly creating databases and not closing them. It is very unlikely you were doing this and the chances of you ever having noticed this bug are very low.\n\n.. _v0.7.2:\n\n------------------\n0.7.2 - 2015-03-22\n------------------\n\nCodename: Hygienic macros or bust\n\n* You can now name an argument to @given 'f' and it won't break (:issue:`38`)\n* strategy_test_suite is now named strategy_test_suite as the documentation claims and not in fact strategy_test_suitee\n* Settings objects can now be used as a context manager to temporarily override the default values inside their context.\n\n\n.. _v0.7.1:\n\n------------------\n0.7.1 - 2015-03-21\n------------------\n\nCodename: Point releases go faster\n\n* Better string generation by parametrizing by a limited alphabet\n* Faster string simplification - previously if simplifying a string with high range unicode characters it would try every unicode character smaller than that. This was pretty pointless. Now it stops after it's a short range (it can still reach smaller ones through recursive calls because of other simplifying operations).\n* Faster list simplification by first trying a binary chop down the middle\n* Simultaneous simplification of identical elements in a list. So if a bug only triggers when you have duplicates but you drew e.g. [-17, -17], this will now simplify to [0, 0].\n\n\n.. _v0.7.0,:\n\n-------------------\n0.7.0, - 2015-03-20\n-------------------\n\nCodename: Starting to look suspiciously real\n\nThis is probably the last minor release prior to 1.0. It consists of stability\nimprovements, a few usability things designed to make Hypothesis easier to try\nout, and filing off some final rough edges from the API.\n\n* Significant speed and memory usage improvements\n* Add an example() method to strategy objects to give an example of the sort of data that the strategy generates.\n* Remove .descriptor attribute of strategies\n* Rename descriptor_test_suite to strategy_test_suite\n* Rename the few remaining uses of descriptor to specifier (descriptor already has a defined meaning in Python)\n\n\n.. _v0.6.0:\n\n---------------------------------------------------------\n0.6.0 - 2015-03-13\n---------------------------------------------------------\n\nCodename: I'm sorry, were you using that API?\n\nThis is primarily a \"simplify all the weird bits of the API\" release. As a result there are a lot of breaking changes. If\nyou just use @given with core types then you're probably fine.\n\nIn particular:\n\n* Stateful testing has been removed from the API\n* The way the database is used has been rendered less useful (sorry). The feature for reassembling values saved from other\n  tests doesn't currently work. This will probably be brought back in post 1.0.\n* SpecificationMapper is no longer a thing. Instead there is an ExtMethod called strategy which you extend to specify how\n  to convert other types to strategies.\n* Settings are now extensible so you can add your own for configuring a strategy\n* MappedSearchStrategy no longer needs an unpack method\n* Basically all the SearchStrategy internals have changed massively. If you implemented SearchStrategy directly rather than\n  using MappedSearchStrategy talk to me about fixing it.\n* Change to the way extra packages work. You now specify the package. This\n  must have a load() method. Additionally any modules in the package will be\n  loaded in under hypothesis.extra\n\nBug fixes:\n\n* Fix for a bug where calling falsify on a lambda with a non-ascii character\n  in its body would error.\n\nHypothesis Extra:\n\nhypothesis-fakefactory\\: An extension for using faker data in hypothesis. Depends\n    on fake-factory.\n\n.. _v0.5.0:\n\n------------------\n0.5.0 - 2015-02-10\n------------------\n\nCodename: Read all about it.\n\nCore hypothesis:\n\n* Add support back in for pypy and python 3.2\n* @given functions can now be invoked with some arguments explicitly provided. If all arguments that hypothesis would have provided are passed in then no falsification is run.\n* Related to the above, this means that you can now use pytest fixtures and mark.parametrize with Hypothesis without either interfering with the other.\n* Breaking change: @given no longer works for functions with varargs (varkwargs are fine). This might be added back in at a later date.\n* Windows is now fully supported. A limited version (just the tests with none of the extras) of the test suite is run on windows with each commit so it is now a first class citizen of the Hypothesis world.\n* Fix a bug for fuzzy equality of equal complex numbers with different reprs (this can happen when one coordinate is zero). This shouldn't affect users - that feature isn't used anywhere public facing.\n* Fix generation of floats on windows and 32-bit builds of python. I was using some struct.pack logic that only worked on certain word sizes.\n* When a test times out and hasn't produced enough examples this now raises a Timeout subclass of Unfalsifiable.\n* Small search spaces are better supported. Previously something like a @given(bool, bool) would have failed because it couldn't find enough examples. Hypothesis is now aware of the fact that these are small search spaces and will not error in this case.\n* Improvements to parameter search in the case of hard to satisfy assume. Hypothesis will now spend less time exploring parameters that are unlikely to provide anything useful.\n* Increase chance of generating \"nasty\" floats\n* Fix a bug that would have caused unicode warnings if you had a sampled_from that was mixing unicode and byte strings.\n* Added a standard test suite that you can use to validate a custom strategy you've defined is working correctly.\n\nHypothesis extra:\n\nFirst off, introducing Hypothesis extra packages!\n\nThese are packages that are separated out from core Hypothesis because they have one or more dependencies. Every\nhypothesis-extra package is pinned to a specific point release of Hypothesis and will have some version requirements\non its dependency. They use entry_points so you will usually not need to explicitly import them, just have them installed\non the path.\n\nThis release introduces two of them:\n\nhypothesis-datetime:\n\nDoes what it says on the tin: Generates datetimes for Hypothesis. Just install the package and datetime support will start\nworking.\n\nDepends on pytz for timezone support\n\nhypothesis-pytest:\n\nA very rudimentary pytest plugin. All it does right now is hook the display of falsifying examples into pytest reporting.\n\nDepends on pytest.\n\n\n.. _v0.4.3:\n\n------------------\n0.4.3 - 2015-02-05\n------------------\n\nCodename: TIL narrow Python builds are a thing\n\nThis just fixes the one bug.\n\n* Apparently there is such a thing as a \"narrow python build\" and OS X ships with these by default\n  for python 2.7. These are builds where you only have two bytes worth of unicode. As a result,\n  generating unicode was completely broken on OS X. Fix this by only generating unicode codepoints\n  in the range supported by the system.\n\n\n.. _v0.4.2:\n\n------------------\n0.4.2 - 2015-02-04\n------------------\n\nCodename: O(dear)\n\nThis is purely a bugfix release:\n\n* Provide sensible external hashing for all core types. This will significantly improve\n  performance of tracking seen examples which happens in literally every falsification\n  run. For Hypothesis fixing this cut 40% off the runtime of the test suite. The behaviour\n  is quadratic in the number of examples so if you're running the default configuration\n  this will be less extreme (Hypothesis's test suite runs at a higher number of examples\n  than default), but you should still see a significant improvement.\n* Fix a bug in formatting of complex numbers where the string could get incorrectly truncated.\n\n\n.. _v0.4.1:\n\n------------------\n0.4.1 - 2015-02-03\n------------------\n\nCodename: Cruel and unusual edge cases\n\nThis release is mostly about better test case generation.\n\nEnhancements:\n\n* Has a cool release name\n* text_type (str in python 3, unicode in python 2) example generation now\n  actually produces interesting unicode instead of boring ascii strings.\n* floating point numbers are generated over a much wider range, with particular\n  attention paid to generating nasty numbers - nan, infinity, large and small\n  values, etc.\n* examples can be generated using pieces of examples previously saved in the\n  database. This allows interesting behaviour that has previously been discovered\n  to be propagated to other examples.\n* improved parameter exploration algorithm which should allow it to more reliably\n  hit interesting edge cases.\n* Timeout can now be disabled entirely by setting it to any value <= 0.\n\n\nBug fixes:\n\n* The descriptor on a OneOfStrategy could be wrong if you had descriptors which\n  were equal but should not be coalesced. e.g. a strategy for one_of((frozenset({int}), {int}))\n  would have reported its descriptor as {int}. This is unlikely to have caused you\n  any problems\n* If you had strategies that could produce NaN (which float previously couldn't but\n  e.g. a Just(float('nan')) could) then this would have sent hypothesis into an infinite\n  loop that would have only been terminated when it hit the timeout.\n* Given elements that can take a long time to minimize, minimization of floats or tuples\n  could be quadratic or worse in the that value. You should now see much better performance\n  for simplification, albeit at some cost in quality.\n\nOther:\n\n* A lot of internals have been rewritten. This shouldn't affect you at all, but\n  it opens the way for certain of hypothesis's oddities to be a lot more extensible by\n  users. Whether this is a good thing may be up for debate...\n\n\n.. _v0.4.0:\n\n------------------\n0.4.0 - 2015-01-21\n------------------\n\nFLAGSHIP FEATURE: Hypothesis now persists examples for later use. It stores\ndata in a local SQLite database and will reuse it for all tests of the same\ntype.\n\nLICENSING CHANGE: Hypothesis is now released under the Mozilla Public License\n2.0. This applies to all versions from 0.4.0 onwards until further notice.\nThe previous license remains applicable to all code prior to 0.4.0.\n\nEnhancements:\n\n* Printing of failing examples. I was finding that the pytest runner was not\n  doing a good job of displaying these, and that Hypothesis itself could do\n  much better.\n* Drop dependency on six for cross-version compatibility. It was easy\n  enough to write the shim for the small set of features that we care about\n  and this lets us avoid a moderately complex dependency.\n* Some improvements to statistical distribution of selecting from small (<=\n  3 elements)\n* Improvements to parameter selection for finding examples.\n\nBugs fixed:\n\n* could_have_produced for lists, dicts and other collections would not have\n  examined the elements and thus when using a union of different types of\n  list this could result in Hypothesis getting confused and passing a value\n  to the wrong strategy. This could potentially result in exceptions being\n  thrown from within simplification.\n* sampled_from would not work correctly on a single element list.\n* Hypothesis could get *very* confused by values which are\n  equal despite having different types being used in descriptors. Hypothesis\n  now has its own more specific version of equality it uses for descriptors\n  and tracking. It is always more fine grained than Python equality: Things\n  considered != are not considered equal by hypothesis, but some things that\n  are considered == are distinguished. If your test suite uses both frozenset\n  and set tests this bug is probably affecting you.\n\n.. _v0.3.2:\n\n------------------\n0.3.2 - 2015-01-16\n------------------\n\n* Fix a bug where if you specified floats_in_range with integer arguments\n  Hypothesis would error in example simplification.\n* Improve the statistical distribution of the floats you get for the\n  floats_in_range strategy. I'm not sure whether this will affect users in\n  practice but it took my tests for various conditions from flaky to rock\n  solid so it at the very least improves discovery of the artificial cases\n  I'm looking for.\n* Improved repr() for strategies and RandomWithSeed instances.\n* Add detection for flaky test cases where hypothesis managed to find an\n  example which breaks it but on the final invocation of the test it does\n  not raise an error. This will typically happen with too much recursion\n  errors but could conceivably happen in other circumstances too.\n* Provide a \"derandomized\" mode. This allows you to run hypothesis with\n  zero real randomization, making your build nice and deterministic. The\n  tests run with a seed calculated from the function they're testing so you\n  should still get a good distribution of test cases.\n* Add a mechanism for more conveniently defining tests which just sample\n  from some collection.\n* Fix for a really subtle bug deep in the internals of the strategy table.\n  In some circumstances if you were to define instance strategies for both\n  a parent class and one or more of its subclasses you would under some\n  circumstances get the strategy for the wrong superclass of an instance.\n  It is very unlikely anyone has ever encountered this in the wild, but it\n  is conceivably possible given that a mix of namedtuple and tuple are used\n  fairly extensively inside hypothesis which do exhibit this pattern of\n  strategy.\n\n\n.. _v0.3.1:\n\n------------------\n0.3.1 - 2015-01-13\n------------------\n\n* Support for generation of frozenset and Random values\n* Correct handling of the case where a called function mutates it argument.\n  This involved introducing a notion of a strategies knowing how to copy\n  their argument. The default method should be entirely acceptable and the\n  worst case is that it will continue to have the old behaviour if you\n  don't mark your strategy as mutable, so this shouldn't break anything.\n* Fix for a bug where some strategies did not correctly implement\n  could_have_produced. It is very unlikely that any of these would have\n  been seen in the wild, and the consequences if they had been would have\n  been minor.\n* Re-export the @given decorator from the main hypothesis namespace. It's\n  still available at the old location too.\n* Minor performance optimisation for simplifying long lists.\n\n\n.. _v0.3.0:\n\n------------------\n0.3.0 - 2015-01-12\n------------------\n\n* Complete redesign of the data generation system. Extreme breaking change\n  for anyone who was previously writing their own SearchStrategy\n  implementations. These will not work any more and you'll need to modify\n  them.\n* New settings system allowing more global and modular control of Verifier\n  behaviour.\n* Decouple SearchStrategy from the StrategyTable. This leads to much more\n  composable code which is a lot easier to understand.\n* A significant amount of internal API renaming and moving. This may also\n  break your code.\n* Expanded available descriptors, allowing for generating integers or\n  floats in a specific range.\n* Significantly more robust. A very large number of small bug fixes, none\n  of which anyone is likely to have ever noticed.\n* Deprecation of support for pypy and python 3 prior to 3.3. 3.3 and 3.4.\n  Supported versions are 2.7.x, 3.3.x, 3.4.x. I expect all of these to\n  remain officially supported for a very long time. I would not be\n  surprised to add pypy support back in later but I'm not going to do so\n  until I know someone cares about it. In the meantime it will probably\n  still work.\n\n\n.. _v0.2.2:\n\n------------------\n0.2.2 - 2015-01-08\n------------------\n\n* Fix an embarrassing complete failure of the installer caused by my being\n  bad at version control\n\n\n.. _v0.2.1:\n\n------------------\n0.2.1 - 2015-01-07\n------------------\n\n* Fix a bug in the new stateful testing feature where you could make\n  __init__ a @requires method. Simplification would not always work if the\n  prune method was able to successfully shrink the test.\n\n\n.. _v0.2.0:\n\n------------------\n0.2.0 - 2015-01-07\n------------------\n\n* It's aliiive.\n* Improve python 3 support using six.\n* Distinguish between byte and unicode types.\n* Fix issues where FloatStrategy could raise.\n* Allow stateful testing to request constructor args.\n* Fix for issue where test annotations would timeout based on when the\n  module was loaded instead of when the test started\n\n\n.. _v0.1.4:\n\n------------------\n0.1.4 - 2013-12-14\n------------------\n\n* Make verification runs time bounded with a configurable timeout\n\n\n.. _v0.1.3:\n\n------------------\n0.1.3 - 2013-05-03\n------------------\n\n* Bugfix: Stateful testing behaved incorrectly with subclassing.\n* Complex number support\n* support for recursive strategies\n* different error for hypotheses with unsatisfiable assumptions\n\n.. _v0.1.2:\n\n------------------\n0.1.2 - 2013-03-24\n------------------\n\n* Bugfix: Stateful testing was not minimizing correctly and could\n  throw exceptions.\n* Better support for recursive strategies.\n* Support for named tuples.\n* Much faster integer generation.\n\n\n.. _v0.1.1:\n\n------------------\n0.1.1 - 2013-03-24\n------------------\n\n* Python 3.x support via 2to3.\n* Use new style classes (oops).\n\n\n.. _v0.1.0:\n\n------------------\n0.1.0 - 2013-03-23\n------------------\n\n* Introduce stateful testing.\n* Massive rewrite of internals to add flags and strategies.\n\n\n.. _v0.0.5:\n\n------------------\n0.0.5 - 2013-03-13\n------------------\n\n* No changes except trying to fix packaging\n\n.. _v0.0.4:\n\n------------------\n0.0.4 - 2013-03-13\n------------------\n\n* No changes except that I checked in a failing test case for 0.0.3\n  so had to replace the release. Doh\n\n.. _v0.0.3:\n\n------------------\n0.0.3 - 2013-03-13\n------------------\n\n* Improved a few internals.\n* Opened up creating generators from instances as a general API.\n* Test integration.\n\n.. _v0.0.2:\n\n------------------\n0.0.2 - 2013-03-12\n------------------\n\n* Starting to tighten up on the internals.\n* Change API to allow more flexibility in configuration.\n* More testing.\n\n.. _v0.0.1:\n\n------------------\n0.0.1 - 2013-03-10\n------------------\n\n* Initial release.\n* Basic working prototype. Demonstrates idea, probably shouldn't be used.\n"
  },
  {
    "path": "hypothesis-python/docs/community.rst",
    "content": "=========\nCommunity\n=========\n\nThe Hypothesis community is full of excellent people who can answer your questions and help you out. Please do join us:\n\n* You can post a question on Stack Overflow using the `python-hypothesis <https://stackoverflow.com/questions/tagged/python-hypothesis>`__ tag.\n* We also have `a mailing list <https://groups.google.com/forum/#!forum/hypothesis-users>`_. Feel free to use it to ask for help, provide feedback, or discuss anything remotely Hypothesis related at all.\n\nNote that the :gh-file:`Hypothesis code of conduct <.github/CODE_OF_CONDUCT.rst>` applies in all Hypothesis community spaces!\n\nIf you would like to cite Hypothesis, please consider :gh-file:`our suggested citation <CITATION.cff>`.\n\nIf you like repo badges, we suggest the following badge, which you can add with Markdown or reStructuredText respectively:\n\n.. image:: https://img.shields.io/badge/hypothesis-tested-brightgreen.svg\n\n.. code:: md\n\n    [![Tested with Hypothesis](https://img.shields.io/badge/hypothesis-tested-brightgreen.svg)](https://hypothesis.readthedocs.io/)\n\n.. code:: restructuredtext\n\n    .. image:: https://img.shields.io/badge/hypothesis-tested-brightgreen.svg\n       :alt: Tested with Hypothesis\n       :target: https://hypothesis.readthedocs.io\n\nFinally, we have a beautiful logo which appears online, and often on stickers:\n\n.. image:: ../../brand/dragonfly-rainbow.svg\n   :alt: The Hypothesis logo, a dragonfly with rainbow wings\n   :align: center\n   :width: 50 %\n\nAs well as being beautiful, dragonflies actively hunt down bugs for a living!\nYou can find the images and a usage guide in the :gh-file:`brand` directory on\nGitHub, or find us at conferences where we often have stickers and sometimes\nother swag.\n"
  },
  {
    "path": "hypothesis-python/docs/compatibility.rst",
    "content": "Compatibility\n=============\n\nHypothesis generally does its level best to be compatible with everything you could need it to be compatible with. This document outlines our compatibility status and guarantees.\n\nHypothesis versions\n-------------------\n\nBackwards compatibility is better than backporting fixes, so we use\n:ref:`semantic versioning <release-policy>` and only support the most recent\nversion of Hypothesis.\n\nDocumented APIs will not break except between major version bumps.\nAll APIs mentioned in the Hypothesis documentation are public unless explicitly\nnoted as provisional, in which case they may be changed in minor releases.\nUndocumented attributes, modules, and behaviour may include breaking\nchanges in patch releases.\n\n\n.. _deprecation-policy:\n\nDeprecations\n------------\n\nDeprecated features will emit |HypothesisDeprecationWarning| for at least six months, and then be removed in the following major release.\n\nNote however that not all warnings are subject to this grace period; sometimes we strengthen validation by adding a warning, and these may become errors immediately at a major release.\n\nWe use custom exception and warning types, so you can see exactly where an error came from, or turn only our warnings into errors.\n\nPython versions\n---------------\n\nHypothesis is supported and tested on CPython and PyPy 3.10+, i.e. all Python versions `that are still supported <https://devguide.python.org/versions/>`_.\n32-bit builds of CPython also work, though we only test them on Windows.\n\nHypothesis does not officially support anything except the latest patch release of each supported Python version. We will fix bugs in earlier patch releases if reported, but they're not tested in CI and no guarantees are made.\n\nOperating systems\n-----------------\n\nIn theory, Hypothesis should work anywhere that Python does. In practice, it is\nknown to work and regularly tested on macOS, Windows, Linux, and `Emscripten <https://peps.python.org/pep-0776/>`_.\n\nIf you experience issues running Hypothesis on other operating systems, we are\nhappy to accept bug reports which either clearly point to the problem or contain\nreproducing instructions for a Hypothesis maintainer who does not have the ability\nto run that OS. It's hard to fix something we can't reproduce!\n\n.. _framework-compatibility:\n\nTesting frameworks\n------------------\n\nIn general, Hypothesis goes to quite a lot of effort to return a function from |@given| that behaves as closely to a normal test function as possible. This means that most things should work sensibly with most testing frameworks.\n\nMaintainers of testing frameworks may be interested in our support for :ref:`custom function execution <custom-function-execution>`, which may make some Hypothesis interactions possible to support.\n\npytest\n~~~~~~\n\nThe main interaction to be aware of between Hypothesis and :pypi:`pytest` is fixtures.\n\npytest fixtures are automatically passed to |@given| tests, as usual. Note that |@given| supplies parameters from the right, so tests which use a fixture should either be written with the fixture placed first, or with keyword arguments:\n\n.. code-block:: python\n\n  @given(st.integers())\n  def test_use_fixture(myfixture, n):\n      pass\n\n  @given(n=st.integers())\n  def test_use_fixture(n, myfixture):\n      pass\n\nHowever, function-scoped fixtures run only once for the entire test, not per-input. This can be surprising for fixtures which are expected to set up per-input state. To proactively warn about this, we raise |HealthCheck.function_scoped_fixture| (unless suppressed with |settings.suppress_health_check|).\n\nCombining |@given| and |pytest.mark.parametrize| is fully supported, again keeping in mind that |@given| supplies parameters from the right:\n\n.. code-block:: python\n\n  @pytest.mark.parametrize(\"s\", [\"a\", \"b\", \"c\"])\n  @given(st.integers())\n  def test_use_parametrize(s, n):\n      assert isinstance(s, str)\n      assert isinstance(n, int)\n\nunittest\n~~~~~~~~\n\n:pypi:`unittest` works out of the box with Hypothesis.\n\nThe :func:`python:unittest.mock.patch` decorator works with |@given|, but we recommend using it as a context manager within the test instead, to ensure that the mock is per-input, and to avoid poor interactions with Pytest fixtures.\n\n:meth:`unittest.TestCase.subTest` is a no-op under Hypothesis, because it interacts poorly with Hypothesis generating hundreds of inputs at a time.\n\nDjango\n~~~~~~\n\nIntegration with Django's testing requires use of the :ref:`hypothesis-django` extra. The issue is that Django tests reset the database once per test, rather than once per input.\n\n:pypi:`pytest-django` doesn't yet implement Hypothesis compatibility. You can follow issue `pytest-django#912 <https://github.com/pytest-dev/pytest-django/issues/912>`_ for updates.\n\ncoverage.py\n~~~~~~~~~~~\n\n:pypi:`coverage` works out of the box with Hypothesis. Our own test suite has 100% branch coverage.\n\nHypoFuzz\n~~~~~~~~\n\n`HypoFuzz <https://hypofuzz.com/>`_ is built on top of Hypothesis and has native support for it. See also the ``hypofuzz`` |alternative backend|.\n\nOptional packages\n-----------------\n\nThe supported versions of optional packages, for strategies in ``hypothesis.extra``,\nare listed in the documentation for that extra.  Our general goal is to support\nall versions that are supported upstream.\n\n\n.. _thread-safety-policy:\n\nThread-Safety Policy\n--------------------\n\nAs of :version:`6.136.9`, Hypothesis is thread-safe. Each of the following is fully supported, and tested regularly in CI:\n\n* Running tests in multiple processes\n* Running separate tests in multiple threads\n* Running the same test in multiple threads\n\nIf you find a bug here, please report it. The main risks internally are global state, shared caches, and cached strategies.\n\nThread usage inside tests\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. TODO_DOCS: link to not-yet-merged flaky failure tutorial page\n\nTests that spawn threads internally are supported by Hypothesis.\n\nHowever, these as with any Hypothesis test, these tests must have deterministic test outcomes and data generation. For example, if timing changes in the threads change the sequence of dynamic draws from |st.composite| or |st.data|, Hypothesis may report the test as flaky. The solution here is to refactor data generation so it does not depend on test timings.\n\nCross-thread API calls\n~~~~~~~~~~~~~~~~~~~~~~\n\nIn theory, Hypothesis supports cross-thread API calls, for instance spawning a thread inside of a test and using that to draw from |st.composite| or |st.data|, or to call |event|, |target|, or |assume|.\n\nHowever, we have not explicitly audited this behavior, and do not regularly test it in our CI. If you find a bug here, please report it. If our investigation determines that we cannot support cross-thread calls for the feature in question, we will update this page accordingly.\n\nType hints\n----------\n\nWe ship type hints with Hypothesis itself. Though we always try to minimize breakage, we may make breaking changes to these between minor releases and do not commit to maintaining a fully stable interface for type hints.\n\nWe may also find more precise ways to describe the type of various interfaces, or change their type and runtime behaviour together in a way which is otherwise backwards-compatible.\n\nThere are known issues with inferring the type of examples generated by |st.deferred|, |st.recursive|, |st.one_of|, |st.dictionaries|, and |st.fixed_dictionaries|. We're following proposed updates to Python's typing standards, but unfortunately the long-standing interfaces of these strategies cannot (yet) be statically typechecked.\n"
  },
  {
    "path": "hypothesis-python/docs/conf.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport datetime\nimport re\nimport sys\nimport types\nfrom pathlib import Path\n\nfrom docutils import nodes\nfrom sphinx.util.docutils import SphinxRole\n\nroot = Path(__file__).parent.parent\n# insert so the local versions are consulted first, before any installed version\nsys.path.insert(0, str(root / \"src\"))\nsys.path.insert(0, str(Path(__file__).parent / \"_ext\"))\n\nneeds_sphinx = re.search(\n    r\"sphinx==([0-9\\.]+)\", root.joinpath(\"../requirements/tools.txt\").read_text()\n).group(1)\ndefault_role = \"py:obj\"\nnitpicky = True\n\nautodoc_member_order = \"bysource\"\nautodoc_typehints = \"none\"\nmaximum_signature_line_length = 60  # either one line, or one param per line\n\nextensions = [\n    \"sphinx.ext.autodoc\",\n    \"sphinx.ext.extlinks\",\n    \"sphinx.ext.viewcode\",\n    \"sphinx.ext.intersphinx\",\n    \"sphinx.ext.napoleon\",\n    \"sphinx_codeautolink\",\n    \"sphinx_selective_exclude.eager_only\",\n    \"sphinx-jsonschema\",\n    # loading this extension overrides the default -b linkcheck behavior with\n    # custom url ignore logic. see hypothesis_linkcheck.py for details.\n    \"hypothesis_linkcheck\",\n    \"hypothesis_redirects\",\n]\n\ntemplates_path = [\"_templates\"]\n\n# config for hypothesis_redirects\nredirects = {\n    \"details\": \"reference/index.html\",\n    \"data\": \"reference/strategies.html\",\n    \"database\": \"reference/api.html#database\",\n    # \"stateful\": \"reference/api.html#stateful-tests\",\n    \"reproducing\": \"reference/api.html\",\n    \"ghostwriter\": \"reference/integrations.html#ghostwriter\",\n    \"django\": \"reference/strategies.html#django\",\n    \"numpy\": \"reference/strategies.html#numpy\",\n    \"observability\": \"reference/integrations.html#observability\",\n    \"settings\": \"reference/api.html#settings\",\n    \"endorsements\": \"usage.html#testimonials\",\n    # TODO enable when we actually rename them\n    # \"extras\": \"extensions.html\",\n    \"supported\": \"compatibility.html\",\n    \"changes\": \"changelog.html\",\n    \"strategies\": \"extensions.html\",\n    # these pages were removed without replacement\n    \"support\": \"index.html\",\n    \"manifesto\": \"index.html\",\n    \"examples\": \"index.html\",\n}\nredirect_html_template_file = \"redirect.html.template\"\n\nsource_suffix = \".rst\"\n\n# The master toctree document.\nmaster_doc = \"index\"\n\n# General information about the project.\nproject = \"Hypothesis\"\nauthor = \"the Hypothesis team\"\ncopyright = f\"2013-{datetime.date.today().year}, {author}\"\n\n_d = {}\n_version_file = root.joinpath(\"src\", \"hypothesis\", \"version.py\")\nexec(_version_file.read_text(encoding=\"utf-8\"), _d)\nversion = _d[\"__version__\"]\nrelease = _d[\"__version__\"]\n\n\n# custom role for version syntaxes.\n# :v:`6.131.0`       = [v6.131.0](changelog.html#v6.13.0)\n# :version:`6.131.0` = [version 6.131.0](changelog.html#v6.13.0)\nclass VersionRole(SphinxRole):\n    def __init__(self, prefix):\n        self.prefix = prefix\n\n    def run(self):\n        node = nodes.reference(\n            \"\",\n            f\"{self.prefix}{self.text}\",\n            refuri=f\"changelog.html#v{self.text.replace('.', '-')}\",\n        )\n        return [node], []\n\n\ndef setup(app):\n    if root.joinpath(\"RELEASE.rst\").is_file():\n        app.tags.add(\"has_release_file\")\n\n    # Workaround for partial-initialization problem when autodoc imports libcst\n    import libcst\n\n    import hypothesis.extra.codemods\n\n    assert libcst\n    assert hypothesis.extra.codemods\n\n    # patch in mock array_api namespace so we can autodoc it\n    from hypothesis.extra.array_api import (\n        RELEASED_VERSIONS,\n        make_strategies_namespace,\n        mock_xp,\n    )\n\n    mod = types.ModuleType(\"xps\")\n    mod.__dict__.update(\n        make_strategies_namespace(mock_xp, api_version=RELEASED_VERSIONS[-1]).__dict__\n    )\n    assert \"xps\" not in sys.modules\n    sys.modules[\"xps\"] = mod\n\n    def process_signature(app, what, name, obj, options, signature, return_annotation):\n        # manually override an ugly signature from .. autofunction. Alternative we\n        # could manually document with `.. function:: run_conformance_test(...)`,\n        # but that's less likely to stay up to date.\n        if (\n            name\n            == \"hypothesis.internal.conjecture.provider_conformance.run_conformance_test\"\n        ):\n            # so we know if this ever becomes obsolete\n            assert \"_realize_objects\" in signature\n            signature = re.sub(\n                r\"_realize_objects=.*\",\n                \"_realize_objects=st.from_type(object) | st.from_type(type).flatmap(st.from_type))\",\n                signature,\n            )\n        return signature, return_annotation\n\n    app.connect(\"autodoc-process-signature\", process_signature)\n    app.add_role(\"v\", VersionRole(prefix=\"v\"))\n    app.add_role(\"version\", VersionRole(prefix=\"version \"))\n\n\nlanguage = \"en\"\nexclude_patterns = [\"_build\", \"prolog.rst\"]\npygments_style = \"sphinx\"\ntodo_include_todos = False\n\n# To run linkcheck (last argument is the output dir)\n#   sphinx-build --builder linkcheck hypothesis-python/docs linkcheck\nlinkcheck_ignore = [\n    # we'll assume that python isn't going to break peps, and github isn't going\n    # to break issues/pulls. (and if they did, we'd hopefully notice quickly).\n    r\"https://peps.python.org/pep-.*\",\n    r\"https://github.com/HypothesisWorks/hypothesis/issues/\\d+\",\n    r\"https://github.com/HypothesisWorks/hypothesis/pull/\\d+\",\n]\n\nintersphinx_mapping = {\n    \"python\": (\"https://docs.python.org/3/\", None),\n    \"numpy\": (\"https://numpy.org/doc/stable/\", None),\n    \"pandas\": (\"https://pandas.pydata.org/docs/\", None),\n    \"pytest\": (\"https://docs.pytest.org/en/stable/\", None),\n    \"django\": (\n        \"http://docs.djangoproject.com/en/stable/\",\n        \"http://docs.djangoproject.com/en/stable/_objects/\",\n    ),\n    \"dateutil\": (\"https://dateutil.readthedocs.io/en/stable/\", None),\n    \"redis\": (\"https://redis.readthedocs.io/en/stable/\", None),\n    \"attrs\": (\"https://www.attrs.org/en/stable/\", None),\n    \"sphinx\": (\"https://www.sphinx-doc.org/en/master/\", None),\n    \"IPython\": (\"https://ipython.readthedocs.io/en/stable/\", None),\n    \"lark\": (\"https://lark-parser.readthedocs.io/en/stable/\", None),\n    \"xarray\": (\"https://docs.xarray.dev/en/stable/\", None),\n}\n\nautodoc_mock_imports = [\"numpy\", \"pandas\", \"redis\", \"django\", \"pytz\"]\n\nrst_prolog = (Path(__file__).parent / \"prolog.rst\").read_text()\n\ncodeautolink_autodoc_inject = False\ncodeautolink_global_preface = \"\"\"\nfrom hypothesis import *\nimport hypothesis.strategies as st\nfrom hypothesis.strategies import *\n\"\"\"\n\n# This config value must be a dictionary of external sites, mapping unique\n# short alias names to a base URL and a prefix.\n# See http://sphinx-doc.org/ext/extlinks.html\n_repo = \"https://github.com/HypothesisWorks/hypothesis/\"\nextlinks = {\n    \"commit\": (_repo + \"commit/%s\", \"commit %s\"),\n    \"gh-file\": (_repo + \"blob/master/%s\", \"%s\"),\n    \"gh-link\": (_repo + \"%s\", \"%s\"),\n    \"issue\": (_repo + \"issues/%s\", \"issue #%s\"),\n    \"pull\": (_repo + \"pull/%s\", \"pull request #%s\"),\n    \"pypi\": (\"https://pypi.org/project/%s/\", \"%s\"),\n    \"bpo\": (\"https://bugs.python.org/issue%s\", \"bpo-%s\"),\n    \"xp-ref\": (\"https://data-apis.org/array-api/latest/API_specification/%s\", \"%s\"),\n    \"wikipedia\": (\"https://en.wikipedia.org/wiki/%s\", \"%s\"),\n}\n\n# -- Options for HTML output ----------------------------------------------\n\nhtml_theme = \"furo\"\n# remove \"Hypothesis <version> documentation\" from just below logo on the sidebar\nhtml_theme_options = {\"sidebar_hide_name\": True}\nhtml_static_path = [\"_static\"]\nhtml_css_files = [\n    \"better-signatures.css\",\n    \"wrap-in-tables.css\",\n    \"no-scroll.css\",\n    \"dark-fix.css\",\n]\nhtmlhelp_basename = \"Hypothesisdoc\"\nhtml_favicon = \"../../brand/favicon.ico\"\nhtml_logo = \"../../brand/dragonfly-rainbow-150w.svg\"\n\n\n# -- Options for LaTeX output ---------------------------------------------\n\nlatex_elements = {}\nlatex_documents = [\n    (master_doc, \"Hypothesis.tex\", \"Hypothesis Documentation\", author, \"manual\")\n]\nman_pages = [(master_doc, \"hypothesis\", \"Hypothesis Documentation\", [author], 1)]\ntexinfo_documents = [\n    (\n        master_doc,\n        \"Hypothesis\",\n        \"Hypothesis Documentation\",\n        author,\n        \"Hypothesis\",\n        \"Advanced property-based testing for Python.\",\n        \"Miscellaneous\",\n    )\n]\n"
  },
  {
    "path": "hypothesis-python/docs/development.rst",
    "content": "======================\nHypothesis development\n======================\n\nHypothesis development is managed by `David R. MacIver <https://www.drmaciver.com>`_\nand `Zac Hatfield-Dodds <https://zhd.dev>`_, respectively the first author and lead\nmaintainer.\n\n*However*, these roles don't include unpaid feature development on Hypothesis.\nOur roles as leaders of the project are:\n\n1. Helping other people do feature development on Hypothesis\n2. Fixing bugs and other code health issues\n3. Improving documentation\n4. General release management work\n5. Planning the general roadmap of the project\n6. Doing sponsored development on tasks that are too large or in depth for other people to take on\n\nSo all new features must either be sponsored or implemented by someone else.\nThat being said, the maintenance team takes an active role in shepherding pull requests and\nhelping people write a new feature (see :gh-file:`CONTRIBUTING.rst` for\ndetails and :gh-link:`these examples of how the process goes\n<pulls?q=is%3Apr+is%3Amerged+mentored>`). This isn't\n\"patches welcome\", it's \"we will help you write a patch\".\n\n\n.. _release-policy:\n\nRelease policy\n==============\n\nHypothesis releases follow `semantic versioning <https://semver.org/>`_.\n\nWe maintain backwards-compatibility wherever possible, and use deprecation\nwarnings to mark features that have been superseded by a newer alternative.\nIf you want to detect this, you can upgrade warnings to errors using the :mod:`warnings <python:warnings>` module.\n\nWe use a rapid release cycle to ensure users get features and bugfixes as soon as possible. Every change to the Hypothesis source is automatically built and published on PyPI as soon as it's merged into master. `We wrote about this process here <https://hypothesis.works/articles/continuous-releases/>`_.\n\nProject roadmap\n===============\n\nHypothesis does not have a long-term release plan.  We respond to bug reports\nas they are made; new features are released as and when someone volunteers to\nwrite and maintain them.\n"
  },
  {
    "path": "hypothesis-python/docs/explanation/domain.rst",
    "content": "Domain and distribution\n=======================\n\n.. note::\n\n    This page is primarily for users who may be familiar with other property-based testing libraries, and who expect control over the distribution of inputs in Hypothesis, via e.g. a ``scale`` parameter for size or a ``frequency`` parameter for relative probabilities.\n\nHypothesis makes a distinction between the *domain* of a strategy, and the *distribution* of a strategy.\n\nThe *domain* is the set of inputs that should be possible to generate. For instance, in ``lists(integers())``, the domain is lists of integers. For other strategies, particularly those that use |st.composite| or |assume| in their definition, the domain might be more complex.\n\nThe *distribution* is the probability with which different elements in the domain should be generated. For ``lists(integers())``, should Hypothesis generate many small lists? Large lists? More positive or more negative numbers? etc.\n\nHypothesis takes a philosophical stance that while users may be responsible for selecting the domain, the property-based testing library—not the user—should be responsible for selecting the distribution. As an intentional design choice, Hypothesis therefore lets you control the domain of inputs to your test, but not the distribution.\n\nHow should I choose a domain for my test?\n-----------------------------------------\n\nWe recommend using the most-general strategy for your test, so that it can in principle generate any edge case for which the test should pass.  Limiting the size of generated inputs, and especially limiting the variety of inputs, can all too easily exclude the bug-triggering values from consideration - and be the difference between a test which finds the bug, or fails to do so.\n\nSometimes size limits are necessary for performance reasons, but we recommend limiting your strategies only after you've seen *substantial* slowdowns without limits.  Far better to find bugs slowly, than not find them at all - and you can manage performance with the |~settings.phases| or |~settings.max_examples| settings rather than weakening the test.\n\nWhy not let users control the distribution?\n-------------------------------------------\n\nThere are a few reasons Hypothesis doesn't let users control the distribution.\n\n* Humans are pretty bad at choosing bug-finding distributions! Some bugs are \"known unknowns\": you suspected that a part of the codebase was buggy in a particular way. Others are \"unknown unknowns\": you didn't know that a bug was possible until stumbling across it. Humans tend to overtune distributions for the former kind of bug, and not enough for the latter.\n* The ideal strategy distribution depends not only on the codebase, but also on the property being tested. A strategy used in many places may have a good distribution for one property, but not another.\n* The distribution of inputs is a deeply internal implementation detail. We sometimes change strategy distributions, either explicitly, or implicitly from other work on the Hypothesis engine. Exposing this would lock us into a public API that may make improvements to Hypothesis more difficult.\n\nFinally, we think distribution control is better handled with |alternative backends|. If existing backends like ``hypofuzz`` and ``crosshair`` don't suit your needs, you can also write your own. Backends can automatically generalize and adapt to the strategy and property being tested and avoid most of the problems above.\n\nWe're not saying that control over the distribution isn't useful! We occasionally receive requests to expose the distribution in Hypothesis (`e.g. <https://github.com/HypothesisWorks/hypothesis/issues/4205>`__), and users wouldn't be asking for it if it wasn't. However, adding this to the public strategy API would make it easy for users to unknowingly weaken their tests, and would add maintenance overhead to Hypothesis, and so we haven't yet done so.\n\nOkay, but what *is* the distribution?\n-------------------------------------\n\nAn exact answer depends on both the strategy or strategies for the tests, and the code being tested - but we can make some general remarks, starting with \"it's actually really complicated\".\n\nHypothesis' default configuration uses a distribution which is tuned to maximize the chance of finding bugs, in as few executions as possible.  We explicitly *don't* aim for a uniform distribution, nor for a 'realistic' distribution of inputs; Hypothesis' goal is to search the domain for a failing input as efficiently as possible.\n\nThe test case distribution remains an active area of research and development, and we change it whenever we think that would be a net improvement for users.  Today, Hypothesis' default distribution is shaped by a wide variety of techniques and heuristics:\n\n* some are statically designed into strategies - for example, |st.integers| upweights range endpoints, and samples from a mixed distribution over integer bit-widths.\n* some are dynamic features of the engine - like replaying prior examples with subsections of the input 'cloned' or otherwise altered, for bugs which trigger only when different fields have the same value (which is otherwise exponentially unlikely).\n* some vary depending on the code under test - we collect interesting-looking constants from imported source files as seeds for test cases.\n\nAnd as if that wasn't enough, :ref:`alternative backends <alternative-backends>` can radically change the distribution again - for example :pypi:`hypofuzz` uses runtime feedback to modify the distribution of inputs as the test runs, to maximize the rate at which we trigger new behaviors in that particular test and code.  If Hypothesis' defaults aren't strong enough, we recommend trying Hypofuzz!\n"
  },
  {
    "path": "hypothesis-python/docs/explanation/example-count.rst",
    "content": "How many times will Hypothesis run my test?\n===========================================\n\nThis is a trickier question than you might expect. The short answer is \"exactly |max_examples| times\", with the following exceptions:\n\n- Less than |max_examples| times, if Hypothesis exhausts the search space early.\n- More than |max_examples| times, if Hypothesis retries some examples because either:\n\n  - They failed an |assume| or |.filter| condition, or\n  - They were too large to continue generating.\n\n- Either less or more than |max_examples| times, if Hypothesis finds a failing example.\n\nRead on for details.\n\nSearch space exhaustion\n-----------------------\n\nIf Hypothesis detects that there are no more examples left to try, it may stop generating examples before it hits |max_examples|. For example:\n\n.. code-block:: python\n\n    from hypothesis import given, strategies as st\n\n    calls = 0\n\n    @given(st.integers(0, 19))\n    def test_function(n):\n        global calls\n        calls += 1\n\n    test_function()\n    assert calls == 20\n\nThis runs ``test_function`` 20 times, not 100, since there are only 20 unique integers to try.\n\nThe search space tracking in Hypothesis is good, but not perfect. We treat this more as a bonus than something to strive for.\n\n.. TODO_DOCS\n\n.. .. note::\n\n..     Search space tracking uses the :doc:`choice sequence <choice-sequence>` to determine uniqueness of inputs.\n\n|assume| and |.filter|\n----------------------\n\nIf an example fails to satisfy an |assume| or |.filter| condition, Hypothesis will retry generating that example and will not count it towards the |max_examples| limit. For instance:\n\n.. code-block:: python\n\n    from hypothesis import assume, given, strategies as st\n\n    @given(st.integers())\n    def test_function(n):\n        assume(n % 2 == 0)\n\nwill run roughly 200 times, since half of the examples are discarded from the |assume|.\n\nNote that while failing an |assume| triggers an immediate retry of the entire example, Hypothesis will try several times in the same example to satisfy a |.filter| condition. This makes expressing the same condition using |.filter| more efficient than |assume|.\n\nAlso note that even if your code does not explicitly use |assume| or |.filter|, a builtin strategy may still use them and cause retries. We try to directly satisfy conditions where possible instead of relying on rejection sampling, so this should be relatively uncommon.\n\nExamples which are too large\n----------------------------\n\nFor performance reasons, Hypothesis places an internal limit on the size of a single example. If an example exceeds this size limit, we will retry generating it and will not count it towards the |max_examples| limit. (And if we see too many of these large examples, we will raise |HealthCheck.data_too_large|, unless suppressed with |settings.suppress_health_check|).\n\nThe specific value of this size limit is an undocumented implementation detail. The majority of Hypothesis tests do not come close to hitting it.\n\nFailing examples\n----------------\n\nIf Hypothesis finds a failing example, it stops generation early, and may call the test function additional times during the |Phase.shrink| and |Phase.explain| phases. Sometimes, Hypothesis determines that the initial failing example was already as simple as possible, in which case |Phase.shrink| will not result in additional test executions (but |Phase.explain| might).\n\nRegardless of whether Hypothesis runs the test during the shrinking and explain phases, it will always run the minimal failing example one additional time to check for flakiness. For instance, the following trivial test runs with ``n=0`` *twice*, even though it only uses the |Phase.generate| phase:\n\n.. code-block:: python\n\n    from hypothesis import Phase, given, settings, strategies as st\n\n    @given(st.integers())\n    @settings(phases=[Phase.generate])\n    def test_function(n):\n        print(f\"called with {n}\")\n        assert n != 0\n\n    test_function()\n\nThe first execution finds the initial failure with ``n=0``, and the second execution replays ``n=0`` to ensure the failure is not flaky.\n"
  },
  {
    "path": "hypothesis-python/docs/explanation/index.rst",
    "content": "Explanations\n============\n\nThese explanation pages are oriented towards deepening your understanding of Hypothesis, including its design philosophy.\n\n.. toctree::\n   :maxdepth: 1\n\n   domain\n   example-count\n"
  },
  {
    "path": "hypothesis-python/docs/extensions.rst",
    "content": "Third-party extensions\n======================\n\nThere are a number of open-source community libraries that extend Hypothesis. This page lists some of them; you can find more by searching PyPI `by keyword <https://pypi.org/search/?q=hypothesis>`_ or `by framework classifier <https://pypi.org/search/?c=Framework+%3A%3A+Hypothesis>`_.\n\nIf there's something missing which you think should be here, let us know!\n\n.. note::\n    Being listed on this page does not imply that the Hypothesis\n    maintainers endorse a package.\n\nExternal strategies\n-------------------\n\nSome packages provide strategies directly:\n\n* :pypi:`hypothesis-fspaths` - strategy to generate filesystem paths.\n* :pypi:`hypothesis-geojson` - strategy to generate `GeoJson <https://geojson.org/>`_.\n* :pypi:`hypothesis-geometry` - strategies to generate geometric objects.\n* :pypi:`hs-dbus-signature` - strategy to generate arbitrary\n  `D-Bus signatures <https://www.freedesktop.org/wiki/Software/dbus/>`_.\n* :pypi:`hypothesis-sqlalchemy` - strategies to generate :pypi:`SQLAlchemy` objects.\n* :pypi:`hypothesis-ros` - strategies to generate messages and parameters for the `Robot Operating System <https://www.ros.org/>`_.\n* :pypi:`hypothesis-csv` - strategy to generate CSV files.\n* :pypi:`hypothesis-networkx` - strategy to generate :pypi:`networkx` graphs.\n* :pypi:`hypothesis-bio` - strategies for bioinformatics data, such as DNA, codons, FASTA, and FASTQ formats.\n* :pypi:`hypothesis-rdkit` - strategies to generate RDKit molecules and representations such as SMILES and mol blocks\n* :pypi:`hypothesmith` - strategy to generate syntatically-valid Python code.\n* :pypi:`hypothesis-torch` - strategy to generate various `Pytorch <https://pytorch.org/>`_ structures (including tensors and modules).\n\nOthers provide a function to infer a strategy from some other schema:\n\n* :pypi:`hypothesis-jsonschema` - infer strategies from `JSON schemas <https://json-schema.org/>`_.\n* :pypi:`lollipop-hypothesis` - infer strategies from :pypi:`lollipop` schemas.\n* :pypi:`hypothesis-drf` - infer strategies from a :pypi:`djangorestframework` serialiser.\n* :pypi:`hypothesis-graphql` - infer strategies from `GraphQL schemas <https://graphql.org/>`_.\n* :pypi:`hypothesis-mongoengine` - infer strategies from a :pypi:`mongoengine` model.\n* :pypi:`hypothesis-pb` - infer strategies from `Protocol Buffer\n  <https://protobuf.dev/>`_ schemas.\n\nOr some other custom integration, such as a :ref:`\"hypothesis\" entry point <entry-points>`:\n\n* :pypi:`deal` is a design-by-contract library with built-in Hypothesis support.\n* :pypi:`icontract-hypothesis` infers strategies from :pypi:`icontract` code contracts.\n* :pypi:`pandera` schemas all have a ``.strategy()`` method, which returns a strategy for\n  matching :class:`~pandas:pandas.DataFrame`\\ s.\n* :pypi:`Pydantic <pydantic>` automatically registers constrained types - so\n  :func:`~hypothesis.strategies.builds` and :func:`~hypothesis.strategies.from_type`\n  \"just work\" regardless of the underlying implementation.\n\nOther cool things\n-----------------\n\n`Tyche <https://marketplace.visualstudio.com/items?itemName=HarrisonGoldstein.tyche>`__\n(`source <https://github.com/tyche-pbt>`__) is a VSCode extension which provides live\ninsights into your property-based tests, including the distribution of generated inputs\nand the resulting code coverage.  You can `read the research paper here\n<https://harrisongoldste.in/papers/uist23.pdf>`__.\n\n:pypi:`schemathesis` is a tool for testing web applications built with `Open API / Swagger specifications <https://swagger.io/>`_.\nIt reads the schema and generates test cases which will ensure that the application is compliant with its schema.\nThe application under test could be written in any language, the only thing you need is a valid API schema in a supported format.\nIncludes CLI and convenient :pypi:`pytest` integration.\nPowered by Hypothesis and :pypi:`hypothesis-jsonschema`, inspired by the earlier :pypi:`swagger-conformance` library.\n\n`Trio <https://trio.readthedocs.io/>`_ is an async framework with \"an obsessive\nfocus on usability and correctness\", so naturally it works with Hypothesis!\n:pypi:`pytest-trio` includes :ref:`a custom hook <custom-function-execution>`\nthat allows ``@given(...)`` to work with Trio-style async test functions, and\n:pypi:`hypothesis-trio` includes stateful testing extensions to support\nconcurrent programs.\n\n:pypi:`pymtl3` is \"an open-source Python-based hardware generation, simulation,\nand verification framework with multi-level hardware modeling support\", which\nships with Hypothesis integrations to check that all of those levels are\nequivalent, from function-level to register-transfer level and even to hardware.\n\n:pypi:`battle-tested` is a fuzzing tool that will show you how your code can\nfail - by trying all kinds of inputs and reporting whatever happens.\n\n:pypi:`pytest-subtesthack` functions as a workaround for :issue:`377`.\n\n:pypi:`returns` uses Hypothesis to verify that Higher Kinded Types correctly\nimplement functor, applicative, monad, and other laws; allowing a declarative\napproach to be combined with traditional pythonic code.\n\n:pypi:`icontract-hypothesis` includes a :ref:`ghostwriter <ghostwriter>` for test files\nand IDE integrations such as `icontract-hypothesis-vim <https://github.com/mristin/icontract-hypothesis-vim>`_,\n`icontract-hypothesis-pycharm <https://github.com/mristin/icontract-hypothesis-pycharm>`_,\nand\n`icontract-hypothesis-vscode <https://github.com/mristin/icontract-hypothesis-vscode>`_ -\nyou can run a quick 'smoke test' with only a few keystrokes for any type-annotated\nfunction, even if it doesn't have any contracts!\n\nWriting an extension\n--------------------\n\n.. note::\n\n    See :gh-file:`CONTRIBUTING.rst` for more information.\n\nNew strategies can be added to Hypothesis, or published as an external package\non PyPI - either is fine for most strategies. If in doubt, ask!\n\nIt's generally much easier to get things working outside, because there's more\nfreedom to experiment and fewer requirements in stability and API style. We're\nhappy to review and help with external packages as well as pull requests!\n\nIf you're thinking about writing an extension, please name it\n``hypothesis-{something}`` - a standard prefix makes the community more\nvisible and searching for extensions easier.  And make sure you use the\n``Framework :: Hypothesis`` trove classifier!\n\nOn the other hand, being inside gets you access to some deeper implementation\nfeatures (if you need them) and better long-term guarantees about maintenance.\nWe particularly encourage pull requests for new composable primitives that\nmake implementing other strategies easier, or for widely used types in the\nstandard library. Strategies for other things are also welcome; anything with\nexternal dependencies just goes in ``hypothesis.extra``.\n\nTools such as assertion helpers may also need to check whether the current\ntest is using Hypothesis. For that, see |currently_in_test_context|.\n\n.. _entry-points:\n\nHypothesis integration via entry points\n---------------------------------------\n\nIf you would like to ship Hypothesis strategies for a custom type - either as\npart of the upstream library, or as a third-party extension, there's a catch:\n|st.from_type| only works after the corresponding\ncall to |st.register_type_strategy|, and you'll have\nthe same problem with |register_random|.  This means that\neither\n\n- you have to try importing Hypothesis to register the strategy when *your*\n  library is imported, though that's only useful at test time, or\n- the user has to call a 'register the strategies' helper that you provide\n  before running their tests\n\n`Entry points <https://setuptools.pypa.io/en/latest/userguide/entry_point.html>`__\nare Python's standard way of automating the latter: when you register a\n``\"hypothesis\"`` entry point in your ``pyproject.toml``, we'll import and run it\nautomatically when *hypothesis* is imported.  Nothing happens unless Hypothesis\nis already in use, and it's totally seamless for downstream users!\n\nLet's look at an example.  You start by adding a function somewhere in your\npackage that does all the Hypothesis-related setup work:\n\n.. code-block:: python\n\n    # mymodule.py\n\n    class MyCustomType:\n        def __init__(self, x: int):\n            assert x >= 0, f\"got {x}, but only positive numbers are allowed\"\n            self.x = x\n\n    def _hypothesis_setup_hook():\n        import hypothesis.strategies as st\n\n        st.register_type_strategy(MyCustomType, st.integers(min_value=0))\n\nand then declare this as your ``\"hypothesis\"`` entry point:\n\n.. code-block:: toml\n\n    # pyproject.toml\n\n    # You can list a module to import by dotted name\n    [project.entry-points.hypothesis]\n    _ = \"mymodule.a_submodule\"\n\n    # Or name a specific function, and Hypothesis will call it for you\n    [project.entry-points.hypothesis]\n    _ = \"mymodule:_hypothesis_setup_hook\"\n\nAnd that's all it takes!\n\n.. envvar:: HYPOTHESIS_NO_PLUGINS\n\n   If set, disables automatic loading of all hypothesis plugins. This is probably only\n   useful for our own self-tests, but documented in case it might help narrow down\n   any particularly weird bugs in complex environments.\n\n\nInteraction with :pypi:`pytest-cov`\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nBecause pytest does not load plugins from entrypoints in any particular order,\nusing the Hypothesis entrypoint may import your module before :pypi:`pytest-cov`\nstarts.  `This is a known issue <https://github.com/pytest-dev/pytest/issues/935>`__,\nbut there are workarounds.\n\nYou can use :command:`coverage run pytest ...` instead of :command:`pytest --cov ...`,\nopting out of the pytest plugin entirely.  Alternatively, you can ensure that Hypothesis\nis loaded after coverage measurement is started by disabling the entrypoint, and\nloading our pytest plugin from your ``conftest.py`` instead::\n\n    echo \"pytest_plugins = ['hypothesis.extra.pytestplugin']\\n\" > tests/conftest.py\n    pytest -p \"no:hypothesispytest\" ...\n\nAnother alternative, which we in fact use in our CI self-tests because it works\nwell also with parallel tests, is to automatically start coverage early for all\nnew processes if an environment variable is set.\nThis automatic starting is set up by the PyPi package :pypi:`coverage_enable_subprocess`.\n\nThis means all configuration must be done in ``.coveragerc``, and not on the\ncommand line::\n\n    [run]\n    parallel = True\n    source = ...\n\nThen, set the relevant environment variable and run normally::\n\n    python -m pip install coverage_enable_subprocess\n    export COVERAGE_PROCESS_START=$PATH/.coveragerc\n    pytest [-n auto] ...\n    coverage combine\n    coverage report\n\n\n.. _alternative-backends:\n\nAlternative backends for Hypothesis\n-----------------------------------\n\n.. seealso::\n\n  See also the :ref:`Alternative backends interface <alternative-backends-internals>` for details on implementing your own alternative backend.\n\nHypothesis supports alternative backends, which tells Hypothesis how to generate primitive\ntypes. This enables powerful generation techniques which are compatible with all parts of\nHypothesis, including the database and shrinking.\n\nHypothesis includes the following backends:\n\nhypothesis\n    The default backend.\nhypothesis-urandom\n    The same as the default backend, but uses ``/dev/urandom`` as its source of randomness,\n    instead of the standard PRNG in |random.Random|. The only reason to use this backend over the default ``backend=\"hypothesis\"`` is if you are also\n    using `Antithesis <https://antithesis.com/>`_, in which case this allows Antithesis\n    mutation of ``/dev/urandom`` to control the values generated by Hypothesis.\n\n    ``/dev/urandom`` is not available on Windows, so we emit a warning and fall back to the\n    hypothesis backend there.\nhypofuzz\n    Generates inputs using coverage-guided fuzzing. See `HypoFuzz <https://hypofuzz.com/>`_ for details.\n\n    Requires ``pip install hypofuzz``.\ncrosshair\n    Generates inputs using SMT solvers like z3, which is particularly effective at satisfying\n    difficult checks in your code, like ``if`` or ``==`` statements.\n\n    Requires ``pip install hypothesis[crosshair]``.\n\nYou can change the backend for a test with the |settings.backend| setting. For instance, after\n``pip install hypothesis[crosshair]``, you can use :pypi:`crosshair <crosshair-tool>` to\ngenerate inputs with SMT via the :pypi:`hypothesis-crosshair` backend:\n\n.. code-block:: python\n\n    from hypothesis import given, settings, strategies as st\n\n    @settings(backend=\"crosshair\")  # pip install hypothesis[crosshair]\n    @given(st.integers())\n    def test_needs_solver(x):\n        assert x != 123456789\n\nFailures found by alternative backends are saved to the database and shrink just like normally\ngenerated inputs, and in general interact with every feature of Hypothesis as you would expect.\n"
  },
  {
    "path": "hypothesis-python/docs/extras.rst",
    "content": "======================\nFirst-party extensions\n======================\n\nHypothesis has minimal dependencies, to maximise\ncompatibility and make installing Hypothesis as easy as possible.\n\nOur integrations with specific packages are therefore provided by ``extra``\nmodules that need their individual dependencies installed in order to work.\nYou can install these dependencies using the setuptools extra feature as e.g.\n``pip install hypothesis[django]``. This will check installation of compatible versions.\n\nYou can also just install hypothesis into a project using them, ignore the version\nconstraints, and hope for the best.\n\nIn general \"Which version is Hypothesis compatible with?\" is a hard question to answer\nand even harder to regularly test. Hypothesis is always tested against the latest\ncompatible version and each package will note the expected compatibility range. If\nyou run into a bug with any of these please specify the dependency version.\n\nThe following lists the available extras in Hypothesis and their documentation.\n\n* :ref:`hypothesis[cli] <hypothesis-cli>`\n* :ref:`hypothesis[codemods] <codemods>`\n* :ref:`hypothesis[django] <hypothesis-django>`\n* :ref:`hypothesis[numpy] <hypothesis-numpy>`\n* :ref:`hypothesis[lark] <hypothesis-lark>`\n* :ref:`hypothesis[pytz] <hypothesis-pytz>`\n* :ref:`hypothesis[dateutil] <hypothesis-dateutil>`\n* :ref:`hypothesis[dpcontracts] <hypothesis-dpcontracts>`\n"
  },
  {
    "path": "hypothesis-python/docs/how-to/custom-database.rst",
    "content": "Write a custom Hypothesis database\n==================================\n\nTo define your own |ExampleDatabase| class, implement the |ExampleDatabase.save|, |ExampleDatabase.fetch|, and |ExampleDatabase.delete| methods.\n\nFor example, here's a simple database class that uses :mod:`sqlite <sqlite3>` as the backing data store:\n\n.. code-block:: python\n\n    import sqlite3\n    from collections.abc import Iterable\n\n    from hypothesis.database import ExampleDatabase\n\n    class SQLiteExampleDatabase(ExampleDatabase):\n        def __init__(self, db_path: str):\n            self.conn = sqlite3.connect(db_path)\n\n            self.conn.execute(\n                \"\"\"\n                CREATE TABLE examples (\n                    key BLOB,\n                    value BLOB,\n                    UNIQUE (key, value)\n                )\n            \"\"\"\n            )\n\n        def save(self, key: bytes, value: bytes) -> None:\n            self.conn.execute(\n                \"INSERT OR IGNORE INTO examples VALUES (?, ?)\",\n                (key, value),\n            )\n\n        def fetch(self, key: bytes) -> Iterable[bytes]:\n            cursor = self.conn.execute(\"SELECT value FROM examples WHERE key = ?\", (key,))\n            yield from [value[0] for value in cursor.fetchall()]\n\n        def delete(self, key: bytes, value: bytes) -> None:\n            self.conn.execute(\n                \"DELETE FROM examples WHERE key = ? AND value = ?\",\n                (key, value),\n            )\n\nDatabase classes are not required to implement |ExampleDatabase.move|. The default implementation of a move is a |ExampleDatabase.delete| of the value in the old key, followed by a |ExampleDatabase.save| of the value in the new key. You can override |ExampleDatabase.move| to override this behavior, if for instance the backing store offers a more efficient move implementation.\n\nChange listening\n----------------\n\nTo support change listening in a database class, you should call |ExampleDatabase._broadcast_change| whenever a value is saved, deleted, or moved in the backing database store. How you track this depends on the details of the database class. For instance, in |DirectoryBasedExampleDatabase|, Hypothesis installs a filesystem monitor via :pypi:`watchdog` in order to broadcast change events.\n\nTwo useful related methods are |ExampleDatabase._start_listening| and |ExampleDatabase._stop_listening|, which a database class can override to know when to start or stop expensive listening operations. See documentation for details.\n"
  },
  {
    "path": "hypothesis-python/docs/how-to/detect-hypothesis-tests.rst",
    "content": "Detect Hypothesis tests\n-----------------------\n\nHow to dynamically determine whether a test function has been defined with Hypothesis.\n\nVia ``is_hypothesis_test``\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe most straightforward way is to use |is_hypothesis_test|:\n\n.. code-block:: python\n\n    from hypothesis import is_hypothesis_test\n\n    @given(st.integers())\n    def f(n): ...\n\n    assert is_hypothesis_test(f)\n\nThis works for stateful tests as well:\n\n.. code-block:: python\n\n    from hypothesis import is_hypothesis_test\n    from hypothesis.stateful import RuleBasedStateMachine\n\n    class MyStateMachine(RuleBasedStateMachine): ...\n\n    assert is_hypothesis_test(MyStateMachine.TestCase().runTest)\n\nVia pytest\n~~~~~~~~~~\n\nIf you're working with :pypi:`pytest`, the :ref:`Hypothesis pytest plugin <pytest-plugin>` automatically adds the ``@pytest.mark.hypothesis`` mark to all Hypothesis tests. You can use ``node.get_closest_marker(\"hypothesis\")`` or similar methods to detect the existence of this mark.\n"
  },
  {
    "path": "hypothesis-python/docs/how-to/external-fuzzers.rst",
    "content": "Use Hypothesis with an external fuzzer\n======================================\n\nSometimes you might want to point a traditional fuzzer like `python-afl <https://github.com/jwilk/python-afl>`__ or Google's :pypi:`atheris` at your code, to get coverage-guided exploration of native C extensions.  The associated tooling is often much less mature than property-based testing libraries though, so you might want to use Hypothesis strategies to describe your input data, and our world-class shrinking and :ref:`observability <observability>` tools to wrangle the results.  That's exactly what this how-to guide is about!\n\n.. note::\n\n    If you already have Hypothesis tests and want to fuzz them, or are targeting pure Python code, we strongly recommend the purpose-built `HypoFuzz <https://hypofuzz.com/>`_.\n    This page is about writing traditional 'fuzz harnesses' with an external fuzzer, using parts of Hypothesis.\n\nIn order to support this workflow, Hypothesis exposes the |fuzz_one_input| method. |fuzz_one_input| takes a bytestring, parses it into a test case, and executes the corresponding test once. This means you can treat each of your Hypothesis tests as a traditional fuzz target, by pointing the fuzzer at |fuzz_one_input|.\n\nFor example:\n\n.. code-block:: python\n\n    from hypothesis import given, strategies as st\n\n    @given(st.integers())\n    def test_ints(n):\n        pass\n\n    # this parses the bytestring into a test case using st.integers(),\n    # and then executes `test_ints` once.\n    test_ints.hypothesis.fuzz_one_input(b\"\\x00\" * 50)\n\nNote that |fuzz_one_input| bypasses the standard test lifecycle. In a standard test run, Hypothesis is responsible for managing the lifecycle of a test, for example by moving between each |Phase|. In contrast, |fuzz_one_input| executes one test case, independent of this lifecycle.\n\nSee the documentation of |fuzz_one_input| for details of how it interacts with other features of Hypothesis, such as |@settings|.\n\nWorked example: using Atheris\n-----------------------------\n\nHere is an example that uses |fuzz_one_input| with the `Atheris <https://github.com/google/atheris>`__ coverage-guided fuzzer (which is built on top of `libFuzzer <https://llvm.org/docs/LibFuzzer.html>`_):\n\n.. code-block:: python\n\n    import json\n    import sys\n\n    import atheris\n\n    from hypothesis import given, strategies as st\n\n    @given(\n        st.recursive(\n            st.none() | st.booleans() | st.integers() | st.floats() | st.text(),\n            lambda j: st.lists(j) | st.dictionaries(st.text(), j),\n        )\n    )\n    def test_json_dumps_valid_json(value):\n        json.dumps(value)\n\n    atheris.Setup(sys.argv, test_json_dumps_valid_json.hypothesis.fuzz_one_input)\n    atheris.Fuzz()\n\nGenerating valid JSON objects based only on Atheris' ``FuzzDataProvider`` interface would be considerably more difficult.\n\nYou may also want to use ``atheris.instrument_all`` or ``atheris.instrument_imports`` in order to add coverage instrumentation to Atheris.  See the `Atheris <https://github.com/google/atheris>`__ documentation for full details.\n"
  },
  {
    "path": "hypothesis-python/docs/how-to/index.rst",
    "content": "How-to guides\n=============\n\nThese how-to pages are practical guides for applying Hypothesis in specific scenarios. Each page addresses a particular question about using Hypothesis.\n\n.. toctree::\n   :maxdepth: 1\n\n   suppress-healthchecks\n   type-strategies\n   custom-database\n   detect-hypothesis-tests\n   external-fuzzers\n"
  },
  {
    "path": "hypothesis-python/docs/how-to/suppress-healthchecks.rst",
    "content": "Suppress a health check everywhere\n==================================\n\nHypothesis sometimes raises a |HealthCheck| to indicate that your test may be less effective than you expect, slower than you expect, unlikely to generate effective examples, or otherwise has silently degraded performance.\n\nWhile |HealthCheck| can be useful to proactively identify issues, you may not care about certain classes of them. If you want to disable a |HealthCheck| everywhere, you can register and load a settings profile with |settings.register_profile| and |settings.load_profile|. Place the following code in any file which is loaded before running your tests (or in ``conftest.py``, if using pytest):\n\n.. code-block:: python\n\n    from hypothesis import HealthCheck, settings\n\n    settings.register_profile(\n        \"my_profile\", suppress_health_check=[HealthCheck.filter_too_much]\n    )\n    settings.load_profile(\"my_profile\")\n\nThis profile in particular suppresses the |HealthCheck.filter_too_much| health check for all tests. The exception is if a test has a |@settings| which explicitly sets a different value for ``suppress_health_check``, in which case the profile value will be overridden by the local settings value.\n\nI want to suppress all health checks!\n-------------------------------------\n\n.. warning::\n\n    We strongly recommend that you suppress health checks as you encounter them, rather than using a blanket suppression. Several health checks check for subtle interactions that may save you hours of debugging, such as |HealthCheck.function_scoped_fixture| and |HealthCheck.differing_executors|.\n\nIf you really want to suppress *all* health checks, for instance to speed up interactive prototyping, you can:\n\n.. code-block:: python\n\n    from hypothesis import HealthCheck, settings\n\n    settings.register_profile(\"my_profile\", suppress_health_check=list(HealthCheck))\n    settings.load_profile(\"my_profile\")\n"
  },
  {
    "path": "hypothesis-python/docs/how-to/type-strategies.rst",
    "content": "Write type hints for strategies\n===============================\n\nHypothesis provides type hints for all strategies and functions which return a strategy:\n\n.. code-block:: python\n\n    from hypothesis import strategies as st\n\n    reveal_type(st.integers())\n    # SearchStrategy[int]\n\n    reveal_type(st.lists(st.integers()))\n    # SearchStrategy[list[int]]\n\n|SearchStrategy| is the type of a strategy. It is parametrized by the type of the example it generates. You can use it to write type hints for your functions which return a strategy:\n\n.. code-block:: python\n\n    from hypothesis import strategies as st\n    from hypothesis.strategies import SearchStrategy\n\n    # returns a strategy for \"normal\" numbers\n    def numbers() -> SearchStrategy[int | float]:\n        return st.integers() | st.floats(allow_nan=False, allow_infinity=False)\n\nIt's worth pointing out the distinction between a strategy, and a function that returns a strategy. |st.integers| is a function which returns a strategy, and that strategy has type ``SearchStrategy[int]``. The function ``st.integers`` therefore has type ``Callable[..., SearchStrategy[int]]``, while the value ``s = st.integers()`` has type ``SearchStrategy[int]``.\n\n\nType hints for |st.composite|\n-----------------------------\n\nWhen writing type hints for strategies defined with |st.composite|, use the type of the returned value (not ``SearchStrategy``):\n\n.. code-block:: python\n\n    @st.composite\n    def ordered_pairs(draw) -> tuple[int, int]:\n        n1 = draw(st.integers())\n        n2 = draw(st.integers(min_value=n1))\n        return (n1, n2)\n\nType variance of |SearchStrategy|\n---------------------------------\n\n|SearchStrategy| is covariant, meaning that if ``B < A`` then ``SearchStrategy[B] < SearchStrategy[A]``. In other words, the strategy ``st.from_type(Dog)`` is a subtype of the strategy ``st.from_type(Animal)``.\n"
  },
  {
    "path": "hypothesis-python/docs/index.rst",
    "content": ".. raw:: html\n\n     <!-- adapted from https://docs.django-cms.org/en/release-4.1.x/, with thanks -->\n\n    <style>\n        .row {\n           clear: both;\n        }\n\n        .column img {border: 1px solid gray;}\n\n        @media only screen and (min-width: 1000px) {\n\n            .column {\n                padding-left: 5px;\n                padding-right: 5px;\n                float: left;\n            }\n\n            .column2  {\n                width: calc(50% - 11px);\n                position: relative;\n            }\n            .column2:before {\n                padding-top: 61.8%;\n                content: \"\";\n                display: block;\n                float: left;\n            }\n            .top-left {\n                border-right: 1px solid var(--color-background-border);\n                border-bottom: 1px solid var(--color-background-border);\n            }\n            .top-right {\n                border-bottom: 1px solid var(--color-background-border);\n            }\n            .bottom-left {\n                border-right: 1px solid var(--color-background-border);\n            }\n        }\n    </style>\n\nWelcome to Hypothesis!\n======================\n\nHypothesis is the property-based testing library for Python. With Hypothesis, you write tests which should pass for all inputs in whatever range you describe, and let Hypothesis randomly choose which of those inputs to check - including edge cases you might not have thought about. For example:\n\n.. code-block:: python\n\n    from hypothesis import given, strategies as st\n\n    @given(st.lists(st.integers() | st.floats()))\n    def test_sort_correctness_using_properties(lst):\n        result = my_sort(lst)\n        assert set(lst) == set(result)\n        assert all(a <= b for a, b in zip(result, result[1:]))\n\nYou should start with the :doc:`tutorial <tutorial/index>`, or alternatively the more condensed :doc:`quickstart <quickstart>`.\n\n.. rst-class:: row\n\n.. rst-class:: column column2 top-left\n\n:doc:`Tutorial <tutorial/index>`\n---------------------------------\n\nAn introduction to Hypothesis.\n\nNew users should start here, or with the more condensed :doc:`quickstart <quickstart>`.\n\n.. rst-class:: column column2 top-right\n\n:doc:`How-to guides <how-to/index>`\n-----------------------------------\n\nPractical guides for applying Hypothesis in specific scenarios.\n\n.. rst-class:: column column2 bottom-left\n\n:doc:`Explanations <explanation/index>`\n---------------------------------------\n\nCommentary oriented towards deepening your understanding of Hypothesis.\n\n.. rst-class:: column column2 bottom-right\n\n:doc:`API Reference <reference/index>`\n--------------------------------------\n\nTechnical API reference.\n\n.. rst-class:: row\n\n.. toctree::\n  :maxdepth: 1\n  :hidden:\n\n  quickstart\n  tutorial/index\n  how-to/index\n  explanation/index\n  reference/index\n  stateful\n  Extras <extras>\n  changelog\n\n.. toctree::\n  :maxdepth: 1\n  :hidden:\n  :caption: About Hypothesis\n\n  development\n  compatibility\n  usage\n  extensions\n  packaging\n  community\n"
  },
  {
    "path": "hypothesis-python/docs/packaging.rst",
    "content": "====================\nPackaging guidelines\n====================\n\nDownstream packagers often want to package Hypothesis. Here are some guidelines.\n\nThe primary guideline is this: If you are not prepared to keep up with the Hypothesis release schedule,\ndon't. You will be doing your users a disservice.\n\nHypothesis has a very frequent release schedule. We often release new versions multiple times a week.\n\nIf you *are* prepared to keep up with this schedule, you might find the rest of this document useful.\n\n----------------\nRelease tarballs\n----------------\n\nThese are available from :gh-link:`the GitHub releases page <releases>`. The\ntarballs on PyPI are intended for installation from a Python tool such as :pypi:`pip` and should not\nbe considered complete releases. Requests to include additional files in them will not be granted. Their absence\nis not a bug.\n\n\n------------\nDependencies\n------------\n\n~~~~~~~~~~~~~~~\nPython versions\n~~~~~~~~~~~~~~~\n\nHypothesis is designed to work with a range of Python versions - we support\n`all versions of CPython with upstream support <https://devguide.python.org/#status-of-python-branches>`_.\nWe also support the latest versions of PyPy for Python 3.\n\n~~~~~~~~~~~~~~~~~~~~~~\nOther Python libraries\n~~~~~~~~~~~~~~~~~~~~~~\n\nHypothesis has *mandatory* dependencies on the following libraries:\n\n* :pypi:`sortedcontainers`\n\nHypothesis has *optional* dependencies on the following libraries:\n\n.. literalinclude:: ../pyproject.toml\n   :prepend: [project.optional-dependencies]\n   :start-after: [project.optional-dependencies]\n   :end-before: # Avoid changing this by hand\n\nThe way this works when installing Hypothesis normally is that these features become available if the relevant\nlibrary is installed.\n\nSpecifically for :pypi:`pytest`, our plugin supports versions of pytest which\nhave been out of upstream support for some time.  Hypothesis tests can still\nbe executed by even older versions of pytest - you just won't have the plugin\nto provide automatic marks, helpful usage warnings, and per-test statistics.\n\n------------------\nTesting Hypothesis\n------------------\n\nIf you want to test Hypothesis as part of your packaging you will probably not want to use the mechanisms\nHypothesis itself uses for running its tests, because it has a lot of logic for installing and testing against\ndifferent versions of Python.\n\nThe tests must be run with fairly recent tooling; check the :gh-link:`tree/master/requirements/`\ndirectory for details.\n\nThe organisation of the tests is described in the :gh-file:`hypothesis-python/tests/README.rst`.\n\n--------\nExamples\n--------\n\n* `arch linux <https://archlinux.org/packages/extra/any/python-hypothesis/>`_\n* `fedora <https://src.fedoraproject.org/rpms/python-hypothesis>`_\n* `gentoo <https://packages.gentoo.org/packages/dev-python/hypothesis>`_\n"
  },
  {
    "path": "hypothesis-python/docs/prolog.rst",
    "content": ".. |given| replace:: :func:`~hypothesis.given`\n.. |@given| replace:: :func:`@given <hypothesis.given>`\n.. |@example| replace:: :func:`@example <hypothesis.example>`\n.. |@example.xfail| replace:: :func:`@example(...).xfail() <hypothesis.example.xfail>`\n.. |@example.via| replace:: :func:`@example(...).via() <hypothesis.example.via>`\n.. |example.xfail| replace:: :func:`example.xfail <hypothesis.example.xfail>`\n.. |example.via| replace:: :func:`example.via <hypothesis.example.via>`\n.. |@settings| replace:: :func:`@settings <hypothesis.settings>`\n.. |settings| replace:: :func:`settings <hypothesis.settings>`\n.. |@composite| replace:: :func:`@composite <hypothesis.strategies.composite>`\n.. |assume| replace:: :func:`~hypothesis.assume`\n.. |target| replace:: :func:`~hypothesis.target`\n.. |event| replace:: :func:`~hypothesis.event`\n.. |note| replace:: :func:`~hypothesis.note`\n.. |infer| replace:: :data:`~hypothesis.infer`\n.. |fuzz_one_input| replace:: :func:`~hypothesis.core.HypothesisHandle.fuzz_one_input`\n\n.. |max_examples| replace:: :obj:`~hypothesis.settings.max_examples`\n.. |settings.max_examples| replace:: :obj:`settings.max_examples <hypothesis.settings.max_examples>`\n.. |settings.database| replace:: :obj:`settings.database <hypothesis.settings.database>`\n.. |settings.deadline| replace:: :obj:`settings.deadline <hypothesis.settings.deadline>`\n.. |settings.derandomize| replace:: :obj:`settings.derandomize <hypothesis.settings.derandomize>`\n.. |settings.phases| replace:: :obj:`settings.phases <hypothesis.settings.phases>`\n.. |settings.print_blob| replace:: :obj:`settings.print_blob <hypothesis.settings.print_blob>`\n.. |settings.report_multiple_bugs| replace:: :obj:`settings.report_multiple_bugs <hypothesis.settings.report_multiple_bugs>`\n.. |settings.verbosity| replace:: :obj:`settings.verbosity <hypothesis.settings.verbosity>`\n.. |settings.suppress_health_check| replace:: :obj:`settings.suppress_health_check <hypothesis.settings.suppress_health_check>`\n.. |settings.stateful_step_count| replace:: :obj:`settings.stateful_step_count <hypothesis.settings.stateful_step_count>`\n.. |settings.backend| replace:: :obj:`settings.backend <hypothesis.settings.backend>`\n\n.. |~settings.max_examples| replace:: :obj:`~hypothesis.settings.max_examples`\n.. |~settings.database| replace:: :obj:`~hypothesis.settings.database`\n.. |~settings.deadline| replace:: :obj:`~hypothesis.settings.deadline`\n.. |~settings.derandomize| replace:: :obj:`~hypothesis.settings.derandomize`\n.. |~settings.phases| replace:: :obj:`~hypothesis.settings.phases`\n.. |~settings.print_blob| replace:: :obj:`~hypothesis.settings.print_blob`\n.. |~settings.report_multiple_bugs| replace:: :obj:`~hypothesis.settings.report_multiple_bugs`\n.. |~settings.verbosity| replace:: :obj:`~hypothesis.settings.verbosity`\n.. |~settings.suppress_health_check| replace:: :obj:`~hypothesis.settings.suppress_health_check`\n.. |~settings.stateful_step_count| replace:: :obj:`~hypothesis.settings.stateful_step_count`\n.. |~settings.backend| replace:: :obj:`~hypothesis.settings.backend`\n\n.. |settings.register_profile| replace:: :func:`~hypothesis.settings.register_profile`\n.. |settings.get_profile| replace:: :func:`~hypothesis.settings.get_profile`\n.. |settings.load_profile| replace:: :func:`~hypothesis.settings.load_profile`\n.. |settings.get_current_profile_name| replace:: :func:`~hypothesis.settings.get_current_profile_name`\n\n.. |HealthCheck.data_too_large| replace:: :obj:`HealthCheck.data_too_large <hypothesis.HealthCheck.data_too_large>`\n.. |HealthCheck.filter_too_much| replace:: :obj:`HealthCheck.filter_too_much <hypothesis.HealthCheck.filter_too_much>`\n.. |HealthCheck.too_slow| replace:: :obj:`HealthCheck.too_slow <hypothesis.HealthCheck.too_slow>`\n.. |HealthCheck.function_scoped_fixture| replace:: :obj:`HealthCheck.function_scoped_fixture <hypothesis.HealthCheck.function_scoped_fixture>`\n.. |HealthCheck.differing_executors| replace:: :obj:`HealthCheck.differing_executors <hypothesis.HealthCheck.differing_executors>`\n.. |HealthCheck| replace:: :obj:`~hypothesis.HealthCheck`\n\n.. |Phase| replace:: :obj:`Phase <hypothesis.Phase>`\n.. |Phase.explicit| replace:: :obj:`Phase.explicit <hypothesis.Phase.explicit>`\n.. |Phase.reuse| replace:: :obj:`Phase.reuse <hypothesis.Phase.reuse>`\n.. |Phase.generate| replace:: :obj:`Phase.generate <hypothesis.Phase.generate>`\n.. |Phase.target| replace:: :obj:`Phase.target <hypothesis.Phase.target>`\n.. |Phase.shrink| replace:: :obj:`Phase.shrink <hypothesis.Phase.shrink>`\n.. |Phase.explain| replace:: :obj:`Phase.explain <hypothesis.Phase.explain>`\n\n.. |Verbosity| replace:: :obj:`~hypothesis.Verbosity`\n.. |Verbosity.verbose| replace:: :obj:`Verbosity.verbose <hypothesis.Verbosity.verbose>`\n.. |Verbosity.debug| replace:: :obj:`Verbosity.debug <hypothesis.Verbosity.debug>`\n.. |Verbosity.normal| replace:: :obj:`Verbosity.normal <hypothesis.Verbosity.normal>`\n.. |Verbosity.quiet| replace:: :obj:`Verbosity.quiet <hypothesis.Verbosity.quiet>`\n\n.. |HypothesisException| replace:: :obj:`HypothesisException <hypothesis.errors.HypothesisException>`\n.. |HypothesisDeprecationWarning| replace:: :obj:`HypothesisDeprecationWarning <hypothesis.errors.HypothesisDeprecationWarning>`\n.. |NonInteractiveExampleWarning| replace:: :obj:`NonInteractiveExampleWarning <hypothesis.errors.NonInteractiveExampleWarning>`\n.. |Flaky| replace:: :obj:`Flaky <hypothesis.errors.Flaky>`\n.. |FlakyStrategyDefinition| replace:: :obj:`FlakyStrategyDefinition <hypothesis.errors.FlakyStrategyDefinition>`\n.. |FlakyFailure| replace:: :obj:`FlakyFailure <hypothesis.errors.FlakyFailure>`\n.. |FlakyBackendFailure| replace:: :obj:`~hypothesis.errors.FlakyBackendFailure`\n.. |InvalidArgument| replace:: :obj:`InvalidArgument <hypothesis.errors.InvalidArgument>`\n.. |DidNotReproduce| replace:: :obj:`DidNotReproduce <hypothesis.errors.DidNotReproduce>`\n.. |DeadlineExceeded| replace:: :obj:`DeadlineExceeded <hypothesis.errors.DeadlineExceeded>`\n.. |BackendCannotProceed| replace:: :obj:`~hypothesis.errors.BackendCannotProceed`\n\n\n.. |st.lists| replace:: :func:`~hypothesis.strategies.lists`\n.. |st.integers| replace:: :func:`~hypothesis.strategies.integers`\n.. |st.floats| replace:: :func:`~hypothesis.strategies.floats`\n.. |st.booleans| replace:: :func:`~hypothesis.strategies.booleans`\n.. |st.none| replace:: :func:`~hypothesis.strategies.none`\n.. |st.composite| replace:: :func:`@composite <hypothesis.strategies.composite>`\n.. |st.data| replace:: :func:`~hypothesis.strategies.data`\n.. |st.one_of| replace:: :func:`~hypothesis.strategies.one_of`\n.. |st.text| replace:: :func:`~hypothesis.strategies.text`\n.. |st.characters| replace:: :func:`~hypothesis.strategies.characters`\n.. |st.tuples| replace:: :func:`~hypothesis.strategies.tuples`\n.. |st.sets| replace:: :func:`~hypothesis.strategies.sets`\n.. |st.dictionaries| replace:: :func:`~hypothesis.strategies.dictionaries`\n.. |st.fixed_dictionaries| replace:: :func:`~hypothesis.strategies.fixed_dictionaries`\n.. |st.datetimes| replace:: :func:`~hypothesis.strategies.datetimes`\n.. |st.builds| replace:: :func:`~hypothesis.strategies.builds`\n.. |st.recursive| replace:: :func:`~hypothesis.strategies.recursive`\n.. |st.deferred| replace:: :func:`~hypothesis.strategies.deferred`\n.. |st.from_type| replace:: :func:`~hypothesis.strategies.from_type`\n.. |st.sampled_from| replace:: :func:`~hypothesis.strategies.sampled_from`\n.. |st.shared| replace:: :func:`~hypothesis.strategies.shared`\n.. |st.uuids| replace:: :func:`~hypothesis.strategies.uuids`\n.. |st.ip_addresses| replace:: :func:`~hypothesis.strategies.ip_addresses`\n.. |st.register_type_strategy| replace:: :func:`~hypothesis.strategies.register_type_strategy`\n.. |st.just| replace:: :func:`~hypothesis.strategies.just`\n.. |st.domains| replace:: :func:`~hypothesis.provisional.domains`\n.. |st.urls| replace:: :func:`~hypothesis.provisional.urls`\n.. |register_random| replace:: :func:`~hypothesis.register_random`\n.. |st.register_random| replace:: :func:`~hypothesis.register_random`\n\n.. |django.from_form| replace:: :func:`~hypothesis.extra.django.from_form`\n.. |django.from_model| replace:: :func:`~hypothesis.extra.django.from_model`\n.. |django.from_field| replace:: :func:`~hypothesis.extra.django.from_field`\n\n.. |SearchStrategy| replace:: :class:`~hypothesis.strategies.SearchStrategy`\n.. |filter| replace:: :func:`.filter() <hypothesis.strategies.SearchStrategy.filter>`\n.. |.filter| replace:: :func:`.filter() <hypothesis.strategies.SearchStrategy.filter>`\n.. |.filter()| replace:: :func:`.filter() <hypothesis.strategies.SearchStrategy.filter>`\n.. |flatmap| replace:: :func:`.flatmap() <hypothesis.strategies.SearchStrategy.flatmap>`\n.. |.flatmap| replace:: :func:`.flatmap() <hypothesis.strategies.SearchStrategy.flatmap>`\n.. |.flatmap()| replace:: :func:`.flatmap() <hypothesis.strategies.SearchStrategy.flatmap>`\n.. |map| replace:: :func:`.map() <hypothesis.strategies.SearchStrategy.map>`\n.. |.map| replace:: :func:`.map() <hypothesis.strategies.SearchStrategy.map>`\n.. |.map()| replace:: :func:`.map() <hypothesis.strategies.SearchStrategy.map>`\n.. |.example| replace:: :func:`.example() <hypothesis.strategies.SearchStrategy.example>`\n.. |.example()| replace:: :func:`.example() <hypothesis.strategies.SearchStrategy.example>`\n\n.. |PrimitiveProvider| replace:: :class:`~hypothesis.internal.conjecture.providers.PrimitiveProvider`\n.. |PrimitiveProvider.realize| replace:: :func:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.realize`\n.. |PrimitiveProvider.draw_integer| replace:: :func:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.draw_integer`\n.. |PrimitiveProvider.draw_boolean| replace:: :func:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.draw_boolean`\n.. |PrimitiveProvider.draw_float| replace:: :func:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.draw_float`\n.. |PrimitiveProvider.draw_string| replace:: :func:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.draw_string`\n.. |PrimitiveProvider.draw_bytes| replace:: :func:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.draw_bytes`\n.. |PrimitiveProvider.on_observation| replace:: :func:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.on_observation`\n.. |PrimitiveProvider.observe_test_case| replace:: :func:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.observe_test_case`\n.. |PrimitiveProvider.observe_information_messages| replace:: :func:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.observe_information_messages`\n.. |PrimitiveProvider.per_test_case_context_manager| replace:: :func:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.per_test_case_context_manager`\n.. |PrimitiveProvider.add_observability_callback| replace:: :data:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.add_observability_callback`\n.. |PrimitiveProvider.span_start| replace:: :func:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.span_start`\n.. |PrimitiveProvider.span_end| replace:: :func:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.span_end`\n.. |PrimitiveProvider.avoid_realization| replace:: :data:`~hypothesis.internal.conjecture.providers.PrimitiveProvider.avoid_realization`\n\n.. |AVAILABLE_PROVIDERS| replace:: :data:`~hypothesis.internal.conjecture.providers.AVAILABLE_PROVIDERS`\n.. |run_conformance_test| replace:: :func:`~hypothesis.internal.conjecture.provider_conformance.run_conformance_test`\n\n.. |add_observability_callback| replace:: :data:`~hypothesis.internal.observability.add_observability_callback`\n.. |remove_observability_callback| replace:: :data:`~hypothesis.internal.observability.remove_observability_callback`\n.. |with_observability_callback| replace:: :data:`~hypothesis.internal.observability.with_observability_callback`\n.. |observability_enabled| replace:: :data:`~hypothesis.internal.observability.observability_enabled`\n.. |TESTCASE_CALLBACKS| replace:: :data:`~hypothesis.internal.observability.TESTCASE_CALLBACKS`\n.. |OBSERVABILITY_CHOICES| replace:: :data:`~hypothesis.internal.observability.OBSERVABILITY_CHOICES`\n.. |BUFFER_SIZE| replace:: :data:`~hypothesis.internal.conjecture.engine.BUFFER_SIZE`\n.. |MAX_SHRINKS| replace:: :data:`~hypothesis.internal.conjecture.engine.MAX_SHRINKS`\n.. |MAX_SHRINKING_SECONDS| replace:: :data:`~hypothesis.internal.conjecture.engine.MAX_SHRINKING_SECONDS`\n\n.. |@rule| replace:: :func:`@rule <hypothesis.stateful.rule>`\n.. |@precondition| replace:: :func:`@precondition <hypothesis.stateful.precondition>`\n.. |@initialize| replace:: :func:`@initialize <hypothesis.stateful.initialize>`\n.. |@invariant| replace:: :func:`@invariant <hypothesis.stateful.invariant>`\n.. |RuleBasedStateMachine| replace:: :class:`~hypothesis.stateful.RuleBasedStateMachine`\n.. |run_state_machine_as_test| replace:: :func:`~hypothesis.stateful.run_state_machine_as_test`\n\n.. |@reproduce_failure| replace:: :func:`@reproduce_failure <hypothesis.reproduce_failure>`\n.. |@seed| replace:: :func:`@seed <hypothesis.seed>`\n\n.. |ExampleDatabase| replace:: :class:`~hypothesis.database.ExampleDatabase`\n.. |ExampleDatabase.save| replace:: :func:`~hypothesis.database.ExampleDatabase.save`\n.. |ExampleDatabase.delete| replace:: :func:`~hypothesis.database.ExampleDatabase.delete`\n.. |ExampleDatabase.fetch| replace:: :func:`~hypothesis.database.ExampleDatabase.fetch`\n.. |ExampleDatabase.move| replace:: :func:`~hypothesis.database.ExampleDatabase.move`\n.. |ExampleDatabase.add_listener| replace:: :func:`~hypothesis.database.ExampleDatabase.add_listener`\n.. |ExampleDatabase.remove_listener| replace:: :func:`~hypothesis.database.ExampleDatabase.remove_listener`\n.. |ExampleDatabase.clear_listeners| replace:: :func:`~hypothesis.database.ExampleDatabase.clear_listeners`\n.. |ExampleDatabase._start_listening| replace:: :func:`~hypothesis.database.ExampleDatabase._start_listening`\n.. |ExampleDatabase._stop_listening| replace:: :func:`~hypothesis.database.ExampleDatabase._stop_listening`\n.. |ExampleDatabase._broadcast_change| replace:: :func:`~hypothesis.database.ExampleDatabase._broadcast_change`\n\n.. |DirectoryBasedExampleDatabase| replace:: :class:`~hypothesis.database.DirectoryBasedExampleDatabase`\n.. |InMemoryExampleDatabase| replace:: :class:`~hypothesis.database.InMemoryExampleDatabase`\n.. |ReadOnlyDatabase| replace:: :class:`~hypothesis.database.ReadOnlyDatabase`\n.. |MultiplexedDatabase| replace:: :class:`~hypothesis.database.MultiplexedDatabase`\n.. |GitHubArtifactDatabase| replace:: :class:`~hypothesis.database.GitHubArtifactDatabase`\n.. |BackgroundWriteDatabase| replace:: :class:`~hypothesis.database.BackgroundWriteDatabase`\n.. |RedisExampleDatabase| replace:: :class:`~hypothesis.extra.redis.RedisExampleDatabase`\n\n.. |is_hypothesis_test| replace:: :func:`~hypothesis.is_hypothesis_test`\n.. |currently_in_test_context| replace:: :func:`~hypothesis.currently_in_test_context`\n\n.. |hypothesis-numpy| replace:: :ref:`NumPy <hypothesis-numpy>`\n.. |hypothesis-pandas| replace:: :ref:`pandas <hypothesis-pandas>`\n.. |hypothesis-django| replace:: :ref:`Django <hypothesis-django>`\n\n.. |str| replace:: :obj:`python:str`\n.. |int| replace:: :obj:`python:int`\n.. |bool| replace:: :obj:`python:bool`\n.. |bytes| replace:: :obj:`python:bytes`\n.. |float| replace:: :obj:`python:float`\n.. |assert| replace:: :keyword:`python:assert`\n.. |memoryview| replace:: :class:`python:memoryview`\n.. |dataclasses| replace:: :mod:`python:dataclasses`\n.. |random.random| replace:: :class:`python:random.Random`\n.. |random.Random| replace:: :class:`python:random.Random`\n.. |ellipsis| replace:: :obj:`python:Ellipsis`\n.. |Ellipsis| replace:: :obj:`python:Ellipsis`\n\n.. |TypeAlias| replace:: :obj:`python:typing.TypeAlias`\n.. |TypeAliasType| replace:: :class:`python:typing.TypeAliasType`\n.. |NewType| replace:: :class:`python:typing.NewType`\n\n.. |alternative backend| replace:: :ref:`alternative backend <alternative-backends>`\n.. |alternative backends| replace:: :ref:`alternative backends <alternative-backends>`\n\n.. |pytest.mark.parametrize| replace:: :ref:`pytest.mark.parametrize <pytest:pytest.mark.parametrize ref>`\n"
  },
  {
    "path": "hypothesis-python/docs/quickstart.rst",
    "content": "Quickstart\n==========\n\nThis is a lightning introduction to the most important features of Hypothesis; enough to get you started writing tests. The :doc:`tutorial <tutorial/index>` introduces these features (and more) in greater detail.\n\nInstall Hypothesis\n------------------\n\n.. code-block:: shell\n\n    pip install hypothesis\n\n\nWrite your first test\n---------------------\n\nCreate a new file called ``example.py``, containing a simple test:\n\n.. code-block:: python\n\n    # contents of example.py\n    from hypothesis import given, strategies as st\n\n    @given(st.integers())\n    def test_integers(n):\n        print(f\"called with {n}\")\n        assert isinstance(n, int)\n\n    test_integers()\n\n|@given| is the standard entrypoint to Hypothesis. It takes a *strategy*, which describes the type of inputs you want the decorated function to accept. When we call ``test_integers``, Hypothesis will generate random integers (because we used the |st.integers| strategy) and pass them as ``n``. Let's see that in action now by running ``python example.py``:\n\n.. code-block:: none\n\n    called with 0\n    called with -18588\n    called with -672780074\n    called with 32616\n    ...\n\nWe just called ``test_integers()``, without passing a value for ``n``, because Hypothesis generates random values of ``n`` for us.\n\n.. note::\n\n    By default, Hypothesis generates 100 random inputs. You can control this with the |max_examples| setting.\n\nRunning in a test suite\n-----------------------\n\nA Hypothesis test is still a regular python function, which means pytest or unittest will pick it up and run it in all the normal ways.\n\n.. code-block:: python\n\n    # contents of example.py\n    from hypothesis import given, strategies as st\n\n    @given(st.integers(0, 200))\n    def test_integers(n):\n        assert n < 50\n\nThis test will clearly fail, which can be confirmed by running ``pytest example.py``:\n\n.. code-block:: none\n\n    $ pytest example.py\n\n        ...\n\n        @given(st.integers())\n        def test_integers(n):\n    >       assert n < 50\n    E       assert 50 < 50\n    E       Falsifying example: test_integers(\n    E           n=50,\n    E       )\n\n\nArguments to |@given|\n---------------------\n\nYou can pass multiple arguments to |@given|:\n\n.. code-block:: python\n\n    @given(st.integers(), st.text())\n    def test_integers(n, s):\n        assert isinstance(n, int)\n        assert isinstance(s, str)\n\nOr use keyword arguments:\n\n.. code-block:: python\n\n    @given(n=st.integers(), s=st.text())\n    def test_integers(n, s):\n        assert isinstance(n, int)\n        assert isinstance(s, str)\n\n.. note::\n\n    See |@given| for details about how |@given| handles different types of arguments.\n\nFiltering inside a test\n-----------------------\n\nSometimes, you need to remove invalid cases from your test. The best way to do this is with |.filter|:\n\n.. code-block:: python\n\n    @given(st.integers().filter(lambda n: n % 2 == 0))\n    def test_integers(n):\n        assert n % 2 == 0\n\nFor more complicated conditions, you can use |assume|, which tells Hypothesis to discard any test case with a false-y argument:\n\n.. code-block:: python\n\n    @given(st.integers(), st.integers())\n    def test_integers(n1, n2):\n        assume(n1 != n2)\n        # n1 and n2 are guaranteed to be different here\n\n.. note::\n\n    You can learn more about |.filter| and |assume| in the :doc:`/tutorial/adapting-strategies` tutorial page.\n\nDependent generation\n--------------------\n\nYou may want an input to depend on the value of another input. For instance, you might want to generate two integers ``n1`` and ``n2`` where ``n1 <= n2``.\n\nYou can do this using the |st.composite| strategy. |st.composite| lets you define a new strategy which is itself built by drawing values from other strategies, using the automatically-passed ``draw`` function.\n\n.. code-block:: python\n\n    @st.composite\n    def ordered_pairs(draw):\n        n1 = draw(st.integers())\n        n2 = draw(st.integers(min_value=n1))\n        return (n1, n2)\n\n    @given(ordered_pairs())\n    def test_pairs_are_ordered(pair):\n        n1, n2 = pair\n        assert n1 <= n2\n\nIn more complex cases, you might need to interleave generation and test code. In this case, use |st.data|.\n\n.. code-block:: python\n\n    @given(st.data(), st.text(min_size=1))\n    def test_string_characters_are_substrings(data, string):\n        assert isinstance(string, str)\n        index = data.draw(st.integers(0, len(string) - 1))\n        assert string[index] in string\n\nCombining Hypothesis with pytest\n--------------------------------\n\nHypothesis works with pytest features, like |pytest.mark.parametrize|:\n\n.. code-block:: python\n\n    import pytest\n\n    from hypothesis import given, strategies as st\n\n    @pytest.mark.parametrize(\"operation\", [reversed, sorted])\n    @given(st.lists(st.integers()))\n    def test_list_operation_preserves_length(operation, lst):\n        assert len(lst) == len(list(operation(lst)))\n\nHypothesis also works with pytest fixtures:\n\n.. code-block:: python\n\n    import pytest\n\n    @pytest.fixture(scope=\"session\")\n    def shared_mapping():\n        return {n: 0 for n in range(101)}\n\n    @given(st.integers(0, 100))\n    def test_shared_mapping_keys(shared_mapping, n):\n        assert n in shared_mapping\n"
  },
  {
    "path": "hypothesis-python/docs/redirect.html.template",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <noscript>\n      <meta http-equiv=\"refresh\" content=\"0; url=${to_uri}\" />\n    </noscript>\n    <script>\n      var target = \"${to_uri}\";\n\n      var manualRedirects = {\n        \"details.html#thread-safety-policy\": \"supported.html#thread-safety-policy\",\n        \"details.html#hypothesis.given\": \"reference/api.html#hypothesis.given\",\n        \"details.html#targeted-example-generation\": \"reference/api.html#targeted-property-based-testing\",\n        \"details.html#custom-function-execution\": \"reference/api.html#custom-function-execution\",\n        \"details.html#type-annotations-in-hypothesis\": \"how-to/type-strategies.html\",\n        \"details.html#the-hypothesis-pytest-plugin\": \"reference/integrations.html#the-hypothesis-pytest-plugin\",\n        \"details.html#use-with-external-fuzzers\": \"reference/api.html#use-with-external-fuzzers\",\n        \"details.html#making-assumptions\": \"reference/api.html#hypothesis.assume\",\n        \"details.html#hypothesis.event\": \"reference/api.html#hypothesis.event\",\n        \"details.html#hypothesis.assume\": \"reference/api.html#hypothesis.assume\",\n        \"details.html#hypothesis.given\": \"reference/api.html#hypothesis.given\",\n        \"details.html#hypothesis.target\": \"reference/api.html#hypothesis.target\",\n        \"details.html#hypothesis.register_random\": \"reference/strategies.html#hypothesis.register_random\",\n        \"details.html#hypothesis.strategies.SearchStrategy\": \"reference/strategies.html#hypothesis.strategies.SearchStrategy\",\n        \"details.html#test-statistics\": \"reference/integrations.html#statistics\",\n      };\n      var redirect = manualRedirects[window.location.pathname.split('/').pop() + window.location.hash];\n\n      if (redirect) {\n        window.location.replace(redirect);\n      } else if (window.location.hash) {\n        // if both the requested url and the redirect target have a hash, prefer the requested url hash.\n        // This makes a redirect config of {\"settings\": \"api.html#settings\"} redirect settings.html#hypothesis.HealthCheck\n        // to api.html#hypothesis.HealthCheck instead of api.html#settings.\n        window.location.replace(target.split('#')[0] + window.location.hash);\n      } else {\n        window.location.replace(target);\n      }\n    </script>\n  </head>\n</html>\n"
  },
  {
    "path": "hypothesis-python/docs/reference/api.rst",
    "content": "API Reference\n=============\n\nReference for non-strategy objects that are part of the Hypothesis API. For documentation on strategies, see the :doc:`strategies reference </reference/strategies>`.\n\n``@given``\n----------\n\n.. autofunction:: hypothesis.given\n\n.. standard #: directives in the source don't work for hypothesis.infer,\n.. see https://github.com/sphinx-doc/sphinx/issues/6495\n\n.. data:: hypothesis.infer\n\n    An alias for ``...`` (|ellipsis|). |infer| can be passed to |@given| or\n    |st.builds| to indicate that a strategy for that parameter should be inferred\n    from its type annotations.\n\n    In all cases, using |infer| is equivalent to using ``...``.\n\n\nInferred strategies\n~~~~~~~~~~~~~~~~~~~\n\nIn some cases, Hypothesis can work out what to do when you omit arguments. This is based on introspection, *not* magic, and therefore has well-defined limits.\n\n|st.builds| will check the signature of the ``target`` (using :func:`python:inspect.signature`). If there are required arguments with type annotations and\nno strategy was passed to |st.builds|, |st.from_type| is used to fill them in. You can also pass the value ``...`` (``Ellipsis``) as a keyword argument, to force this inference for arguments with a default value.\n\n.. code-block:: pycon\n\n    >>> def func(a: int, b: str):\n    ...     return [a, b]\n    ...\n    >>> builds(func).example()\n    [-6993, '']\n\n|@given| does not perform any implicit inference for required arguments, as this would break compatibility with pytest fixtures. ``...`` (:obj:`python:Ellipsis`), can be used as a keyword argument to explicitly fill in an argument from its type annotation.  You can also use the |infer| alias if writing a literal ``...`` seems too weird.\n\n.. code:: python\n\n    @given(a=...)  # or @given(a=infer)\n    def test(a: int):\n        pass\n\n    # is equivalent to\n    @given(a=from_type(int))\n    def test(a):\n        pass\n\n``@given(...)`` can also be specified to fill all arguments from their type annotations.\n\n.. code:: python\n\n    @given(...)\n    def test(a: int, b: str):\n        pass\n\n    # is equivalent to\n    @given(a=..., b=...)\n    def test(a, b):\n        pass\n\nLimitations\n^^^^^^^^^^^\n\nHypothesis does not inspect :pep:`484` type comments at runtime. While |st.from_type| will work as usual, inference in |st.builds| and |@given| will only work if you manually create the ``__annotations__`` attribute (e.g. by using ``@annotations(...)`` and ``@returns(...)`` decorators).\n\nThe :mod:`python:typing` module changes between different Python releases, including at minor versions.  These are all supported on a best-effort basis, but you may encounter problems.  Please report them to us, and consider updating to a newer version of Python as a workaround.\n\nExplicit inputs\n---------------\n\n.. seealso::\n\n    See also the :doc:`/tutorial/replaying-failures` tutorial, which discusses using explicit inputs to reproduce failures.\n\n.. autoclass:: hypothesis.example\n.. automethod:: hypothesis.example.xfail\n.. automethod:: hypothesis.example.via\n\n.. _reproducing-inputs:\n\nReproducing inputs\n------------------\n\n.. seealso::\n\n    See also the :doc:`/tutorial/replaying-failures` tutorial.\n\n.. autofunction:: hypothesis.reproduce_failure\n.. autofunction:: hypothesis.seed\n\nControl\n-------\n\nFunctions that can be called from anywhere inside a test, to either modify how Hypothesis treats the current test case, or to give Hypothesis more information about the current test case.\n\n.. autofunction:: hypothesis.assume\n.. autofunction:: hypothesis.note\n.. autofunction:: hypothesis.event\n\nYou can mark custom events in a test using |event|:\n\n.. code:: python\n\n  from hypothesis import event, given, strategies as st\n\n  @given(st.integers().filter(lambda x: x % 2 == 0))\n  def test_even_integers(i):\n      event(f\"i mod 3 = {i%3}\")\n\nThese events appear in :ref:`observability <observability>` output, as well as the output of :ref:`our pytest plugin <pytest-plugin>` when run with ``--hypothesis-show-statistics``.\n\nFor instance, in the latter case, you would see output like:\n\n.. code-block:: none\n\n  test_even_integers:\n\n    - during generate phase (0.09 seconds):\n        - Typical runtimes: < 1ms, ~ 59% in data generation\n        - 100 passing examples, 0 failing examples, 32 invalid examples\n        - Events:\n          * 54.55%, Retried draw from integers().filter(lambda x: x % 2 == 0) to satisfy filter\n          * 31.06%, i mod 3 = 2\n          * 28.79%, i mod 3 = 0\n          * 24.24%, Aborted test because unable to satisfy integers().filter(lambda x: x % 2 == 0)\n          * 15.91%, i mod 3 = 1\n    - Stopped because settings.max_examples=100\n\nArguments to ``event`` can be any hashable type, but two events will be considered the same\nif they are the same when converted to a string with :obj:`python:str`.\n\n.. _targeted:\n\nTargeted property-based testing\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTargeted property-based testing combines the advantages of both search-based and property-based testing.  Instead of being completely random, targeted PBT uses a search-based component to guide the input generation towards values that have a higher probability of falsifying a property.  This explores the input space more effectively and requires fewer tests to find a bug or achieve a high confidence in the system being tested than random PBT. (`Löscher and Sagonas <http://proper.softlab.ntua.gr/Publications.html>`__)\n\nThis is not *always* a good idea - for example calculating the search metric might take time better spent running more uniformly-random test cases, or your target metric might accidentally lead Hypothesis *away* from bugs - but if there is a natural metric like \"floating-point error\", \"load factor\" or \"queue length\", we encourage you to experiment with targeted testing.\n\nWe recommend that users also skim the papers introducing targeted PBT; from `ISSTA 2017 <http://proper.softlab.ntua.gr/papers/issta2017.pdf>`__ and `ICST 2018 <http://proper.softlab.ntua.gr/papers/icst2018.pdf>`__. For the curious, the initial implementation in Hypothesis uses hill-climbing search via a mutating fuzzer, with some tactics inspired by simulated annealing to avoid getting stuck and endlessly mutating a local maximum.\n\n.. code-block:: python\n\n  from hypothesis import given, strategies as st, target\n\n  @given(st.floats(0, 1e100), st.floats(0, 1e100), st.floats(0, 1e100))\n  def test_associativity_with_target(a, b, c):\n      ab_c = (a + b) + c\n      a_bc = a + (b + c)\n      difference = abs(ab_c - a_bc)\n      target(difference)  # Without this, the test almost always passes\n      assert difference < 2.0\n\n.. autofunction:: hypothesis.target\n\nSettings\n--------\n\n.. seealso::\n\n    See also :doc:`the tutorial for settings </tutorial/settings>`.\n\n.. autoclass:: hypothesis.settings\n    :members:\n\n.. autoclass:: hypothesis.Phase\n    :members:\n\n.. autoclass:: hypothesis.Verbosity\n    :members:\n\n.. autoclass:: hypothesis.HealthCheck\n   :undoc-members:\n   :inherited-members:\n   :exclude-members: all\n\n.. _database:\n\nDatabase\n--------\n\n.. autoclass:: hypothesis.database.ExampleDatabase\n    :members:\n    :private-members: _broadcast_change, _start_listening, _stop_listening\n\n.. autoclass:: hypothesis.database.InMemoryExampleDatabase\n.. autoclass:: hypothesis.database.DirectoryBasedExampleDatabase\n.. autoclass:: hypothesis.database.GitHubArtifactDatabase\n.. autoclass:: hypothesis.database.ReadOnlyDatabase\n.. autoclass:: hypothesis.database.MultiplexedDatabase\n.. autoclass:: hypothesis.database.BackgroundWriteDatabase\n.. autoclass:: hypothesis.extra.redis.RedisExampleDatabase\n\n.. _stateful:\n\nStateful tests\n--------------\n\n.. autoclass:: hypothesis.stateful.RuleBasedStateMachine\n\nRules\n~~~~~\n\n.. autofunction:: hypothesis.stateful.rule\n.. autofunction:: hypothesis.stateful.consumes\n.. autofunction:: hypothesis.stateful.multiple\n.. autoclass:: hypothesis.stateful.Bundle\n.. autofunction:: hypothesis.stateful.initialize\n.. autofunction:: hypothesis.stateful.precondition\n.. autofunction:: hypothesis.stateful.invariant\n\nRunning state machines\n~~~~~~~~~~~~~~~~~~~~~~\n\nIf you want to bypass the TestCase infrastructure you can invoke these manually. The stateful module exposes |run_state_machine_as_test|, which takes an arbitrary function returning a |RuleBasedStateMachine| and an optional settings parameter and does the same as the class based runTest provided.\n\n.. autofunction:: hypothesis.stateful.run_state_machine_as_test\n\nHypothesis exceptions\n---------------------\n\nCustom exceptions raised by Hypothesis.\n\n.. autoclass:: hypothesis.errors.HypothesisException\n.. autoclass:: hypothesis.errors.HypothesisDeprecationWarning\n.. autoclass:: hypothesis.errors.NonInteractiveExampleWarning\n.. autoclass:: hypothesis.errors.Flaky\n.. autoclass:: hypothesis.errors.FlakyStrategyDefinition\n.. autoclass:: hypothesis.errors.FlakyFailure\n.. autoclass:: hypothesis.errors.FlakyBackendFailure\n.. autoclass:: hypothesis.errors.InvalidArgument\n.. autoclass:: hypothesis.errors.ResolutionFailed\n.. autoclass:: hypothesis.errors.Unsatisfiable\n.. autoclass:: hypothesis.errors.DidNotReproduce\n.. autoclass:: hypothesis.errors.DeadlineExceeded\n\n.. _hypothesis-django:\n\nDjango\n------\n\n.. seealso::\n\n    See the :ref:`Django strategies reference <django-strategies>` for documentation on strategies in the ``hypothesis.extra.django`` module.\n\nHypothesis offers a number of features specific for Django testing, available\nin the ``hypothesis[django]`` :doc:`extra </extras>`.  This is tested\nagainst each supported series with mainstream or extended support -\nif you're still getting security patches, you can test with Hypothesis.\n\n.. autoclass:: hypothesis.extra.django.TestCase\n\nUsing it is quite straightforward: All you need to do is subclass\n:class:`hypothesis.extra.django.TestCase` or\n:class:`hypothesis.extra.django.SimpleTestCase` or\n:class:`hypothesis.extra.django.TransactionTestCase` or\n:class:`~hypothesis.extra.django.LiveServerTestCase` or\n:class:`~hypothesis.extra.django.StaticLiveServerTestCase`\nand you can use |@given| as normal,\nand the transactions will be per example\nrather than per test function as they would be if you used |@given| with a normal\ndjango test suite (this is important because your test function will be called\nmultiple times and you don't want them to interfere with each other). Test cases\non these classes that do not use\n|@given| will be run as normal for :class:`django:django.test.TestCase` or :class:`django:django.test.TransactionTestCase`.\n\n.. autoclass:: hypothesis.extra.django.SimpleTestCase\n.. autoclass:: hypothesis.extra.django.TransactionTestCase\n.. autoclass:: hypothesis.extra.django.LiveServerTestCase\n.. autoclass:: hypothesis.extra.django.StaticLiveServerTestCase\n\nWe recommend avoiding :class:`~hypothesis.extra.django.TransactionTestCase`\nunless you really have to run each test case in a database transaction.\nBecause Hypothesis runs this in a loop, the performance problems :class:`django:django.test.TransactionTestCase` normally has\nare significantly exacerbated and your tests will be really slow.\nIf you are using :class:`~hypothesis.extra.django.TransactionTestCase`,\nyou may need to use ``@settings(suppress_health_check=[HealthCheck.too_slow])``\nto avoid a |HealthCheck| error due to slow example generation.\n\nHaving set up a test class, you can now pass |@given|\na strategy for Django models with |django.from_model|.\nFor example, using :gh-file:`the trivial django project we have for testing\n<hypothesis-python/tests/django/toystore/models.py>`:\n\n.. code-block:: pycon\n\n    >>> from hypothesis.extra.django import from_model\n    >>> from toystore.models import Customer\n    >>> c = from_model(Customer).example()\n    >>> c\n    <Customer: Customer object>\n    >>> c.email\n    'jaime.urbina@gmail.com'\n    >>> c.name\n    '\\U00109d3d\\U000e07be\\U000165f8\\U0003fabf\\U000c12cd\\U000f1910\\U00059f12\\U000519b0\\U0003fabf\\U000f1910\\U000423fb\\U000423fb\\U00059f12\\U000e07be\\U000c12cd\\U000e07be\\U000519b0\\U000165f8\\U0003fabf\\U0007bc31'\n    >>> c.age\n    -873375803\n\nHypothesis has just created this with whatever the relevant type of data is.\n\nObviously the customer's age is implausible, which is only possible because\nwe have not used (eg) :class:`~django:django.core.validators.MinValueValidator`\nto set the valid range for this field (or used a\n:class:`~django:django.db.models.PositiveSmallIntegerField`, which would only\nneed a maximum value validator).\n\nIf you *do* have validators attached, Hypothesis will only generate examples\nthat pass validation.  Sometimes that will mean that we fail a\n:class:`~hypothesis.HealthCheck` because of the filtering, so let's explicitly\npass a strategy to skip validation at the strategy level:\n\n.. code-block:: pycon\n\n    >>> from hypothesis.strategies import integers\n    >>> c = from_model(Customer, age=integers(min_value=0, max_value=120)).example()\n    >>> c\n    <Customer: Customer object>\n    >>> c.age\n    5\n\nCustom field types\n~~~~~~~~~~~~~~~~~~\n\nIf you have a custom Django field type you can register it with Hypothesis's\nmodel deriving functionality by registering a default strategy for it:\n\n.. code-block:: pycon\n\n    >>> from toystore.models import CustomishField, Customish\n    >>> from_model(Customish).example()\n    hypothesis.errors.InvalidArgument: Missing arguments for mandatory field\n        customish for model Customish\n    >>> from hypothesis.extra.django import register_field_strategy\n    >>> from hypothesis.strategies import just\n    >>> register_field_strategy(CustomishField, just(\"hi\"))\n    >>> x = from_model(Customish).example()\n    >>> x.customish\n    'hi'\n\nNote that this mapping is on exact type. Subtypes will not inherit it.\n\nGenerating child models\n~~~~~~~~~~~~~~~~~~~~~~~\n\nFor the moment there's no explicit support in hypothesis-django for generating\ndependent models. i.e. a Company model will generate no Shops. However if you\nwant to generate some dependent models as well, you can emulate this by using\nthe |.flatmap| function as follows:\n\n.. code:: python\n\n  from hypothesis.strategies import just, lists\n\n  def generate_with_shops(company):\n      return lists(from_model(Shop, company=just(company))).map(lambda _: company)\n\n  company_with_shops_strategy = from_model(Company).flatmap(generate_with_shops)\n\nLet's unpack what this is doing:\n\nThe way flatmap works is that we draw a value from the original strategy, then\napply a function to it which gives us a new strategy. We then draw a value from\n*that* strategy. So in this case we're first drawing a company, and then we're\ndrawing a list of shops belonging to that company: The |st.just| strategy is a\nstrategy such that drawing it always produces the individual value, so\n``from_model(Shop, company=just(company))`` is a strategy that generates a Shop belonging\nto the original company.\n\nSo the following code would give us a list of shops all belonging to the same\ncompany:\n\n.. code:: python\n\n  from_model(Company).flatmap(lambda c: lists(from_model(Shop, company=just(c))))\n\nThe only difference from this and the above is that we want the company, not\nthe shops. This is where the inner map comes in. We build the list of shops\nand then throw it away, instead returning the company we started for. This\nworks because the models that Hypothesis generates are saved in the database,\nso we're essentially running the inner strategy purely for the side effect of\ncreating those children in the database.\n\n\n.. _django-generating-primary-key:\n\nGenerating primary key values\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf your model includes a custom primary key that you want to generate\nusing a strategy (rather than a default auto-increment primary key)\nthen Hypothesis has to deal with the possibility of a duplicate\nprimary key.\n\nIf a model strategy generates a value for the primary key field,\nHypothesis will create the model instance with\n:meth:`~django:django.db.models.query.QuerySet.update_or_create`,\noverwriting any existing instance in the database for this test case\nwith the same primary key.\n\n\nOn the subject of ``MultiValueField``\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDjango forms feature the :class:`~django:django.forms.MultiValueField`\nwhich allows for several fields to be combined under a single named field, the\ndefault example of this is the :class:`~django:django.forms.SplitDateTimeField`.\n\n.. code:: python\n\n  class CustomerForm(forms.Form):\n      name = forms.CharField()\n      birth_date_time = forms.SplitDateTimeField()\n\n|django.from_form| supports ``MultiValueField`` subclasses directly, however if you\nwant to define your own strategy be forewarned that Django binds data for a\n``MultiValueField`` in a peculiar way. Specifically each sub-field is expected\nto have its own entry in ``data`` addressed by the field name\n(e.g. ``birth_date_time``) and the index of the sub-field within the\n``MultiValueField``, so form ``data`` for the example above might look\nlike this:\n\n.. code:: python\n\n  {\n      \"name\": \"Samuel John\",\n      \"birth_date_time_0\": \"2018-05-19\",  # the date, as the first sub-field\n      \"birth_date_time_1\": \"15:18:00\",  # the time, as the second sub-field\n  }\n\nThus, if you want to define your own strategies for such a field you must\naddress your sub-fields appropriately:\n\n.. code:: python\n\n  from_form(CustomerForm, birth_date_time_0=just(\"2018-05-19\"))\n\n.. _fuzz_one_input:\n\nExternal fuzzers\n----------------\n\n.. autodata:: hypothesis.core.HypothesisHandle.fuzz_one_input\n\n.. _custom-function-execution:\n\nCustom function execution\n-------------------------\n\nHypothesis provides you with a hook that lets you control how it runs examples.\n\nThis lets you do things like set up and tear down around each example, run examples in a subprocess, transform coroutine tests into normal tests, etc. For example, :class:`~hypothesis.extra.django.TransactionTestCase` in the Django extra runs each example in a separate database transaction.\n\nThe way this works is by introducing the concept of an executor. An executor is essentially a function that takes a block of code and run it. The default executor is:\n\n.. code:: python\n\n    def default_executor(function):\n        return function()\n\nYou define executors by defining a method ``execute_example`` on a class. Any test methods on that class with |@given| used on them will use ``self.execute_example`` as an executor with which to run tests. For example, the following executor runs all its code twice:\n\n.. code:: python\n\n    from unittest import TestCase\n\n    class TestTryReallyHard(TestCase):\n        @given(integers())\n        def test_something(self, i):\n            perform_some_unreliable_operation(i)\n\n        def execute_example(self, f):\n            f()\n            return f()\n\nNote: The functions you use in map, etc. will run *inside* the executor. i.e. they will not be called until you invoke the function passed to ``execute_example``.\n\nAn executor must be able to handle being passed a function which returns None, otherwise it won't be able to run normal test cases. So for example the following executor is invalid:\n\n.. code:: python\n\n    from unittest import TestCase\n\n    class TestRunTwice(TestCase):\n        def execute_example(self, f):\n            return f()()\n\nand should be rewritten as:\n\n.. code:: python\n\n    from unittest import TestCase\n\n    class TestRunTwice(TestCase):\n        def execute_example(self, f):\n            result = f()\n            if callable(result):\n                result = result()\n            return result\n\nAn alternative hook is provided for use by test runner extensions such as :pypi:`pytest-trio`, which cannot use the ``execute_example`` method. This is **not** recommended for end-users - it is better to write a complete test function directly, perhaps by using a decorator to perform the same transformation before applying |@given|.\n\n.. code:: python\n\n    @given(x=integers())\n    @pytest.mark.trio\n    async def test(x): ...\n\n    # Illustrative code, inside the pytest-trio plugin\n    test.hypothesis.inner_test = lambda x: trio.run(test, x)\n\nFor authors of test runners however, assigning to the ``inner_test`` attribute of the ``hypothesis`` attribute of the test will replace the interior test.\n\n.. note::\n    The new ``inner_test`` must accept and pass through all the ``*args``\n    and ``**kwargs`` expected by the original test.\n\nIf the end user has also specified a custom executor using the ``execute_example`` method, it - and all other execution-time logic - will be applied to the *new* inner test assigned by the test runner.\n\nDetection\n---------\n\n.. autofunction:: hypothesis.is_hypothesis_test\n.. autofunction:: hypothesis.currently_in_test_context\n"
  },
  {
    "path": "hypothesis-python/docs/reference/index.rst",
    "content": "API Reference\n=============\n\nThe technical API reference for Hypothesis is split into four pages:\n\n* :doc:`API Reference </reference/api>`. Non-strategy Hypothesis objects, classes, and functions. |@given| and others live here.\n* :doc:`Strategies Reference </reference/strategies>`. Hypothesis strategies, including for :doc:`extras </extras>`.\n* :doc:`Integrations Reference </reference/integrations>`. Features with a defined interface, but no code API.\n* :doc:`Hypothesis internals </reference/internals>`. Internal APIs for developers building tools, libraries, or research on top of Hypothesis.\n\n.. toctree::\n   :hidden:\n   :maxdepth: 1\n\n   api\n   strategies\n   integrations\n   internals\n"
  },
  {
    "path": "hypothesis-python/docs/reference/integrations.rst",
    "content": "Integrations Reference\n======================\n\nReference for Hypothesis features with a defined interface, but no code API.\n\n.. _ghostwriter:\n\nGhostwriter\n-----------\n\n.. automodule:: hypothesis.extra.ghostwriter\n   :members:\n\nA note for test-generation researchers\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nGhostwritten tests are intended as a *starting point for human authorship*,\nto demonstrate best practice, help novices past blank-page paralysis, and save time\nfor experts.  They *may* be ready-to-run, or include placeholders and ``# TODO:``\ncomments to fill in strategies for unknown types.  In either case, improving tests\nfor their own code gives users a well-scoped and immediately rewarding context in\nwhich to explore property-based testing.\n\nBy contrast, most test-generation tools aim to produce ready-to-run test suites...\nand implicitly assume that the current behavior is the desired behavior.\nHowever, the code might contain bugs, and we want our tests to fail if it does!\nWorse, tools require that the code to be tested is finished and executable,\nmaking it impossible to generate tests as part of the development process.\n\n`Fraser 2013`_ found that evolving a high-coverage test suite (e.g. Randoop_, EvoSuite_, Pynguin_)\n\"leads to clear improvements in commonly applied quality metrics such as code coverage\n[but] no measurable improvement in the number of bugs actually found by developers\"\nand that \"generating a set of test cases, even high coverage test cases,\ndoes not necessarily improve our ability to test software\".\nInvariant detection (famously Daikon_; in PBT see e.g. `Alonso 2022`_,\nQuickSpec_, Speculate_) relies on code execution. Program slicing (e.g. FUDGE_,\nFuzzGen_, WINNIE_) requires downstream consumers of the code to test.\n\nGhostwriter inspects the function name, argument names and types, and docstrings.\nIt can be used on buggy or incomplete code, runs in a few seconds, and produces\na single semantically-meaningful test per function or group of functions.\nRather than detecting regressions, these tests check semantic properties such as\n`encode/decode or save/load round-trips <https://zhd.dev/ghostwriter/?q=gzip.compress>`__,\nfor `commutative, associative, and distributive operations\n<https://zhd.dev/ghostwriter/?q=operator.mul>`__,\n`equivalence between methods <https://zhd.dev/ghostwriter/?q=operator.add+numpy.add>`__,\n`array shapes <https://zhd.dev/ghostwriter/?q=numpy.matmul>`__,\nand idempotence.  Where no property is detected, we simply check for\n'no error on valid input' and allow the user to supply their own invariants.\n\nEvaluations such as the SBFT24_ competition_ measure performance on a task which\nthe Ghostwriter is not intended to perform.  I'd love to see qualitative user\nstudies, such as `PBT in Practice`_ for test generation, which could check\nwhether the Ghostwriter is onto something or tilting at windmills.\nIf you're interested in similar questions, `drop me an email`_!\n\n.. _Daikon: https://plse.cs.washington.edu/daikon/pubs/\n.. _Alonso 2022: https://doi.org/10.1145/3540250.3559080\n.. _QuickSpec: http://www.cse.chalmers.se/~nicsma/papers/quickspec2.pdf\n.. _Speculate: https://matela.com.br/speculate.pdf\n.. _FUDGE: https://research.google/pubs/pub48314/\n.. _FuzzGen: https://www.usenix.org/conference/usenixsecurity20/presentation/ispoglou\n.. _WINNIE: https://www.ndss-symposium.org/wp-content/uploads/2021-334-paper.pdf\n.. _Fraser 2013: https://doi.org/10.1145/2483760.2483774\n.. _Randoop: https://homes.cs.washington.edu/~mernst/pubs/feedback-testgen-icse2007.pdf\n.. _EvoSuite: https://www.evosuite.org/wp-content/papercite-data/pdf/esecfse11.pdf\n.. _Pynguin: https://arxiv.org/abs/2007.14049\n.. _SBFT24: https://arxiv.org/abs/2401.15189\n.. _competition: https://github.com/ThunderKey/python-tool-competition-2024\n.. _PBT in Practice: https://harrisongoldste.in/papers/icse24-pbt-in-practice.pdf\n.. _drop me an email: mailto:zac@zhd.dev?subject=Hypothesis%20Ghostwriter%20research\n\n.. _observability:\n\nObservability\n-------------\n\n.. note::\n\n  The `Tyche <https://github.com/tyche-pbt/tyche-extension>`__ VSCode extension provides an in-editor UI for observability results generated by Hypothesis. If you want to *view* observability results, rather than programmatically consume or display them, we recommend using Tyche.\n\n.. warning::\n\n    This feature is experimental, and could have breaking changes or even be removed\n    without notice.  Try it out, let us know what you think, but don't rely on it\n    just yet!\n\n\nMotivation\n~~~~~~~~~~\n\nUnderstanding what your code is doing - for example, why your test failed - is often\na frustrating exercise in adding some more instrumentation or logging (or ``print()`` calls)\nand running it again.  The idea of :wikipedia:`observability <Observability_(software)>`\nis to let you answer questions you didn't think of in advance.  In slogan form,\n\n  *Debugging should be a data analysis problem.*\n\nBy default, Hypothesis only reports the minimal failing example... but sometimes you might\nwant to know something about *all* the examples.  Printing them to the terminal by increasing\n|Verbosity| might be nice, but isn't always enough.\nThis feature gives you an analysis-ready dataframe with useful columns and one row\nper test case, with columns from arguments to code coverage to pass/fail status.\n\nThis is deliberately a much lighter-weight and task-specific system than e.g.\n`OpenTelemetry <https://opentelemetry.io/>`__.  It's also less detailed than time-travel\ndebuggers such as `rr <https://rr-project.org/>`__ or `pytrace <https://pytrace.com/>`__,\nbecause there's no good way to compare multiple traces from these tools and their\nPython support is relatively immature.\n\n\nConfiguration\n~~~~~~~~~~~~~\n\nIf you set the ``HYPOTHESIS_EXPERIMENTAL_OBSERVABILITY`` environment variable,\nHypothesis will log various observations to jsonlines files in the\n``.hypothesis/observed/`` directory.  You can load and explore these with e.g.\n:func:`pd.read_json(\".hypothesis/observed/*_testcases.jsonl\", lines=True) <pandas.read_json>`,\nor by using the :pypi:`sqlite-utils` and :pypi:`datasette` libraries::\n\n    sqlite-utils insert testcases.db testcases .hypothesis/observed/*_testcases.jsonl --nl --flatten\n    datasette serve testcases.db\n\nIf you are experiencing a significant slow-down, you can try setting\n``HYPOTHESIS_EXPERIMENTAL_OBSERVABILITY_NOCOVER`` instead; this will disable coverage information\ncollection. This should not be necessary on Python 3.12 or later, where coverage collection is very fast.\n\n\nCollecting more information\n^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nIf you want to record more information about your test cases than the arguments and\noutcome - for example, was ``x`` a binary tree?  what was the difference between the\nexpected and the actual value?  how many queries did it take to find a solution? -\nHypothesis makes this easy.\n\n:func:`~hypothesis.event` accepts a string label, and optionally a string or int or\nfloat observation associated with it.  All events are collected and summarized in\n:ref:`statistics`, as well as included on a per-test-case basis in our observations.\n\n:func:`~hypothesis.target` is a special case of numeric-valued events: as well as\nrecording them in observations, Hypothesis will try to maximize the targeted value.\nKnowing that, you can use this to guide the search for failing inputs.\n\n\nData Format\n~~~~~~~~~~~\n\nWe dump observations in `json lines format <https://jsonlines.org/>`__, with each line\ndescribing either a test case or an information message.  The tables below are derived\nfrom :download:`this machine-readable JSON schema <schema_observations.json>`, to\nprovide both readable and verifiable specifications.\n\nNote that we use :func:`python:json.dumps` and can therefore emit non-standard JSON\nwhich includes infinities and NaN.  This is valid in `JSON5 <https://json5.org/>`__,\nand supported by `some JSON parsers <https://evanhahn.com/pythons-nonstandard-json-encoding/>`__\nincluding Gson in Java, ``JSON.parse()`` in Ruby, and of course in Python.\n\nInformation message\n^^^^^^^^^^^^^^^^^^^\n\n.. jsonschema:: ./schema_observations.json#/oneOf/1\n   :hide_key: /additionalProperties, /type\n\nTest case\n^^^^^^^^^\n\n.. jsonschema:: ./schema_observations.json#/oneOf/0\n   :hide_key: /additionalProperties, /type\n\n.. _observability-hypothesis-metadata:\n\nHypothesis metadata\n+++++++++++++++++++\n\nWhile the observability format is agnostic to the property-based testing library which generated it, Hypothesis includes specific values in the ``metadata`` key for test cases. You may rely on these being present if and only if the observation was generated by Hypothesis.\n\n.. jsonschema:: ./schema_metadata.json\n   :hide_key: /additionalProperties, /type\n\nChoices metadata\n++++++++++++++++\n\nThese additional metadata elements are included in ``metadata`` (as e.g. ``metadata[\"choice_nodes\"]`` or ``metadata[\"choice_spans\"]``), if and only if |OBSERVABILITY_CHOICES| is set.\n\n.. jsonschema:: ./schema_metadata_choices.json\n   :hide_key: /additionalProperties, /type\n\n.. _pytest-plugin:\n\nThe Hypothesis pytest plugin\n----------------------------\n\nHypothesis includes a tiny plugin to improve integration with :pypi:`pytest`, which is activated by default (but does not affect other test runners). It aims to improve the integration between Hypothesis and Pytest by providing extra information and convenient access to config options.\n\n- ``pytest --hypothesis-show-statistics`` can be used to :ref:`display test and data generation statistics <statistics>`.\n- ``pytest --hypothesis-profile=<profile name>`` can be used to load a settings profile (as in |settings.load_profile|).\n- ``pytest --hypothesis-verbosity=<level name>`` can be used to override the current |Verbosity| setting.\n- ``pytest --hypothesis-seed=<an int>`` can be used to reproduce a failure with a particular seed (as in |@seed|).\n- ``pytest --hypothesis-explain`` can be used to temporarily enable |Phase.explain|.\n\nFinally, all tests that are defined with Hypothesis automatically have ``@pytest.mark.hypothesis`` applied to them.  See :ref:`here for information on working with markers <pytest:mark examples>`.\n\n.. note::\n    Pytest will load the plugin automatically if Hypothesis is installed. You don't need to do anything at all to use it.\n\n    If this causes problems, you can avoid loading the plugin with the ``-p no:hypothesispytest`` option.\n\n.. _statistics:\n\nTest statistics\n~~~~~~~~~~~~~~~\n\n.. note::\n\n  While test statistics are only available under pytest, you can use the :ref:`observability <observability>` interface to view similar information about your tests.\n\nYou can see a number of statistics about executed tests by passing the command line argument ``--hypothesis-show-statistics``. This will include some general statistics about the test:\n\nFor example if you ran the following with ``--hypothesis-show-statistics``:\n\n.. code-block:: python\n\n  from hypothesis import given, strategies as st\n\n  @given(st.integers())\n  def test_integers(i):\n      pass\n\nYou would see:\n\n.. code-block:: none\n\n    - during generate phase (0.06 seconds):\n        - Typical runtimes: < 1ms, ~ 47% in data generation\n        - 100 passing examples, 0 failing examples, 0 invalid examples\n    - Stopped because settings.max_examples=100\n\nThe final \"Stopped because\" line tells you why Hypothesis stopped generating new examples. This is typically because we hit |max_examples|, but occasionally because we exhausted the search space or because shrinking was taking a very long time. This can be useful for understanding the behaviour of your tests.\n\nIn some cases (such as filtered and recursive strategies) you will see events mentioned which describe some aspect of the data generation:\n\n.. code-block:: python\n\n  from hypothesis import given, strategies as st\n\n  @given(st.integers().filter(lambda x: x % 2 == 0))\n  def test_even_integers(i):\n      pass\n\nYou would see something like:\n\n.. code-block:: none\n\n  test_even_integers:\n\n    - during generate phase (0.08 seconds):\n        - Typical runtimes: < 1ms, ~ 57% in data generation\n        - 100 passing examples, 0 failing examples, 12 invalid examples\n        - Events:\n          * 51.79%, Retried draw from integers().filter(lambda x: x % 2 == 0) to satisfy filter\n          * 10.71%, Aborted test because unable to satisfy integers().filter(lambda x: x % 2 == 0)\n    - Stopped because settings.max_examples=100\n\n.. _hypothesis-cli:\n\nhypothesis[cli]\n----------------\n\n.. note::\n\n  This feature requires the ``hypothesis[cli]`` :doc:`extra </extras>`, via ``pip install hypothesis[cli]``.\n\n.. automodule:: hypothesis.extra.cli\n\n.. _codemods:\n\nhypothesis[codemods]\n--------------------\n\n.. note::\n\n  This feature requires the ``hypothesis[codemods]`` :doc:`extra </extras>`, via ``pip install hypothesis[codemods]``.\n\n.. automodule:: hypothesis.extra.codemods\n\n.. _hypothesis-dpcontracts:\n\nhypothesis[dpcontracts]\n-----------------------\n\n.. note::\n\n  This feature requires the ``hypothesis[dpcontracts]`` :doc:`extra </extras>`, via ``pip install hypothesis[dpcontracts]``.\n\n.. tip::\n\n   For new projects, we recommend using either :pypi:`deal` or :pypi:`icontract`\n   and :pypi:`icontract-hypothesis` over :pypi:`dpcontracts`.\n   They're generally more powerful tools for design-by-contract programming,\n   and have substantially nicer Hypothesis integration too!\n\n.. automodule:: hypothesis.extra.dpcontracts\n   :members:\n"
  },
  {
    "path": "hypothesis-python/docs/reference/internals.rst",
    "content": "Hypothesis internals\n====================\n\n.. warning::\n\n    This page documents internal Hypothesis interfaces. Some are fairly stable, while others are still experimental. In either case, they are not subject to our standard :ref:`deprecation policy <deprecation-policy>`, and we might make breaking changes in minor or patch releases.\n\n    This page is intended for people building tools, libraries, or research on top of Hypothesis. If that includes you, please get in touch! We'd love to hear what you're doing, or explore more stable ways to support your use-case.\n\n.. _alternative-backends-internals:\n\nAlternative backends\n--------------------\n\n.. seealso::\n\n    See also the user-facing :ref:`alternative-backends` documentation.\n\n.. autoclass:: hypothesis.internal.conjecture.providers.PrimitiveProvider\n    :members:\n\n.. autodata:: hypothesis.internal.conjecture.providers.AVAILABLE_PROVIDERS\n    :no-value:\n\n.. autofunction:: hypothesis.internal.conjecture.provider_conformance.run_conformance_test\n\n.. autoclass:: hypothesis.errors.BackendCannotProceed\n.. autoclass:: hypothesis.internal.intervalsets.IntervalSet\n\nObservability\n-------------\n\n.. autofunction:: hypothesis.internal.observability.add_observability_callback\n.. autofunction:: hypothesis.internal.observability.remove_observability_callback\n.. autofunction:: hypothesis.internal.observability.with_observability_callback\n.. autofunction:: hypothesis.internal.observability.observability_enabled\n\n.. autodata:: hypothesis.internal.observability.TESTCASE_CALLBACKS\n.. autodata:: hypothesis.internal.observability.OBSERVABILITY_COLLECT_COVERAGE\n.. autodata:: hypothesis.internal.observability.OBSERVABILITY_CHOICES\n\nEngine constants\n----------------\n\nWe pick reasonable values for these constants, but if you must, you can monkeypatch them. (Hypothesis is not responsible for any performance degradation that may result).\n\n.. autodata:: hypothesis.internal.conjecture.engine.MAX_SHRINKS\n.. autodata:: hypothesis.internal.conjecture.engine.MAX_SHRINKING_SECONDS\n.. autodata:: hypothesis.internal.conjecture.engine.BUFFER_SIZE\n"
  },
  {
    "path": "hypothesis-python/docs/reference/schema_metadata.json",
    "content": "{\n    \"type\": \"object\",\n    \"properties\": {\n        \"traceback\": {\n            \"type\": [\"string\", \"null\"],\n            \"description\": \"The traceback for failing tests, if and only if ``status == \\\"failed\\\"``.\"\n        },\n        \"reproduction_decorator\": {\n            \"type\": [\"string\", \"null\"],\n            \"description\": \"The ``@reproduce_failure`` decorator string for failing tests, if and only if ``status == \\\"failed\\\"``.\"\n        },\n        \"predicates\": {\n            \"type\": \"object\",\n            \"description\": \"The number of times each |assume| and |@precondition| predicate was satisfied (``True``) and not satisfied (``False``).\",\n            \"additionalProperties\": {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"satisfied\": {\n                        \"type\": \"integer\",\n                        \"minimum\": 0,\n                        \"description\": \"The number of times this predicate was satisfied (``True``).\"\n                    },\n                    \"unsatisfied\": {\n                        \"type\": \"integer\",\n                        \"minimum\": 0,\n                        \"description\": \"The number of times this predicate was not satisfied (``False``).\"\n                    }\n                },\n                \"required\": [\"satisfied\", \"unsatisfied\"],\n                \"additionalProperties\": false\n            }\n        },\n        \"backend\": {\n            \"type\": \"object\",\n            \"description\": \"Backend-specific observations from |PrimitiveProvider.observe_test_case| and |PrimitiveProvider.observe_information_messages|.\"\n        },\n        \"sys.argv\": {\n            \"type\": \"array\",\n            \"items\": {\"type\": \"string\"},\n            \"description\": \"The result of ``sys.argv``.\"\n        },\n        \"os.getpid()\": {\n            \"type\": \"integer\",\n            \"description\": \"The result of ``os.getpid()``.\"\n        },\n        \"imported_at\": {\n            \"type\": \"number\",\n            \"description\": \"The unix timestamp when Hypothesis was imported.\"\n        },\n        \"phase\": {\n            \"type\": \"string\",\n            \"description\": \"The Hypothesis |Phase| this test case was generated in.\"\n        },\n        \"data_status\": {\n            \"type\": \"number\",\n            \"enum\": [0, 1, 2, 3],\n            \"description\": \"The internal status of the ConjectureData for this test case. The values are as follows: ``Status.OVERRUN = 0``, ``Status.INVALID = 1``, ``Status.VALID = 2``, and ``Status.INTERESTING = 3``.\"\n        },\n        \"interesting_origin\": {\n            \"type\": [\"string\", \"null\"],\n            \"description\": \"The internal ``InterestingOrigin`` object for failing tests, if and only if ``status == \\\"failed\\\"``. The ``traceback`` string value is derived from this object.\"\n        }\n    },\n    \"required\": [\"traceback\", \"reproduction_decorator\", \"predicates\", \"backend\", \"sys.argv\", \"os.getpid()\", \"imported_at\", \"data_status\", \"interesting_origin\"],\n    \"additionalProperties\": false\n}\n"
  },
  {
    "path": "hypothesis-python/docs/reference/schema_metadata_choices.json",
    "content": "{\n    \"type\": \"object\",\n    \"properties\": {\n        \"choice_nodes\": {\n            \"type\": [\"array\", \"null\"],\n            \"description\": \".. warning::\\n\\n  EXPERIMENTAL AND UNSTABLE. This attribute may change format or disappear without warning.\\n\\nThe sequence of choices made during this test case. This includes the choice value, as well as its constraints and whether it was forced or not.\\n\\nOnly present if |OBSERVABILITY_CHOICES| is ``True``.\\n\\n.. note::\\n\\n  The choice sequence is a relatively low-level implementation detail of Hypothesis, and is exposed in observability for users building tools or research on top of Hypothesis. See |PrimitiveProvider| for more details about the choice sequence.\",\n            \"items\": {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"type\": {\n                        \"type\": \"string\",\n                        \"enum\": [\"integer\", \"float\", \"string\", \"bytes\", \"boolean\"],\n                        \"description\": \"The type of choice made. Corresponds to a call to |PrimitiveProvider.draw_integer|, |PrimitiveProvider.draw_float|, |PrimitiveProvider.draw_string|, |PrimitiveProvider.draw_bytes|, or |PrimitiveProvider.draw_boolean|.\"\n                    },\n                    \"value\": {\n                        \"description\": \"The value of the choice. Corresponds to the value returned by a ``PrimitiveProvider.draw_*`` method.\\n\\n``NaN`` float values are returned as ``[\\\"float\\\", <float64_int_value>]``, to distinguish ``NaN`` floats with nonstandard bit patterns. Integers with  ``abs(value) >= 2**63`` are returned as ``[\\\"integer\\\", str(value)]``, for compatibility with tools with integer size limitations. Bytes are returned as ``[\\\"bytes\\\", base64.b64encode(value)]``.\"\n                    },\n                    \"constraints\": {\n                        \"type\": \"object\",\n                        \"description\": \"The constraints for this choice. Corresponds to the constraints passed to a ``PrimitiveProvider.draw_*`` method. ``NaN`` float values, integers with ``abs(value) >= 2**63``, and byte values for constraints are transformed as for the ``value`` attribute.\"\n                    },\n                    \"was_forced\": {\n                        \"type\": \"boolean\",\n                        \"description\": \"Whether this choice was forced. As an implementation detail, Hypothesis occasionally requires that some choices take on a specific value, for instance to end generation of collection elements early for performance. These values are called \\\"forced\\\", and have ``was_forced = True``.\"\n                    }\n                },\n                \"required\": [\"type\", \"value\", \"constraints\", \"was_forced\"],\n                \"additionalProperties\": false\n            }\n        },\n        \"choice_spans\": {\n            \"type\": \"array\",\n            \"items\": {\"type\": \"array\"},\n            \"description\": \".. warning::\\n\\n  EXPERIMENTAL AND UNSTABLE. This attribute may change format or disappear without warning.\\n\\nThe semantically-meaningful spans of the choice sequence of this test case.\\n\\nEach span has the format ``[label, start, end, discarded]``, where:\\n\\n* ``label`` is an opaque integer-value string shared by all spans drawn from a particular strategy.\\n* ``start`` and ``end`` are indices into the choice sequence for this span, such that ``choices[start:end]`` are the corresponding choices.\\n* ``discarded`` is a boolean indicating whether this span was discarded (see |PrimitiveProvider.span_end|).\\n\\nOnly present if |OBSERVABILITY_CHOICES| is ``True``.\\n\\n.. note::\\n\\n  Spans are a relatively low-level implementation detail of Hypothesis, and are exposed in observability for users building tools or research on top of Hypothesis. See |PrimitiveProvider| (and particularly |PrimitiveProvider.span_start| and |PrimitiveProvider.span_end|) for more details about spans.\"\n        }\n    },\n    \"required\": [\"traceback\", \"reproduction_decorator\", \"predicates\", \"backend\", \"sys.argv\", \"os.getpid()\", \"imported_at\", \"data_status\", \"interesting_origin\", \"choice_nodes\", \"choice_spans\"],\n    \"additionalProperties\": false\n}\n"
  },
  {
    "path": "hypothesis-python/docs/reference/schema_observations.json",
    "content": "{\n    \"title\": \"PBT Observations\",\n    \"description\": \"PBT Observations define a standard way to communicate what happened when property-based tests were run.  They describe test cases, or general notifications classified as info, alert, or error messages.\",\n    \"oneOf\": [\n        {\n            \"description\": \"Describes the inputs to and result of running some test function on a particular input.  The test might have passed, failed, or been abandoned part way through (e.g. because we failed a |.filter| condition).\",\n            \"type\": \"object\",\n            \"properties\": {\n                \"type\": {\n                    \"const\": \"test_case\",\n                    \"description\": \"A tag which labels this observation as data about a specific test case.\"\n                },\n                \"status\": {\n                    \"enum\": [\"passed\", \"failed\", \"gave_up\"],\n                    \"description\": \"Whether the test passed, failed, or was aborted before completion (e.g. due to use of |.filter|).  Note that if we gave_up partway, values such as arguments and features may be incomplete.\"\n                },\n                \"status_reason\": {\n                    \"type\": \"string\",\n                    \"description\": \"If non-empty, the reason for which the test failed or was abandoned.  For Hypothesis, this is usually the exception type and location.\"\n                },\n                \"representation\": {\n                    \"type\": \"string\",\n                    \"description\": \"The string representation of the input. In Hypothesis, this includes the property name and arguments (like ``test_a(a=1)``), any interactive draws from |st.data|, and additionally some comments from |Phase.explain| for failing examples.\"\n                },\n                \"arguments\": {\n                    \"type\": \"object\",\n                    \"description\": \"A structured json-encoded representation of the input.  Hypothesis provides a dictionary of argument names to json-ified values, including interactive draws from the |st.data| strategy.  If 'status' is 'gave_up', this may be absent or incomplete.  In other libraries this can be any object.\"\n                },\n                \"how_generated\": {\n                    \"type\": [\"string\", \"null\"],\n                    \"description\": \"How the input was generated, if known.  In Hypothesis this might be an explicit example, generated during a particular phase with some backend, or by replaying the minimal failing example.\"\n                },\n                \"features\": {\n                    \"type\": \"object\",\n                    \"description\": \"Runtime observations which might help explain what this test case did.  Hypothesis includes |target| scores, tags from |event|, and so on.\"\n                },\n                \"coverage\": {\n                    \"type\": [\"object\", \"null\"],\n                    \"description\": \"Mapping of filename to list of covered line numbers, if coverage information is available, or None if not.  Hypothesis deliberately omits stdlib and site-packages code.\",\n                    \"additionalProperties\": {\n                        \"type\": \"array\",\n                        \"items\": {\"type\": \"integer\", \"minimum\": 1},\n                        \"uniqueItems\": true\n                    }\n                },\n                \"timing\": {\n                    \"type\": \"object\",\n                    \"description\": \"The time in seconds taken by non-overlapping parts of this test case.  Hypothesis reports ``execute:test``, ``overall:gc``, and ``generate:{argname}`` for each argument.\",\n                    \"additionalProperties\": {\n                        \"type\": \"number\",\n                        \"minimum\": 0\n                    }\n                },\n                \"metadata\": {\n                    \"type\": \"object\",\n                    \"description\": \"Arbitrary metadata which might be of interest, but does not semantically fit in 'features'.  For example, Hypothesis includes the traceback for failing tests here.\"\n                },\n                \"property\": {\n                    \"type\": \"string\",\n                    \"description\": \"The name or representation of the test function we're running.\"\n                },\n                \"run_start\": {\n                    \"type\": \"number\",\n                    \"description\": \"unix timestamp at which we started running this test function, so that later analysis can group test cases by run.\"\n                }\n            },\n            \"required\": [\"type\", \"status\", \"status_reason\", \"representation\", \"arguments\", \"how_generated\", \"features\", \"coverage\", \"timing\", \"metadata\", \"property\", \"run_start\"],\n            \"additionalProperties\": false\n        },\n        {\n            \"description\": \"Info, alert, and error messages correspond to a group of test cases or the overall run, and are intended for humans rather than machine analysis.\",\n            \"type\": \"object\",\n            \"properties\": {\n                \"type\": {\n                    \"enum\": [\"info\", \"alert\", \"error\"],\n                    \"description\": \"A tag which labels this observation as general information to show the user.  Hypothesis uses info messages to report statistics; alert or error messages can be provided by plugins.\"\n                },\n                \"title\": {\n                    \"type\": \"string\",\n                    \"description\": \"The title of this message\"\n                },\n                \"content\": {\n                    \"type\": [\"string\", \"object\"],\n                    \"description\": \"The body of the message.  Strings are presumed to be human-readable messages in markdown format; dictionaries may contain arbitrary information (as for test-case metadata).\"\n                },\n                \"property\": {\n                    \"type\": \"string\",\n                    \"description\": \"The name or representation of the test function we're running.  For Hypothesis, usually the Pytest nodeid.\"\n                },\n                \"run_start\": {\n                    \"type\": \"number\",\n                    \"description\": \"unix timestamp at which we started running this test function, so that later analysis can group test cases by run.\"\n                }\n            },\n            \"required\": [\"type\", \"title\", \"content\", \"property\", \"run_start\"],\n            \"additionalProperties\": false\n        }\n    ]\n}\n"
  },
  {
    "path": "hypothesis-python/docs/reference/strategies.rst",
    "content": ".. _strategies:\n\nStrategies Reference\n====================\n\nStrategies are the way Hypothesis describes the values for |@given| to generate.  For instance, passing the strategy ``st.lists(st.integers(), min_size=1)`` to |@given| tells Hypothesis to generate lists of integers with at least one element.\n\nThis reference page lists all of Hypothesis' first-party functions which return a strategy. There are also many provided by :doc:`third-party libraries </extensions>`.  Note that we often say \"strategy\" when we mean \"function returning a strategy\"; it's usually clear from context which one we mean.\n\nStrategies can be passed to other strategies as arguments, combined using :ref:`combinator strategies <combinators>`, or modified using |.filter|, |.map|, or |.flatmap|.\n\nPrimitives\n----------\n\n.. autofunction:: hypothesis.strategies.none\n.. autofunction:: hypothesis.strategies.nothing\n.. autofunction:: hypothesis.strategies.just\n.. autofunction:: hypothesis.strategies.booleans\n\nNumeric\n-------\n\n.. seealso::\n\n  See also the separate sections for :ref:`Numpy strategies <hypothesis-numpy>`, :ref:`Pandas strategies <hypothesis-pandas>`, and :ref:`Array API strategies <array-api>`.\n\n.. autofunction:: hypothesis.strategies.integers\n.. autofunction:: hypothesis.strategies.floats\n.. autofunction:: hypothesis.strategies.complex_numbers\n.. autofunction:: hypothesis.strategies.decimals\n.. autofunction:: hypothesis.strategies.fractions\n\nStrings\n-------\n\n.. note::\n\n  The |st.uuids| and |st.ip_addresses| strategies generate instances of :mod:`UUID <python:uuid>` and :mod:`IPAddress <python:ipaddress>` respectively. You can generate corresponding string values by using |.map|, such as ``st.uuids().map(str)``.\n\n.. autofunction:: hypothesis.strategies.text\n.. autofunction:: hypothesis.strategies.characters\n.. autofunction:: hypothesis.strategies.from_regex\n.. autofunction:: hypothesis.strategies.binary\n.. autofunction:: hypothesis.strategies.emails\n\n.. autofunction:: hypothesis.provisional.domains\n\n.. warning::\n\n  The |st.domains| strategy is provisional. Its interface may be changed in a minor release, without being subject to our :ref:`deprecation policy <deprecation-policy>`. That said, we expect it to be relatively stable.\n\n.. autofunction:: hypothesis.provisional.urls\n\n.. warning::\n\n  The |st.urls| strategy is provisional. Its interface may be changed in a minor release, without being subject to our :ref:`deprecation policy <deprecation-policy>`. That said, we expect it to be relatively stable.\n\nCollections\n-----------\n\n.. autofunction:: hypothesis.strategies.lists\n.. autofunction:: hypothesis.strategies.tuples\n.. autofunction:: hypothesis.strategies.sets\n.. autofunction:: hypothesis.strategies.frozensets\n.. autofunction:: hypothesis.strategies.dictionaries\n.. autofunction:: hypothesis.strategies.fixed_dictionaries\n.. autofunction:: hypothesis.strategies.iterables\n\nDatetime\n--------\n\n.. autofunction:: hypothesis.strategies.dates\n.. autofunction:: hypothesis.strategies.times\n.. autofunction:: hypothesis.strategies.datetimes\n.. autofunction:: hypothesis.strategies.timezones\n.. autofunction:: hypothesis.strategies.timezone_keys\n.. autofunction:: hypothesis.strategies.timedeltas\n\nRecursive\n---------\n\n.. autofunction:: hypothesis.strategies.recursive\n.. autofunction:: hypothesis.strategies.deferred\n\nRandom\n------\n\n.. autofunction:: hypothesis.strategies.randoms\n.. autofunction:: hypothesis.strategies.random_module\n.. autofunction:: hypothesis.register_random\n\n.. _combinators:\n\nCombinators\n-----------\n\n.. autofunction:: hypothesis.strategies.one_of\n.. autofunction:: hypothesis.strategies.builds\n.. autofunction:: hypothesis.strategies.composite\n.. autofunction:: hypothesis.strategies.data\n\nTyping\n------\n\n.. autofunction:: hypothesis.strategies.from_type\n.. autofunction:: hypothesis.strategies.register_type_strategy\n\nHypothesis\n----------\n\n.. autofunction:: hypothesis.strategies.runner\n.. autofunction:: hypothesis.strategies.shared\n\nMisc\n----\n\n.. autofunction:: hypothesis.strategies.functions\n.. autofunction:: hypothesis.strategies.slices\n.. autofunction:: hypothesis.strategies.uuids\n.. autofunction:: hypothesis.strategies.ip_addresses\n\n.. autofunction:: hypothesis.strategies.sampled_from\n.. autofunction:: hypothesis.strategies.permutations\n\nRelated\n-------\n\n.. autoclass:: hypothesis.strategies.DrawFn\n.. autoclass:: hypothesis.strategies.DataObject\n\n  .. automethod:: hypothesis.strategies.DataObject.draw\n\n.. autoclass:: hypothesis.strategies.SearchStrategy\n\n  .. automethod:: hypothesis.strategies.SearchStrategy.example\n  .. automethod:: hypothesis.strategies.SearchStrategy.filter\n  .. automethod:: hypothesis.strategies.SearchStrategy.map\n  .. automethod:: hypothesis.strategies.SearchStrategy.flatmap\n\n.. _hypothesis-numpy:\n\nNumPy\n-----\n\nHypothesis offers a number of strategies for `NumPy <https://numpy.org/>`_ testing,\navailable in the ``hypothesis[numpy]`` :doc:`extra </extras>`.\nIt lives in the ``hypothesis.extra.numpy`` package.\n\nThe centerpiece is the :func:`~hypothesis.extra.numpy.arrays` strategy, which generates arrays with\nany dtype, shape, and contents you can specify or give a strategy for.\nTo make this as useful as possible, strategies are provided to generate array\nshapes and generate all kinds of fixed-size or compound dtypes.\n\n.. automodule:: hypothesis.extra.numpy\n   :members:\n   :exclude-members: ArrayStrategy, BasicIndexStrategy, BroadcastableShapes, MutuallyBroadcastableShapesStrategy\n\n\n.. _hypothesis-pandas:\n\npandas\n------\n\nHypothesis provides strategies for several of the core pandas data types:\n:class:`pandas.Index`, :class:`pandas.Series` and :class:`pandas.DataFrame`.\n\nThe general approach taken by the pandas module is that there are multiple\nstrategies for generating indexes, and all of the other strategies take the\nnumber of entries they contain from their index strategy (with sensible defaults).\nSo e.g. a Series is specified by specifying its :class:`numpy.dtype` (and/or\na strategy for generating elements for it).\n\n.. automodule:: hypothesis.extra.pandas\n   :members:\n\nSupported versions\n~~~~~~~~~~~~~~~~~~\n\nThere is quite a lot of variation between pandas versions. We only\ncommit to supporting the latest version of pandas, but older minor versions are\nsupported on a \"best effort\" basis.  Hypothesis is currently tested against\nand confirmed working with every Pandas minor version from 1.1 through to 2.2.\n\nReleases that are not the latest patch release of their minor version are not\ntested or officially supported, but will probably also work unless you hit a\npandas bug.\n\n\n.. _array-api:\n\nArray API\n---------\n\n.. note::\n\n  Several array libraries have more library-specific strategies, including :pypi:`Xarray <xarray>` (via their :ref:`upstream strategies <xarray:testing.hypothesis>`) and :pypi:`NumPy` (via :ref:`its Hypothesis extra <hypothesis-numpy>`). Of course, strategies in the Array API namespace can still be used to test Xarray or NumPy, just like any other array library.\n\nHypothesis offers strategies for `Array API <https://data-apis.org/>`_ adopting\nlibraries in the ``hypothesis.extra.array_api`` package. See :issue:`3037` for\nmore details.  If you want to test with :pypi:`CuPy <cupy>`, :pypi:`Dask <dask>`, :pypi:`JAX <jax>`,\n:pypi:`MXNet <maxnet>`, :pypi:`PyTorch <torch>`, :pypi:`TensorFlow <tensorflow>`, or :pypi:`Xarray <xarray>` -\nor just :pypi:`NumPy <numpy>` - this is the extension for you!\n\n.. autofunction:: hypothesis.extra.array_api.make_strategies_namespace\n\nThe resulting namespace contains all our familiar strategies like\n:func:`~xps.arrays` and :func:`~xps.from_dtype`, but based on the Array API\nstandard semantics and returning objects from the ``xp`` module:\n\n.. automodule:: xps\n   :members:\n        from_dtype,\n        arrays,\n        array_shapes,\n        scalar_dtypes,\n        boolean_dtypes,\n        numeric_dtypes,\n        real_dtypes,\n        integer_dtypes,\n        unsigned_integer_dtypes,\n        floating_dtypes,\n        complex_dtypes,\n        valid_tuple_axes,\n        broadcastable_shapes,\n        mutually_broadcastable_shapes,\n        indices,\n\n.. _django-strategies:\n\nDjango\n------\n\n.. seealso::\n\n  See the :ref:`Django API reference <hypothesis-django>` for documentation on testing Django with Hypothesis.\n\n.. autofunction:: hypothesis.extra.django.from_model\n.. autofunction:: hypothesis.extra.django.from_form\n.. autofunction:: hypothesis.extra.django.from_field\n.. autofunction:: hypothesis.extra.django.register_field_strategy\n\n.. _hypothesis-lark:\n\nhypothesis[lark]\n----------------\n\n.. note::\n\n  Strategies in this module require the ``hypothesis[lark]`` :doc:`extra </extras>`, via ``pip install hypothesis[lark]``.\n\n.. automodule:: hypothesis.extra.lark\n   :members:\n\nExample grammars, which may provide a useful starting point for your tests, can be found\n`in the Lark repository <https://github.com/lark-parser/lark/tree/master/examples>`__\nand in `this third-party collection <https://github.com/ligurio/lark-grammars>`__.\n\n.. _hypothesis-pytz:\n\nhypothesis[pytz]\n----------------\n\n.. note::\n\n  Strategies in this module require the ``hypothesis[pytz]`` :doc:`extra </extras>`, via ``pip install hypothesis[pytz]``.\n\n.. automodule:: hypothesis.extra.pytz\n   :members:\n\n.. _hypothesis-dateutil:\n\nhypothesis[dateutil]\n--------------------\n\n.. note::\n\n  Strategies in this module require the ``hypothesis[dateutil]`` :doc:`extra </extras>`, via ``pip install hypothesis[dateutil]``.\n\n.. automodule:: hypothesis.extra.dateutil\n   :members:\n"
  },
  {
    "path": "hypothesis-python/docs/stateful.rst",
    "content": "Stateful tests\n==============\n\n.. note::\n\n    See also `How not to Die Hard with Hypothesis <https://hypothesis.works/articles/how-not-to-die-hard-with-hypothesis/>`__ and `An Introduction to Rule-Based Stateful Testing <https://hypothesis.works/articles/rule-based-stateful-testing/>`__.\n\nWith |@given|, your tests are still something that you mostly write yourself, with Hypothesis providing some data. With Hypothesis's *stateful testing*, Hypothesis instead tries to generate not just data but entire tests. You specify a number of primitive actions that can be combined together, and then Hypothesis will try to find sequences of those actions that result in a failure.\n\nYou may not need stateful tests\n-------------------------------\n\nThe basic idea of stateful testing is to make Hypothesis choose actions as well as values for your test, and state machines are a great declarative way to do just that.\n\nFor simpler cases though, you might not need them at all - a standard test with |@given| might be enough, since you can use |st.data| in branches or loops.  In fact, that's how the state machine explorer works internally.  For more complex workloads though, where a higher level API comes into it's own, keep reading!\n\nRule-based state machines\n-------------------------\n\nA state machine is very similar to a normal |@given| based test in that it takes values drawn from strategies and passes them to a user defined test function, which may use assertions to check the system's behavior. The key difference is that where |@given| based tests must be independent, rules can be chained together - a single test run may involve multiple rule invocations, which may interact in various ways.\n\nRules can take normal strategies as arguments, but normal strategies, with the exception of  :func:`~hypothesis.strategies.runner` and |st.data|, cannot take into account the current state of the machine. This is where bundles come in.\n\nA rule can, in place of a normal strategy, take a :class:`~hypothesis.stateful.Bundle`. A :class:`hypothesis.stateful.Bundle` is a named collection of generated values that can be reused by other operations in the test. They are populated with the results of rules, and may be used as arguments to rules, allowing data to flow from one rule to another, and rules to work on the results of previous computations or actions.\n\nSpecifically, a rule that specifies ``target=a_bundle`` will cause its return value to be added to that bundle. A rule that specifies ``an_argument=a_bundle`` as a strategy will draw a value from that bundle.  A rule can also specify that an argument chooses a value from a bundle and removes that value by using :func:`~hypothesis.stateful.consumes` as in ``an_argument=consumes(a_bundle)``.\n\n.. note::\n    There is some overlap between what you can do with Bundles and what you can do with instance variables. Both represent state that rules can manipulate. If you do not need to draw values that depend on the machine's state, you can simply use instance variables. If you do need to draw values that depend on the machine's state, Bundles provide a fairly straightforward way to do this. If you need rules that draw values that depend on the machine's state in some more complicated way, you will have to abandon bundles. You can use :func:`~hypothesis.strategies.runner` and |.flatmap| to access the instance from a rule: the strategy ``runner().flatmap(lambda self: sampled_from(self.a_list))`` will draw from the instance variable ``a_list``. If you need something more complicated still, you can use |st.data| to draw data from the instance (or anywhere else) based on logic in the rule.\n\nThe following rule based state machine example is a simplified version of a test for Hypothesis's example database implementation. An example database maps keys to sets of values, and in this test we compare one implementation of it to a simplified in memory model of its behaviour, which just stores the same values in a Python ``dict``. The test then runs operations against both the real database and the in-memory representation of it and looks for discrepancies in their behaviour.\n\n.. code:: python\n\n  import shutil\n  import tempfile\n  from collections import defaultdict\n\n  import hypothesis.strategies as st\n  from hypothesis.database import DirectoryBasedExampleDatabase\n  from hypothesis.stateful import Bundle, RuleBasedStateMachine, rule\n\n  class DatabaseComparison(RuleBasedStateMachine):\n      def __init__(self):\n          super().__init__()\n          self.tempd = tempfile.mkdtemp()\n          self.database = DirectoryBasedExampleDatabase(self.tempd)\n          self.model = defaultdict(set)\n\n      keys = Bundle(\"keys\")\n      values = Bundle(\"values\")\n\n      @rule(target=keys, k=st.binary())\n      def add_key(self, k):\n          return k\n\n      @rule(target=values, v=st.binary())\n      def add_value(self, v):\n          return v\n\n      @rule(k=keys, v=values)\n      def save(self, k, v):\n          self.model[k].add(v)\n          self.database.save(k, v)\n\n      @rule(k=keys, v=values)\n      def delete(self, k, v):\n          self.model[k].discard(v)\n          self.database.delete(k, v)\n\n      @rule(k=keys)\n      def values_agree(self, k):\n          assert set(self.database.fetch(k)) == self.model[k]\n\n      def teardown(self):\n          shutil.rmtree(self.tempd)\n\n  TestDBComparison = DatabaseComparison.TestCase\n\nIn this we declare two bundles - one for keys, and one for values. We have two trivial rules which just populate them with data (``k`` and ``v``), and three non-trivial rules: ``save`` saves a value under a key and ``delete`` removes a value from a key, in both cases also updating the model of what *should* be in the database. ``values_agree`` then checks that the contents of the database agrees with the model for a particular key.\n\n.. note::\n\n    While this could have been simplified by not using bundles, generating keys and values directly in the ``save`` and ``delete`` rules, using bundles encourages Hypothesis to choose the same keys and values for multiple operations. The bundle operations establish a \"universe\" of keys and values that are used in the rules.\n\nWe can now integrate this into our test suite by getting a unittest TestCase from it:\n\n.. code:: python\n\n  TestTrees = DatabaseComparison.TestCase\n\n  # Or just run with pytest's unittest support\n  if __name__ == \"__main__\":\n      unittest.main()\n\nThis test currently passes, but if we comment out the line where we call ``self.model[k].discard(v)``, we would see the following output when run under pytest::\n\n    AssertionError: assert set() == {b''}\n\n    ------------ Hypothesis ------------\n\n    state = DatabaseComparison()\n    var1 = state.add_key(k=b'')\n    var2 = state.add_value(v=var1)\n    state.save(k=var1, v=var2)\n    state.delete(k=var1, v=var2)\n    state.values_agree(k=var1)\n    state.teardown()\n\nNote how it's printed out a very short program that will demonstrate the problem. The output from a rule based state machine should generally be pretty close to Python code - if you have custom ``repr`` implementations that don't return valid Python then it might not be, but most of the time you should just be able to copy and paste the code into a test to reproduce it.\n\nYou can control the detailed behaviour with a settings object on the TestCase (this is a normal hypothesis settings object using the defaults at the time the TestCase class was first referenced). For example if you wanted to run fewer examples with larger programs you could change the settings to:\n\n.. code:: python\n\n  DatabaseComparison.TestCase.settings = settings(\n      max_examples=50, stateful_step_count=100\n  )\n\nWhich doubles the number of steps each program runs and halves the number of test cases that will be run.\n\nRules\n-----\n\nAs said earlier, rules are the most common feature used in RuleBasedStateMachine. They are defined by applying the :func:`~hypothesis.stateful.rule` decorator\non a function. Note that RuleBasedStateMachine must have at least one rule defined and that a single function cannot be used to define multiple rules (this is to avoid having multiple rules doing the same things). Due to the stateful execution method, rules generally cannot take arguments from other sources such as fixtures or ``pytest.mark.parametrize`` - consider providing them via a strategy such as :func:`~hypothesis.strategies.sampled_from` instead.\n\nInitializes\n-----------\n\nInitializes are a special case of rules, which are guaranteed to be run exactly once before any normal rule is called. Note if multiple initialize rules are defined, they will all be called but in any order, and that order will vary from run to run.\n\nInitializes are typically useful to populate bundles:\n\n.. code:: python\n\n    import hypothesis.strategies as st\n    from hypothesis.stateful import Bundle, RuleBasedStateMachine, initialize, rule\n\n    name_strategy = st.text(min_size=1).filter(lambda x: \"/\" not in x)\n\n    class NumberModifier(RuleBasedStateMachine):\n        folders = Bundle(\"folders\")\n        files = Bundle(\"files\")\n\n        @initialize(target=folders)\n        def init_folders(self):\n            return \"/\"\n\n        @rule(target=folders, parent=folders, name=name_strategy)\n        def create_folder(self, parent, name):\n            return f\"{parent}/{name}\"\n\n        @rule(target=files, parent=folders, name=name_strategy)\n        def create_file(self, parent, name):\n            return f\"{parent}/{name}\"\n\nInitializes can also allow you to initialize the system under test in a way that depends on values chosen from a strategy. You could do this by putting an instance variable in the state machine that indicates whether the system under test has been initialized or not, and then using preconditions (below) to ensure that exactly one of the rules that initialize it get run before any rules that depend on it being initialized.\n\nPreconditions\n-------------\n\nWhile it's possible to use :func:`~hypothesis.assume` in RuleBasedStateMachine rules, if you use it in only a few rules you can quickly run into a situation where few or none of your rules pass their assumptions. Thus, Hypothesis provides a :func:`~hypothesis.stateful.precondition` decorator to avoid this problem. The :func:`~hypothesis.stateful.precondition` decorator is used on ``rule``-decorated functions, and must be given a function that returns True or False based on the RuleBasedStateMachine instance.\n\n.. code:: python\n\n    from hypothesis.stateful import RuleBasedStateMachine, precondition, rule\n\n    class NumberModifier(RuleBasedStateMachine):\n        num = 0\n\n        @rule()\n        def add_one(self):\n            self.num += 1\n\n        @precondition(lambda self: self.num != 0)\n        @rule()\n        def divide_with_one(self):\n            self.num = 1 / self.num\n\nBy using :func:`~hypothesis.stateful.precondition` here instead of :func:`~hypothesis.assume`, Hypothesis can filter the inapplicable rules before running them. This makes it much more likely that a useful sequence of steps will be generated.\n\nNote that currently preconditions can't access bundles; if you need to use preconditions, you should store relevant data on the instance instead.\n\nInvariants\n----------\n\nOften there are invariants that you want to ensure are met after every step in a process.  It would be possible to add these as rules that are run, but they would be run zero or multiple times between other rules. Hypothesis provides a decorator that marks a function to be run after every step.\n\n.. code:: python\n\n    from hypothesis.stateful import RuleBasedStateMachine, invariant, rule\n\n    class NumberModifier(RuleBasedStateMachine):\n        num = 0\n\n        @rule()\n        def add_two(self):\n            self.num += 2\n            if self.num > 50:\n                self.num += 1\n\n        @invariant()\n        def is_even(self):\n            assert self.num % 2 == 0\n\n    NumberTest = NumberModifier.TestCase\n\nInvariants can also have :func:`~hypothesis.stateful.precondition`\\ s applied to them, in which case they will only be run if the precondition function returns true.\n\nNote that currently invariants can't access bundles; if you need to use invariants, you should store relevant data on the instance instead.\n\nMore fine grained control\n-------------------------\n\nIf you want to bypass the TestCase infrastructure you can invoke these manually. The stateful module exposes the function ``run_state_machine_as_test``, which takes an arbitrary function returning a RuleBasedStateMachine and an optional settings parameter and does the same as the class based runTest provided.\n"
  },
  {
    "path": "hypothesis-python/docs/tutorial/adapting-strategies.rst",
    "content": "Adapting strategies\n===================\n\nThis page discusses ways to adapt strategies to your needs, either by transforming them inline with |.map|, or filtering out unwanted inputs with |.filter| and |assume|.\n\nMapping strategy inputs\n-----------------------\n\nSometimes you want to apply a simple transformation to a strategy. For instance, we know that we can generate lists of integers with ``lists(integers())``. But maybe we wanted to instead generate sorted lists. We could use an inline |.map| to achieve this:\n\n.. code-block:: pycon\n\n    >>> lists(integers()).map(sorted).example()\n    [-25527, -24245, -93, -70, -7, 0, 39, 65, 112, 6189, 19469, 32526, 1566924430]\n\nIn general, ``strategy.map(f)`` returns a new strategy which transforms all the examples generated by ``strategy`` by calling ``f`` on them.\n\nFiltering strategy inputs\n-------------------------\n\nMany strategies in Hypothesis offer some control over the kinds of values that get generated. For instance, ``integers(min_value=0)`` generates positive integers, and ``integers(100, 200)`` generates integers between ``100`` and ``200``.\n\nSometimes, you need more control than this. The inputs from a strategy may not match exactly what you need, and you just need to filter out a few bad cases.\n\nFor instance, suppose we have written a simple test involving the modulo operator ``%``:\n\n.. code-block:: python\n\n    from hypothesis import given, strategies as st\n\n    @given(st.integers(), st.integers())\n    def test_remainder_magnitude(a, b):\n        # the remainder after division is always less than\n        # the divisor\n        assert abs(a % b) < abs(b)\n\nHypothesis will quickly report a failure for this test: ``ZeroDivisionError: integer modulo by zero``. Just like division, modulo isn't defined for 0. The case of ``b == 0`` isn't interesting for the test, and we would like to get rid of it.\n\nThe best way to do this is with the |.filter| method:\n\n.. code-block:: python\n\n    from hypothesis import assume, given, strategies as st\n\n    @given(st.integers(), st.integers().filter(lambda n: n != 0))\n    def test_remainder_magnitude(a, b):\n        # b is guaranteed to be nonzero here, thanks to the filter\n        assert abs(a % b) < abs(b)\n\nThis test now passes cleanly.\n\nCalling |.filter| on a strategy creates a new strategy with that filter applied at generation-time. For instance, ``integers().filter(lambda n: n != 0)`` is a strategy which generates nonzero integers.\n\nAssuming away test cases\n------------------------\n\n|.filter| lets you filter test inputs from a single strategy. Hypothesis also provides an |assume| function for when you need to filter an entire test case, based on an arbitrary condition.\n\nThe |assume| function skips test cases where some condition evaluates to ``True``. You can use it anywhere in your test. We could have expressed our |.filter| example above using |assume| as well:\n\n.. code-block:: python\n\n    from hypothesis import assume, given, strategies as st\n\n    @given(st.integers(), st.integers())\n    def test_remainder_magnitude(a, b):\n        assume(b != 0)\n        # b will be nonzero here\n        assert abs(a % b) < abs(b)\n\n|assume| vs |.filter|\n~~~~~~~~~~~~~~~~~~~~~\n\nWhere possible, you should use |.filter|. Hypothesis can often rewrite simple filters into more efficient sampling methods than rejection sampling, and will retry filters several times instead of aborting the entire test case (as with |assume|).\n\nFor more complex relationships that can't be expressed with |.filter|, use |assume|.\n\nHere's an example of a test where we want to filter out two different types of examples:\n\n.. code-block:: python\n\n    from hypothesis import assume, given, strategies as st\n\n    @given(st.integers(), st.integers())\n    def test_floor_division_lossless_when_b_divides_a(a, b):\n        # we want to assume that:\n        # * b is nonzero, and\n        # * b divides a\n        assert (a // b) * b == a\n\nWe could start by using |assume| for both:\n\n.. code-block:: python\n\n    from hypothesis import assume, given, strategies as st\n\n    @given(st.integers(), st.integers())\n    def test_floor_division_lossless_when_b_divides_a(a, b):\n        assume(b != 0)\n        assume(a % b == 0)\n        assert (a // b) * b == a\n\nAnd then notice that the ``b != 0`` condition can be moved into the strategy definition as a |.filter| call:\n\n.. code-block:: python\n\n    from hypothesis import assume, given, strategies as st\n\n    @given(st.integers(), st.integers().filter(lambda n: n != 0))\n    def test_floor_division_lossless_when_b_divides_a(a, b):\n        assume(a % b == 0)\n        assert (a // b) * b == a\n\nHowever, the ``a % b == 0`` condition has to stay as an |assume|, because it expresses a more complicated relationship between ``a`` and ``b``.\n\n|assume| vs early-returning\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOne other way we could have avoided the divide-by-zero error inside the test function is to early-return when ``b == 0``:\n\n.. code-block:: python\n\n    from hypothesis import assume, given, strategies as st\n\n    @given(st.integers(), st.integers())\n    def test_remainder_magnitude(a, b):\n        if b == 0:\n            # bad plan - test \"passes\" without checking anything!\n            return\n        assert abs(a % b) < abs(b)\n\nWhile this would have avoided the divide-by-zero, early-returning is not the same as using |assume|. With |assume|, Hypothesis knows that a test case has been filtered out, and will not count it towards the |max_examples| limit. In contrast, early-returns are counted as a passing test, even though the assertions didn't run! In more complicted cases, this could end up testing your code less than you expect, because many test cases get discarded without Hypothesis knowing about it.\n\nIn addition, |assume| lets you skip the test case at any point in the test, even inside arbitrarily deep nestings of functions.\n"
  },
  {
    "path": "hypothesis-python/docs/tutorial/adding-notes.rst",
    "content": "Adding notes\n============\n\nWhen a test fails, Hypothesis will normally print output that looks like this:\n\n.. code::\n\n    Falsifying example: test_a_thing(x=1, y=\"foo\")\n\nSometimes you want to add some additional information to a failure, such as the output of some intermediate step in your test. The |note| function lets you do this:\n\n.. code-block:: pycon\n\n    >>> from hypothesis import given, note, strategies as st\n    >>> @given(st.lists(st.integers()), st.randoms())\n    ... def test_shuffle_is_noop(ls, r):\n    ...     ls2 = list(ls)\n    ...     r.shuffle(ls2)\n    ...     note(f\"Shuffle: {ls2!r}\")\n    ...     assert ls == ls2\n    ...\n    >>> try:\n    ...     test_shuffle_is_noop()\n    ... except AssertionError:\n    ...     print(\"ls != ls2\")\n    ...\n    Falsifying example: test_shuffle_is_noop(ls=[0, 1], r=RandomWithSeed(1))\n    Shuffle: [1, 0]\n    ls != ls2\n\n|note| is like a print statement that gets attached to the falsifying example reported by Hypothesis. It's also reported by :ref:`observability <observability>`, and shown for all examples (if |settings.verbosity| is set to |Verbosity.verbose| or higher).\n\n.. note::\n\n    |event| is a similar function which tells Hypothesis to count the number of test cases which reported each distinct value you pass, for inclusion in :ref:`test statistics <statistics>` and :ref:`observability reports <observability>`.\n"
  },
  {
    "path": "hypothesis-python/docs/tutorial/builtin-strategies.rst",
    "content": "Built-in strategies\n===================\n\nThis page shows some of the strategies that Hypothesis provides for you.\n\nStrategies provided by Hypothesis\n---------------------------------\n\nHere is a selection of strategies provided by Hypothesis that may be useful to know:\n\n|st.integers|\n    Generates integers.\n|st.floats|\n    Generates floats.\n|st.booleans|\n    Generates booleans.\n|st.text|\n    Generates unicode strings (i.e., instances of |str|). Can be constrained to ASCII with ``st.text(st.characters(codec=\"ascii\"))``.\n|st.lists|\n    Generates lists with elements from the strategy passed to it. ``st.lists(st.integers())`` generates lists of integers.\n|st.tuples|\n    Generates tuples of a fixed length. ``st.tuples(st.integers(), st.floats())`` generates tuples with two elements, where the first element is an integer and the second is a float.\n|st.one_of|\n    Generates from any of the strategies passed to it. ``st.one_of(st.integers(), st.floats())`` generates either integers or floats. You can also use ``|`` to construct |st.one_of|, like ``st.integers() | st.floats()``.\n|st.builds|\n    Generates instances of a class (or other callable) by specifying a strategy for each argument, like ``st.builds(Person, name=st.text(), age=st.integers())``.\n|st.just|\n    Generates the exact value passed to it. ``st.just(\"a\")`` generates the exact string ``\"a\"``. This is useful when something expects to be passed a strategy. For instance, ``st.lists(st.integers() | st.just(\"a\"))`` generates lists whose elements are either integers or the string ``\"a\"``.\n|st.sampled_from|\n    Generates a random value from a list. ``st.sampled_from([\"a\", 1])`` is roughly equivalent to ``st.just(\"a\") | st.just(1)``.\n|st.none|\n    Generates ``None``. Useful for parameters that can be optional, like ``st.integers() | st.none()``.\n\n.. seealso::\n\n    See the :doc:`strategies API reference </reference/strategies>` for a full list of strategies provided by Hypothesis.\n"
  },
  {
    "path": "hypothesis-python/docs/tutorial/custom-strategies.rst",
    "content": "Custom strategies\n==================\n\nThis page describes how to write a custom strategy, for when the built-in strategies don't quite fit your needs.\n\nWriting helper functions\n------------------------\n\nSometimes you might find it useful to write helper functions, to more concisely express a common pattern for your project. For example, it's much easier to write (and read!) ``response=json()`` than to have the whole implementation inline:\n\n.. code-block:: python\n\n    def json(*, finite_only=True):\n        \"\"\"Helper function to describe JSON objects, with optional inf and nan.\"\"\"\n        numbers = st.floats(allow_infinity=not finite_only, allow_nan=not finite_only)\n        return st.recursive(\n            st.none() | st.booleans() | st.integers() | numbers | st.text(),\n            extend=lambda xs: st.lists(xs) | st.dictionaries(st.text(), xs),\n        )\n\nWriting your own strategy\n-------------------------\n\nIf a strategy in Hypothesis doesn't match what you need, you can write your own strategy.\n\nFor instance, suppose we want to generate a list of floats which sum to ``1``. We might start implementing this by generating lists of integers between 0 and 1 with ``lists(floats(0, 1))``. But now we're a bit stuck, and can't go any further with the standard strategies.\n\nOne way to define a new strategy is using the |st.composite| decorator. |st.composite| lets you define a new strategy that uses arbitrary Python code. For instance, to implement the above:\n\n.. code-block:: python\n\n    from hypothesis import strategies as st\n\n    @st.composite\n    def sums_to_one(draw):\n        l = draw(st.lists(st.floats(0, 1)))\n        return [f / sum(l) for f in l]\n\n|st.composite| passes a ``draw`` function to the decorated function as its first argument. ``draw`` is used to draw a random value from another strategy. We return from ``sums_to_one`` a value of the form we wanted to generate; in this case, a list that sums to one.\n\nLet's see this new strategy in action:\n\n.. code-block:: python\n\n    import pytest\n\n    from hypothesis import given, strategies as st\n\n    @st.composite\n    def sums_to_one(draw):\n        lst = draw(st.lists(st.floats(0.001, 1), min_size=1))\n        return [f / sum(lst) for f in lst]\n\n    @given(sums_to_one())\n    def test(lst):\n        # ignore floating point errors\n        assert sum(lst) == pytest.approx(1)\n\n.. note::\n\n    Just like all other strategies, we called ``sums_to_one`` before passing it to |@given|. |st.composite| should be thought of as turning its decorated function into a function which returns a strategy when called. This is actually the same as existing strategies in Hypothesis; |st.integers| is really a function, which returns a strategy for integers when called.\n\nCombining |st.composite| with parameters\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nYou can add parameters to functions decorated with |st.composite|, including keyword-only arguments. These work as you would normally expect.\n\nFor instance, suppose we wanted to generalize our ``sums_to_one`` function to ``sums_to_n``. We can add a parameter ``n``:\n\n.. code-block:: python\n\n    import pytest\n\n    from hypothesis import assume, given, strategies as st\n\n    @st.composite\n    def sums_to_n(draw, n=1):  #  <-- changed\n        lst = draw(st.lists(st.floats(0, 1), min_size=1))\n        assume(sum(lst) > 0)\n        return [f / sum(lst) * n for f in lst]  #  <-- changed\n\n    @given(sums_to_n(10))\n    def test(lst):\n        assert sum(lst) == pytest.approx(10)\n\nAnd we could just as easily have made ``n`` a keyword-only argument instead:\n\n.. code-block:: python\n\n    import pytest\n\n    from hypothesis import assume, given, strategies as st\n\n    @st.composite\n    def sums_to_n(draw, *, n=1):  #  <-- changed\n        lst = draw(st.lists(st.floats(0, 1), min_size=1))\n        assume(sum(lst) > 0)\n        return [f / sum(lst) * n for f in lst]\n\n    @given(sums_to_n(n=10))  #  <-- changed\n    def test(lst):\n        assert sum(lst) == pytest.approx(10)\n\nDependent generation with |st.composite|\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nAnother scenario where |st.composite| is useful is when generating a value that depends on a value from another strategy. For instance, suppose we wanted to generate two integers ``n1`` and ``n2`` with ``n1 <= n2``. We can do this using |st.composite|:\n\n.. code-block:: python\n\n    @st.composite\n    def ordered_pairs(draw):\n        n1 = draw(st.integers())\n        n2 = draw(st.integers(min_value=n1))\n        return (n1, n2)\n\n    @given(ordered_pairs())\n    def test_pairs_are_ordered(pair):\n        n1, n2 = pair\n        assert n1 <= n2\n\n.. note::\n\n    We could also have written this particular strategy as ``st.tuples(st.integers(), st.integers()).map(sorted)`` (see :doc:`/tutorial/adapting-strategies`). Some prefer this inline approach, while others prefer defining well-named helper functions with |st.composite|. Our suggestion is simply that you prioritize ease of understanding when choosing which to use.\n\nMixing data generation and test code\n------------------------------------\n\nWhen using |st.composite|, you have to finish generating the entire input before running your test. But maybe you don't want to generate all of the input until you're sure some initial test assertions have passed. Or maybe you have some complicated control flow which makes it necessary to generate something in the middle of the test.\n\n|st.data| lets you to do this. It's similar to |st.composite|, except it lets you mix test code and generation code.\n\n.. note::\n\n    The downside of this power is that |st.data| is incompatible |@example|, and that Hypothesis cannot print a nice representation of values generated from |st.data| when reporting failing examples, because the draws are spread out. Where possible, prefer |st.composite| to |st.data|.\n\nFor instance, here's how we would write our earlier |st.composite| example using |st.data|:\n\n.. code-block:: python\n\n    import pytest\n\n    from hypothesis import given, strategies as st\n\n    @given(st.data())\n    def test(data):\n        lst = data.draw(st.lists(st.floats(0.001, 1), min_size=1))\n        lst = [f / sum(lst) for f in lst]\n        # ignore floating point errors\n        assert sum(lst) == pytest.approx(1)\n"
  },
  {
    "path": "hypothesis-python/docs/tutorial/flaky.rst",
    "content": "Flaky failures\n==============\n\nHave you ever had a test fail, and then you re-run it, only for the test to magically pass? That is a *flaky test*. A flaky test is one which might behave differently when called again. You can think of it as a test which is not deterministic.\n\nAny test can be flaky, but because Hypothesis runs your test many times, Hypothesis tests are particularly likely to uncover flaky behavior.\n\nNote that Hypothesis does not require tests to be fully deterministic. Only the sequence of calls to Hypothesis APIs like ``draw`` from |st.composite| and the outcome of the test (pass or fail) need to be deterministic. This means you can use randomness, threads, or nondeterminism in your test, as long as it doesn't impact anything Hypothesis can see.\n\nWhy is flakiness bad?\n---------------------\n\nHypothesis raises an exception when it detects flakiness. This might seem extreme, relative to a simple warning. But there are good reasons to consider flakiness a fatal error.\n\n.. TODO_DOCS: link to not-yet-written database page\n\n* Hypothesis relies on deterministic behavior for the database to work.\n* Flakiness makes debugging failures substantially harder if the failing input reported by Hypothesis only flakily reproduces.\n* Flakiness makes effectively exploration of the test's behavior space by Hypothesis difficult or impossible.\n\nCommon sources of flakiness\n---------------------------\n\nHere is a quick and non-exhaustive enumeration of some reasons you might encounter flakiness:\n\n* Decisions based on global state.\n* Explicit dependencies between inputs.\n* Test depends on filesystem or database state which isn't reset between inputs.\n* Un-managed sources of randomness. This includes standard PRNGs (see also |register_random|), but also thread scheduling, network timing, etc.\n\n.. note::\n\n    If your tests depend on global state, consider replacing that state with |st.shared|. This is a common way to refactor your test to bring conceptually-global state under the control and visibility of Hypothesis.\n\nTypes of flakiness\n------------------\n\nWhen Hypothesis detects that a test is flaky, it will raise one of two |Flaky| exceptions.\n\nFlaky failure\n~~~~~~~~~~~~~\n\nThe most common form of flakiness is that Hypothesis finds a failure, but then replaying that input does not reproduce the failure. For example, here is a contrived test which only fails the first time it is called:\n\n.. code-block:: python\n\n    called = False\n\n    @given(st.integers())\n    def test_fails_flakily(n):\n        global called\n        if not called:\n            called = True\n            assert False\n\nThe first time Hypothesis generates an input, this test will fail. But when Hypothesis tries replaying that failure—by generating the same input—the test will succeed. This test is flaky.\n\nAs a result, running ``test_fails_flakily()`` will raise |FlakyFailure|. |FlakyFailure| is an ``ExceptionGroup``, which contains the origin failure as a sub-exception:\n\n.. code-block:: none\n\n  + Exception Group Traceback (most recent call last):\n  | hypothesis.errors.FlakyFailure: Hypothesis test_fails_flakily(n=0) produces unreliable results: Falsified on the first call but did not on a subsequent one (1 sub-exception)\n  | Falsifying example: test_fails_flakily(\n  |     n=0,\n  | )\n  | Failed to reproduce exception. Expected:\n  | Traceback (most recent call last):\n  |   File \"/Users/tybug/Desktop/sandbox2.py\", line 13, in test_fails_flakily\n  |     assert False\n  |            ^^^^^\n  | AssertionError\n  +-+---------------- 1 ----------------\n    | ...\n    | Traceback (most recent call last):\n    |   File \"/Users/tybug/Desktop/sandbox2.py\", line 13, in test_fails_flakily\n    |     assert False\n    |            ^^^^^\n    | AssertionError\n    +------------------------------------\n\nThe solution to seeing |FlakyFailure| is to refactor the test to not depend on external state. In this case, the external state is the variable ``called``.\n\nFlaky strategy definition\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nEach strategy must 'do the same thing' (again, as seen by Hypothesis) if we replay a previously-seen input.  Failing to do so is a more subtle but equally serious form of flakiness, which leaves us unable to shrink to a minimal failing input, or even reliably report the failure in future runs.\n\nOne easy way for this to occur is if a strategy depends on external state. For example, this strategy filters out previously-generated integers, including those seen in any previous test case:\n\n.. code-block:: python\n\n    seen = set()\n\n    @st.composite\n    def unique_ints(draw):\n        while (n := draw(st.integers())) in seen:\n            pass\n        seen.add(n)\n        return n\n\n    @given(unique_ints(), unique_ints())\n    def test_ints(x, y): ...\n\nBy using ``seen``, this test is relying on outside state! In the first test case where |st.integers| generates ``0``, ``unique_ints`` draws only one integer. But if in the next test case |st.integers| generates ``0``, ``unique_ints`` has to draw two integers because ``0`` is already in ``seen``. This means data generation is not deterministic.\n\nAs a result, running ``test_ints()`` will raise |FlakyStrategyDefinition|. The solution is to refactor the strategy to not depend on external state. One way to do this is using |st.shared|:\n\n.. code-block:: python\n\n    @st.composite\n    def unique_ints(draw):\n        seen_this_test = draw(st.shared(st.builds(set), key=\"seen_ints\"))\n        while (n := draw(st.integers())) in seen_this_test:\n            pass\n        seen_this_test.add(n)\n        return n\n"
  },
  {
    "path": "hypothesis-python/docs/tutorial/index.rst",
    "content": "Tutorial\n========\n\nThe Hypothesis tutorial introduces the main features of Hypothesis. We suggest reading through in order until completing :doc:`/tutorial/custom-strategies`, at which point you can choose to read what seems interesting to you.\n\nIf you're in a hurry, the :doc:`quickstart </quickstart>` is a much faster bare-bones version.\n\n.. toctree::\n   :maxdepth: 1\n\n   introduction\n   builtin-strategies\n   adapting-strategies\n   custom-strategies\n   settings\n   replaying-failures\n   adding-notes\n   flaky\n"
  },
  {
    "path": "hypothesis-python/docs/tutorial/introduction.rst",
    "content": "Introduction to Hypothesis\n==========================\n\nThis page introduces two fundamental parts of Hypothesis (|@given|, and strategies) and shows how to test a selection sort implementation using Hypothesis.\n\nInstall Hypothesis\n------------------\n\nFirst, let's install Hypothesis:\n\n.. code-block:: shell\n\n    pip install hypothesis\n\nDefining a simple test\n----------------------\n\nHypothesis tests are defined using two things; |@given|, and a *strategy*, which is passed to |@given|. Here's a simple example:\n\n.. code-block:: python\n\n    from hypothesis import given, strategies as st\n\n    @given(st.integers())\n    def test_is_integer(n):\n        assert isinstance(n, int)\n\nAdding the |@given| decorator turns this function into a Hypothesis test. Passing |st.integers| to |@given| says that Hypothesis should generate random integers for the argument ``n`` when testing.\n\nWe can run this test by calling it:\n\n.. code-block:: python\n\n    from hypothesis import given, strategies as st\n\n    @given(st.integers())\n    def test_is_integer(n):\n        print(f\"called with {n}\")\n        assert isinstance(n, int)\n\n    test_is_integer()\n\nNote that we don't pass anything for ``n``; Hypothesis handles generating that value for us. The resulting output looks like this:\n\n.. code-block:: none\n\n    called with 0\n    called with -18588\n    called with -672780074\n    called with 32616\n    ...\n\n\nTesting a sorting algorithm\n---------------------------\n\nSuppose we have implemented a simple selection sort:\n\n.. code-block:: python\n\n  # contents of example.py\n  from hypothesis import given, strategies as st\n\n  def selection_sort(lst):\n      result = []\n      while lst:\n          smallest = min(lst)\n          result.append(smallest)\n          lst.remove(smallest)\n      return result\n\nand want to make sure it's correct. We can write the following test by combining the |st.integers| and |st.lists| strategies:\n\n.. code-block:: python\n\n  ...\n\n  @given(st.lists(st.integers()))\n  def test_sort_correct(lst):\n      print(f\"called with {lst}\")\n      assert selection_sort(lst.copy()) == sorted(lst)\n\n  test_sort_correct()\n\nWhen running ``test_sort_correct``, Hypothesis uses the ``lists(integers())`` strategy to generate random lists of integers. Feel free to run ``python example.py`` to get an idea of the kinds of lists Hypothesis generates (and to convince yourself that this test passes).\n\nAdding floats to our test\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis test is a good start. But ``selection_sort`` should be able to sort lists with floats, too. If we wanted to generate lists of either integers or floats, we can change our strategy:\n\n.. code-block:: python\n\n  # changes to example.py\n  @given(st.lists(st.integers() | st.floats()))\n  def test_sort_correct(lst):\n      pass\n\nThe pipe operator ``|`` takes two strategies, and returns a new strategy which generates values from either of its strategies. So the strategy ``integers() | floats()`` can generate either an integer, or a float.\n\n.. note::\n\n  ``strategy1 | strategy2`` is equivalent to :func:`st.one_of(strategy1, strategy2) <hypothesis.strategies.one_of>`.\n\nPreventing |st.floats| from generating ``nan``\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nEven though ``test_sort_correct`` passed when we used lists of integers, it actually fails now that we've added floats! If you run ``python example.py``, you'll likely (but not always; this is random testing, after all) find that Hypothesis reports a counterexample to ``test_sort_correct``. For me, that counterexample is ``[1.0, nan, 0]``. It might be different for you.\n\nThe issue is that sorting in the presence of ``nan`` is not well defined. As a result, we may decide that we don't want to generate them while testing. We can pass ``floats(allow_nan=False)`` to tell Hypothesis not to generate ``nan``:\n\n.. code-block:: python\n\n  # changes to example.py\n  @given(st.lists(st.integers() | st.floats(allow_nan=False)))\n  def test_sort_correct(lst):\n      pass\n\nAnd now this test passes without issues.\n\n.. note::\n\n  You can use the |.example()| method to get an idea of the kinds of things a strategy will generate:\n\n  .. code-block:: pycon\n\n    >>> st.lists(st.integers() | st.floats(allow_nan=False)).example()\n    [-5.969063e-08, 15283673678, 18717, -inf]\n\n  Note that |.example()| is intended for interactive use only (i.e., in a :term:`REPL <python:REPL>`). It is not intended to be used inside tests.\n\n\nTests with multiple arguments\n-----------------------------\n\nIf we wanted to pass multiple arguments to a test, we can do this by passing multiple strategies to |@given|:\n\n.. code-block:: python\n\n    from hypothesis import given, strategies as st\n\n    @given(st.integers(), st.lists(st.floats()))\n    def test_multiple_arguments(n, lst):\n        assert isinstance(n, int)\n        assert isinstance(lst, list)\n        for f in lst:\n            assert isinstance(f, float)\n\nKeyword arguments\n~~~~~~~~~~~~~~~~~\n\nWe can also pass strategies using keyword arguments:\n\n.. code-block:: python\n\n    @given(lst=st.lists(st.floats()), n=st.integers())  #  <-- changed\n    def test_multiple_arguments(n, lst):\n        pass\n\nNote that even though we changed the order the parameters to |@given| appear, we also explicitly told it which parameters to pass to by using keyword arguments, so the meaning of the test hasn't changed.\n\nIn general, you can think of positional and keyword arguments to |@given| as being forwarded to the test arguments.\n\n.. note::\n\n  One exception is that |@given| does not support mixing positional and keyword arguments. See the |@given| documentation for more about how it handles arguments.\n\n\nRunning Hypothesis tests\n------------------------\n\nThere are a few ways to run a Hypothesis test.\n\n* Explicitly call it, like ``test_is_integer()``, as we've seen. Hypothesis tests are just normal functions, except |@given| handles generating and passing values for the function arguments.\n* Let a test runner such as :pypi:`pytest` pick up on it (as long as the function name starts with ``test_``).\n\nConcretely, when running a Hypothesis test, Hypothesis will:\n\n* generate 100 random inputs,\n* run the body of the function for each input, and\n* report any exceptions that get raised.\n\n.. note::\n\n  The number of examples can be controlled with the |max_examples| setting. The default is 100.\n\n\nWhen to use Hypothesis and property-based testing\n-------------------------------------------------\n\nProperty-based testing is a powerful *addition* to unit testing. It is not always a replacement.\n\nIf you're having trouble coming up with a property in your code to test, we recommend trying the following:\n\n* Look for round-trip properties: encode/decode, serialize/deserialize, etc. These property-based tests tend to be both powerful and easy to write.\n* Look for ``@pytest.mark.parametrize`` in your existing tests. This is sometimes a good hint you can replace the parametrization with a strategy. For instance, ``@pytest.mark.parametrize(\"n\", range(0, 100))`` could be replaced by ``@given(st.integers(0, 100 - 1))``.\n* Simply call your code with random inputs (of the correct shape) from Hypothesis! You might be surprised how often this finds crashes. This can be especially valuable for projects with a single entrypoint interface to a lot of underlying code.\n\nOther examples of properties include:\n\n* An optimized implementation is equivalent to a slower, but clearly correct, implementation.\n* A sequence of transactions in a financial system always \"balances\"; money never gets lost.\n* The derivative of a polynomial of order ``n`` has order ``n - 1``.\n* A type-checker, linter, formatter, or compiler does not crash when called on syntactically valid code.\n* `And more <https://fsharpforfunandprofit.com/posts/property-based-testing-2/>`_.\n"
  },
  {
    "path": "hypothesis-python/docs/tutorial/replaying-failures.rst",
    "content": "Replaying failed tests\n======================\n\nReplaying failures found by your Hypothesis tests is almost as important as finding failures in the first place. Hypothesis therefore contains several ways to replay failures: they are automatically saved to (and replayed from) a local |ExampleDatabase|, and can be manually replayed via |@example| or |@reproduce_failure|.\n\nThe Hypothesis database\n-----------------------\n\nWhen a test fails, Hypothesis automatically saves the failure so it can be replayed later. For instance, the first time you run the following code, it will take up to a few seconds to fail:\n\n.. code-block:: python\n\n    import time\n\n    from hypothesis import strategies as st\n\n    @given(st.integers())\n    def f(n):\n        assert n < 50\n        time.sleep(0.1)\n\n    f()\n\nBut the next time you run this code, it will fail instantly. When Hypothesis saw the failure the first time, it automatically saved that failing input. On future runs, Hypothesis retries any failing inputs (in |Phase.explain|) before generating new inputs (in |Phase.generate|)\n\nHypothesis saves failures to the |settings.database| setting. By default, this is a |DirectoryBasedExampleDatabase| in the local ``.hypothesis`` directory.\n\nDisabling the database\n~~~~~~~~~~~~~~~~~~~~~~\n\nYou can disable the database by passing ``database=None`` to |@settings|:\n\n.. code-block:: python\n\n    @settings(database=None)\n    def f(n): ...\n\nUsing |@example| to run a specific input\n----------------------------------------\n\nIf you want Hypothesis to always run a specific input, you can use |@example|. |@example| adds an explicit input which Hypothesis will run every time, in addition to the randomly generated examples. You can think of |@example| as combining unit-testing with property-based testing.\n\nFor instance, suppose we write a test using |st.integers|, but want to make sure we try a few special prime numbers every time we run the test. We can add these inputs with |@example|:\n\n.. code-block:: python\n\n    # two mersenne primes\n    @example(2**17 - 1)\n    @example(2**19 - 1)\n    @given(st.integers())\n    def test_integers(n):\n        pass\n\n    test_integers()\n\nHypothesis runs all explicit examples first, in the |Phase.explicit| phase, before generating additional random examples in the |Phase.generate| phase.\n\nInputs from |@example| do not shrink\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nNote that unlike examples generated by Hypothesis, examples provided using |@example| do not shrink. We can see this by adding a failing assertion:\n\n.. code-block:: python\n\n    @example(2**17 - 1)\n    @given(st.integers())\n    def test_something_with_integers(n):\n        assert n < 100\n\nHypothesis will print ``Falsifying explicit example: test_something_with_integers(n=131071)``, instead of shrinking to ``n=100``.\n\nPrefer |@example| over the database for correctness\n---------------------------------------------------\n\n.. TODO_DOCS: link to /explanation/database-keys\n\nWhile the database is useful for quick local iteration, Hypothesis may invalidate it when upgrading (because e.g. the internal format may have changed). Changes to the source code of a test function may also change its database key, invalidating its stored entries. We therefore recommend against relying on the database for the correctness of your tests. If you want to ensure an input is run every time, use |@example|.\n\nReplaying examples with |@reproduce_failure|\n--------------------------------------------\n\nIf |settings.print_blob| is set to ``True`` (the default in the ``ci`` settings profile), and a test fails, Hypothesis will print an |@reproduce_failure| decorator containing an opaque blob as part of the error message:\n\n.. code-block:: pycon\n\n    >>> from hypothesis import settings, given\n    >>> import hypothesis.strategies as st\n    >>> @given(st.floats())\n    ... @settings(print_blob=True)\n    ... def test(f):\n    ...     assert f == f\n    ...\n    >>> test()\n\n    ...\n    Falsifying example: test(\n        f=nan,\n    )\n    You can reproduce this example by temporarily adding @reproduce_failure('6.131.23', b'ACh/+AAAAAAAAA==') as a decorator on your test case\n\n\nYou can add this decorator to your test to reproduce the failure. This can be useful for locally replaying failures found by CI. Note that the binary blob is not stable across Hypothesis versions, so you should not leave this decorator on your tests permanently. Use |@example| with an explicit input instead.\n\nSharing failures with the database\n----------------------------------\n\nIf you work with multiple developers, or want to share failures across environments (such as locally replaying a failure found by CI), another option is to share the Hypothesis database.\n\nFor instance, by setting |settings.database| to an instance of a networked database like |RedisExampleDatabase|, any developer connecting to that networked database will automatically replay any failures found by other developers.\n\nSimilarly, setting |settings.database| to |GitHubArtifactDatabase| will automatically replay any failures found by the connected CI artifact.\n"
  },
  {
    "path": "hypothesis-python/docs/tutorial/settings.rst",
    "content": "Configuring test settings\n=========================\n\nThis page discusses how to configure the behavior of a single Hypothesis test, or of an entire test suite.\n\nConfiguring a single test\n-------------------------\n\nHypothesis lets you configure the default behavior of a test using the |@settings| decorator. You can use settings to configure how many examples Hypothesis generates, how Hypothesis replays failing examples, and the verbosity level of the test, among others.\n\nUsing |@settings| on a single test looks like this:\n\n.. code-block:: python\n\n    from hypothesis import given, settings, strategies as st\n\n    @given(st.integers())\n    @settings(max_examples=200)\n    def runs_200_times_instead_of_100(n):\n        pass\n\nYou can put |@settings| either before or after |@given|. Both are equivalent.\n\nChanging the number of examples\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf you have a test which is very expensive or very cheap to run, you can change the number of examples (inputs) Hypothesis generates with the |max_examples| setting:\n\n.. code-block:: python\n\n    from hypothesis import given, settings, strategies as st\n\n    @given(st.integers())\n    @settings(max_examples=5)\n    def test(n):\n        print(\"prints five times\")\n\nThe default is 100 examples.\n\n.. note::\n\n    See :doc:`../explanation/example-count` for details on how |max_examples| interacts with other parts of Hypothesis.\n\n\nOther settings options\n~~~~~~~~~~~~~~~~~~~~~~\n\nHere are a few of the more commonly used setting values:\n\n* |settings.phases| controls which phases of Hypothesis run, like replaying from the database or generating new inputs.\n* |settings.database| controls how and if Hypothesis replays failing examples.\n* |settings.verbosity| can print debug information.\n* |settings.derandomize| makes Hypothesis deterministic. (`Two kinds of testing <https://blog.nelhage.com/post/two-kinds-of-testing/>`__ discusses when and why you might want that).\n\n.. note::\n\n    See the |settings| reference for a full list of possible settings.\n\n\nChanging settings across your test suite\n----------------------------------------\n\nIn addition to configuring individual test functions with |@settings|, you can configure test behavior across your test suite using a settings profile. This might be useful for creating a development settings profile which runs fewer examples, or a settings profile in CI which connects to a separate database.\n\nTo create a settings profile, use |settings.register_profile|:\n\n.. code-block:: python\n\n    from hypothesis import HealthCheck, settings\n\n    settings.register_profile(\"fast\", max_examples=10)\n\nYou can place this code in any file which gets loaded before your tests get run. This includes an ``__init__.py`` file in the test directory or any of the test files themselves. If using pytest, the standard location to place this code is in a ``confest.py`` file (though an ``__init__.py`` or test file will also work).\n\nNote that registering a new profile will not affect tests until it is loaded with |settings.load_profile|:\n\n.. code-block:: python\n\n    from hypothesis import HealthCheck, settings\n\n    settings.register_profile(\"fast\", max_examples=10)\n\n    # any tests executed before loading this profile will still use the\n    # default active profile of 100 examples.\n\n    settings.load_profile(\"fast\")\n\n    # any tests executed after this point will use the active fast\n    # profile of 10 examples.\n\nThere is no limit to the number of settings profiles you can create. Hypothesis creates a profile called ``\"default\"``, which is active by default. You can also explicitly make it active at any time using ``settings.load_profile(\"default\")``, if for instance you wanted to revert a custom profile you had previously loaded.\n\nLoading profiles from environment variables\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nUsing an environment variable to load a settings profile is a useful trick for choosing a settings profile depending on the environment:\n\n.. code-block:: pycon\n\n    >>> import os\n    >>> from hypothesis import settings, Verbosity\n    >>> settings.register_profile(\"long\", max_examples=1000)\n    >>> settings.register_profile(\"fast\", max_examples=10)\n    >>> settings.register_profile(\"debug\", max_examples=10, verbosity=Verbosity.verbose)\n    >>> settings.load_profile(os.getenv(\"HYPOTHESIS_PROFILE\", \"default\"))\n\nIf using pytest, you can also easily select the active profile with ``--hypothesis-profile``:\n\n.. code:: bash\n\n    $ pytest --hypothesis-profile fast\n\nSee the :ref:`Hypothesis pytest plugin <pytest-plugin>`.\n"
  },
  {
    "path": "hypothesis-python/docs/usage.rst",
    "content": "Projects using Hypothesis\n=========================\n\nHypothesis is downloaded `over 4 million times each week <https://pypistats.org/packages/hypothesis>`__,\nand was used by `more than 5% of Python users surveyed by the PSF in 2023\n<https://lp.jetbrains.com/python-developers-survey-2023/>`__!\n\nThe following notable open-source projects use Hypothesis to test their code: `pytorch <https://github.com/pytorch/pytorch>`_, `jax <https://github.com/jax-ml/jax>`_, `PyPy <https://github.com/pypy/pypy>`_, `numpy <https://github.com/numpy/numpy>`_, `pandas <https://github.com/pandas-dev/pandas>`_, `attrs <https://github.com/python-attrs/attrs>`_, `chardet <https://github.com/chardet/chardet>`_, `bidict <https://github.com/jab/bidict>`_, `xarray <https://github.com/pydata/xarray>`_, `array-api-tests <https://github.com/data-apis/array-api-tests>`_, `pandera <https://github.com/unionai-oss/pandera>`_, `ivy <https://github.com/ivy-llc/ivy>`_, `zenml <https://github.com/zenml-io/zenml>`_, `mercurial <https://www.mercurial-scm.org/>`_, `qutebrowser <https://github.com/qutebrowser/qutebrowser>`_, `dry-python/returns <https://github.com/dry-python/returns>`_, `argon2_cffi <https://github.com/hynek/argon2-cffi>`_, `axelrod <https://github.com/Axelrod-Python/Axelrod>`_, `hyper-h2 <https://github.com/python-hyper/h2>`_, `MDAnalysis <https://github.com/MDAnalysis/mdanalysis>`_, `napari <https://github.com/napari/napari>`_, `natsort <https://github.com/SethMMorton/natsort>`_, `vdirsyncer <https://github.com/pimutils/vdirsyncer>`_, and `pyrsistent <https://github.com/tobgu/pyrsistent>`_. You can find `thousands more projects tested by Hypothesis on GitHub <https://github.com/HypothesisWorks/hypothesis/network/dependents>`__.\n\nThere are also dozens of :doc:`first-party <extras>` and :doc:`third-party extensions <extensions>` integrating Hypothesis with a wide variety of libraries and data formats.\n\n.. ^ citations that I put effort into looking up but decided not to use. Maybe we'll use them in the future?\n.. https://github.com/pytorch/pytorch/blob/59ad8f1ac6bce11617a5f856df9e88b3bf9266af/pyproject.toml#L41\n.. https://github.com/jax-ml/jax/blob/48335107f82117ac34c76cac3e22546d2da78eaf/build/test-requirements.txt#L5\n.. https://github.com/pypy/pypy/blob/338295bd0567cda9a3c603f428b14229da08e750/extra_tests/requirements.txt#L2\n.. https://github.com/numpy/numpy/blob/c9b2919556789675dca0e202dd5a4b46d7d23ff2/requirements/test_requirements.txt#L5\n.. https://github.com/pandas-dev/pandas/blob/1863adb252863b718ba29912922bf050ce0eaa3d/pyproject.toml#L60\n.. https://github.com/python-attrs/attrs/blob/5084de361bf9e722dda6876e6e2b8ce8c63b7272/pyproject.toml#L47\n.. https://github.com/chardet/chardet/blob/8e8dfcd93c572c2cbe37585e01662a90b16fbab6/pyproject.toml#L59\n.. https://github.com/jab/bidict/blob/0116e5b772bd2e390267c511187e60931b733153/pyproject.toml#L38\n.. https://github.com/pydata/xarray/blob/3572f4e70f2b12ef9935c1f8c3c1b74045d2a092/pyproject.toml#L73\n.. https://foss.heptapod.net/mercurial/mercurial-devel/-/blob/b8ca286fda2eb275ffdfd7417fb539a03748d22c/tests/hypothesishelpers.py\n.. https://github.com/qutebrowser/qutebrowser/blob/642c5fe2fe46082de53219c19e02fef209753aa0/misc/requirements/requirements-tests.txt#L19\n\nResearch papers about Hypothesis\n--------------------------------\n\nLooking to read more about Hypothesis and property-based testing? Hypothesis has been the subject of a number of research papers:\n\n1. `Hypothesis: A new approach to property-based testing <https://doi.org/10.21105/joss.01891>`_ (2019)*\n2. `Test-Case Reduction via Test-Case Generation: Insights from the Hypothesis Reducer <https://doi.org/10.4230/LIPIcs.ECOOP.2020.13>`_ (2020)*\n3. `Deriving semantics-aware fuzzers from web API schemas <https://dl.acm.org/doi/10.1145/3510454.3528637>`_ (2022)*\n4. `Tyche: Making Sense of PBT Effectiveness <https://dl.acm.org/doi/10.1145/3654777.3676407>`_ (2024)*\n5. `An Empirical Evaluation of Property-Based Testing in Python <https://dl.acm.org/doi/10.1145/3764068>`_ (2025)\n6. `Agentic Property-Based Testing: Finding Bugs Across the Python Ecosystem <https://doi.org/10.48550/arXiv.2510.09907>`_ (2025)*\n\n\\* *Author list includes one or more Hypothesis maintainers*\n"
  },
  {
    "path": "hypothesis-python/examples/README.md",
    "content": "# Examples of Hypothesis usage\n\nThis is a directory for examples of using Hypothesis that show case its features or demonstrate a useful way of testing something.\n\nRight now it's a bit small and fairly algorithmically focused. Pull requests to add more examples would be *greatly* appreciated, especially ones using e.g. the Django integration or testing something \"Businessy\".\n"
  },
  {
    "path": "hypothesis-python/examples/example_hypothesis_entrypoint/example_hypothesis_entrypoint.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"This example demonstrates a setuptools entry point.\n\nSee https://hypothesis.readthedocs.io/en/latest/strategies.html#registering-strategies-via-setuptools-entry-points\nfor details and documentation.\n\"\"\"\n\n\nclass MyCustomType:\n    def __init__(self, x: int):\n        assert x >= 0, f\"got {x}, but only positive numbers are allowed\"\n        self.x = x\n\n\ndef _hypothesis_setup_hook():\n    import hypothesis.strategies as st\n\n    st.register_type_strategy(MyCustomType, st.integers(min_value=0).map(MyCustomType))\n"
  },
  {
    "path": "hypothesis-python/examples/example_hypothesis_entrypoint/setup.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"Minimal setup.py to register an entrypoint.\"\"\"\n\nimport setuptools\n\nsetuptools.setup(\n    name=\"example_hypothesis_entrypoint\",\n    author=\"Example Author\",\n    email=\"author@example.com\",\n    license=\"MPL v2\",\n    description=\"Minimal setup.py to register an entrypoint.\",\n    packages=setuptools.find_packages(),\n    install_requires=[\"hypothesis\"],\n    python_requires=\">=3.7\",\n    entry_points={\n        \"hypothesis\": [\"_ = example_hypothesis_entrypoint:_hypothesis_setup_hook\"]\n    },\n)\n"
  },
  {
    "path": "hypothesis-python/examples/example_hypothesis_entrypoint/test_entrypoint.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom example_hypothesis_entrypoint import MyCustomType\n\nfrom hypothesis import given, strategies as st\n\n\n@given(st.from_type(MyCustomType))\ndef test_registered_from_entrypoint(x):\n    # This demonstrates that we've registered the type, not just\n    # worked out how to construct an instance.\n    assert isinstance(x, MyCustomType)\n    assert x.x >= 0\n"
  },
  {
    "path": "hypothesis-python/examples/test_basic.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, strategies as st\n\n\n# Our tested class\nclass Product:\n    def __init__(self, price: float) -> None:\n        self.price: float = price\n\n    def get_discount_price(self, discount_percentage: float):\n        return self.price * (discount_percentage / 100)\n\n\n# The @given decorator generates examples for us!\n@given(\n    price=st.floats(min_value=0, allow_nan=False, allow_infinity=False),\n    discount_percentage=st.floats(\n        min_value=0, max_value=100, allow_nan=False, allow_infinity=False\n    ),\n)\ndef test_a_discounted_price_is_not_higher_than_the_original_price(\n    price, discount_percentage\n):\n    product = Product(price)\n    assert product.get_discount_price(discount_percentage) <= product.price\n"
  },
  {
    "path": "hypothesis-python/examples/test_binary_search.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"This file demonstrates testing a binary search.\n\nIt's a useful example because the result of the binary search is so clearly\ndetermined by the invariants it must satisfy, so we can simply test for those\ninvariants.\n\nIt also demonstrates the useful testing technique of testing how the answer\nshould change (or not) in response to movements in the underlying data.\n\"\"\"\n\nimport itertools\n\nfrom hypothesis import given, strategies as st\n\n\ndef binary_search(ls, v):\n    \"\"\"Take a list ls and a value v such that ls is sorted and v is comparable\n    with the elements of ls.\n\n    Return an index i such that 0 <= i <= len(v) with the properties:\n\n    1. ls.insert(i, v) is sorted\n    2. ls.insert(j, v) is not sorted for j < i\n    \"\"\"\n    # Without this check we will get an index error on the next line when the\n    # list is empty.\n    if not ls:\n        return 0\n\n    # Without this check we will miss the case where the insertion point should\n    # be zero: The invariant we maintain in the next section is that lo is\n    # always strictly lower than the insertion point.\n    if v <= ls[0]:\n        return 0\n\n    # Invariant: There is no insertion point i with i <= lo\n    lo = 0\n\n    # Invariant: There is an insertion point i with i <= hi\n    hi = len(ls)\n    while lo + 1 < hi:\n        mid = (lo + hi) // 2\n        if v > ls[mid]:\n            # Inserting v anywhere below mid would result in an unsorted list\n            # because it's > the value at mid. Therefore mid is a valid new lo\n            lo = mid\n        # Uncommenting the following lines will cause this to return a valid\n        # insertion point which is not always minimal.\n        # elif v == ls[mid]:\n        #   return mid\n        else:\n            # Either v == ls[mid] in which case mid is a valid insertion point\n            # or v < ls[mid], in which case all valid insertion points must be\n            # < hi. Either way, mid is a valid new hi.\n            hi = mid\n    assert lo + 1 == hi\n    # We now know that there is a valid insertion point <= hi and there is no\n    # valid insertion point < hi because hi - 1 is lo. Therefore hi is the\n    # answer we were seeking\n    return hi\n\n\ndef is_sorted(ls):\n    \"\"\"Is this list sorted?\"\"\"\n    return all(x <= y for x, y in itertools.pairwise(ls))\n\n\nValues = st.integers()\n\n# We generate arbitrary lists and turn this into generating sorting lists\n# by just sorting them.\nSortedLists = st.lists(Values).map(sorted)\n\n# We could also do it this way, but that would be a bad idea:\n# SortedLists = st.lists(Values).filter(is_sorted)\n# The problem is that Hypothesis will only generate long sorted lists with very\n# low probability, so we are much better off post-processing values into the\n# form we want than filtering them out.\n\n\n@given(ls=SortedLists, v=Values)\ndef test_insert_is_sorted(ls, v):\n    \"\"\"We test the first invariant: binary_search should return an index such\n    that inserting the value provided at that index would result in a sorted\n    set.\"\"\"\n    ls.insert(binary_search(ls, v), v)\n    assert is_sorted(ls)\n\n\n@given(ls=SortedLists, v=Values)\ndef test_is_minimal(ls, v):\n    \"\"\"We test the second invariant: binary_search should return an index such\n    that no smaller index is a valid insertion point for v.\"\"\"\n    for i in range(binary_search(ls, v)):\n        ls2 = list(ls)\n        ls2.insert(i, v)\n        assert not is_sorted(ls2)\n\n\n@given(ls=SortedLists, v=Values)\ndef test_inserts_into_same_place_twice(ls, v):\n    \"\"\"In this we test a *consequence* of the second invariant: When we insert\n    a value into a list twice, the insertion point should be the same both\n    times. This is because we know that v is > the previous element and == the\n    next element.\n\n    In theory if the former passes, this should always pass. In practice,\n    failures are detected by this test with much higher probability because it\n    deliberately puts the data into a shape that is likely to trigger a\n    failure.\n\n    This is an instance of a good general category of test: Testing how the\n    function moves in responses to changes in the underlying data.\n    \"\"\"\n    i = binary_search(ls, v)\n    ls.insert(i, v)\n    assert binary_search(ls, v) == i\n"
  },
  {
    "path": "hypothesis-python/examples/test_rle.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"This example demonstrates testing a run length encoding scheme. That is, we\ntake a sequence and represent it by a shorter sequence where each 'run' of\nconsecutive equal elements is represented as a single element plus a count. So\ne.g.\n\n[1, 1, 1, 1, 2, 1] is represented as [[1, 4], [2, 1], [1, 1]]\n\nThis demonstrates the useful decode(encode(x)) == x invariant that is often\na fruitful source of testing with Hypothesis.\n\nIt also has an example of testing invariants in response to changes in the\nunderlying data.\n\"\"\"\n\nfrom hypothesis import assume, given, strategies as st\n\n\ndef run_length_encode(seq):\n    \"\"\"Encode a sequence as a new run-length encoded sequence.\"\"\"\n    if not seq:\n        return []\n    # By starting off the count at zero we simplify the iteration logic\n    # slightly.\n    result = [[seq[0], 0]]\n    for s in seq:\n        if (\n            # If you uncomment this line this branch will be skipped and we'll\n            # always append a new run of length 1. Note which tests fail.\n            # False and\n            s\n            == result[-1][0]\n            # Try uncommenting this line and see what problems occur:\n            # and result[-1][-1] < 2\n        ):\n            result[-1][1] += 1\n        else:\n            result.append([s, 1])\n    return result\n\n\ndef run_length_decode(seq):\n    \"\"\"Take a previously encoded sequence and reconstruct the original from\n    it.\"\"\"\n    result = []\n    for s, i in seq:\n        for _ in range(i):\n            result.append(s)\n    return result\n\n\n# We use lists of a type that should have a relatively high duplication rate,\n# otherwise we'd almost never get any runs.\nLists = st.lists(st.integers(0, 10))\n\n\n@given(Lists)\ndef test_decodes_to_starting_sequence(ls):\n    \"\"\"If we encode a sequence and then decode the result, we should get the\n    original sequence back.\n\n    Otherwise we've done something very wrong.\n    \"\"\"\n    assert run_length_decode(run_length_encode(ls)) == ls\n\n\n@given(Lists, st.data())\ndef test_duplicating_an_element_does_not_increase_length(ls, data):\n    \"\"\"The previous test could be passed by simply returning the input sequence\n    so we need something that tests the compression property of our encoding.\n\n    In this test we deliberately introduce or extend a run and assert\n    that this does not increase the length of our encoding, because they\n    should be part of the same run in the final result.\n    \"\"\"\n    # We use assume to get a valid index into the list. We could also have used\n    # e.g. flatmap, but this is relatively straightforward and will tend to\n    # perform better.\n    assume(ls)\n    i = data.draw(st.integers(0, len(ls) - 1))\n    ls2 = list(ls)\n    # duplicating the value at i right next to it guarantees they are part of\n    # the same run in the resulting compression.\n    ls2.insert(i, ls2[i])\n    assert len(run_length_encode(ls2)) == len(run_length_encode(ls))\n"
  },
  {
    "path": "hypothesis-python/pyproject.toml",
    "content": "[build-system]\n# require a recent setuptools for `license = ` support\nrequires = [\"setuptools >= 78.1.0\", \"wheel\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"hypothesis\"\n# see [tool.setuptools.dynamic]\ndynamic = [\"version\"]\nauthors = [\n    { name = \"David R. MacIver and Zac Hatfield-Dodds\", email = \"david@drmaciver.com\" }\n]\ndescription = \"The property-based testing library for Python\"\n\nlicense = \"MPL-2.0\"\nrequires-python = \">= 3.10\"\nkeywords = [\"python\", \"testing\", \"fuzzing\", \"property-based-testing\"]\nclassifiers = [\n    \"Development Status :: 5 - Production/Stable\",\n    \"Framework :: Hypothesis\",\n    \"Framework :: Pytest\",\n    \"Intended Audience :: Developers\",\n    \"Operating System :: Unix\",\n    \"Operating System :: POSIX\",\n    \"Operating System :: Microsoft :: Windows\",\n    \"Programming Language :: Python\",\n    \"Programming Language :: Python :: 3\",\n    \"Programming Language :: Python :: 3 :: Only\",\n    \"Programming Language :: Python :: 3.10\",\n    \"Programming Language :: Python :: 3.11\",\n    \"Programming Language :: Python :: 3.12\",\n    \"Programming Language :: Python :: 3.13\",\n    \"Programming Language :: Python :: 3.14\",\n    \"Programming Language :: Python :: Implementation :: CPython\",\n    \"Programming Language :: Python :: Implementation :: PyPy\",\n    \"Topic :: Education :: Testing\",\n    \"Topic :: Software Development :: Testing\",\n    \"Typing :: Typed\",\n]\n\ndependencies = [\n    \"exceptiongroup>=1.0.0; python_version<'3.11'\",\n    \"sortedcontainers>=2.1.0,<3.0.0\",\n]\n\n# Avoid changing this by hand. This is automatically updated by update_changelog_and_version.\n[project.readme]\ntext = \"\"\"<div align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/HypothesisWorks/hypothesis/master/brand/dragonfly-rainbow.svg\" width=\"300\">\n</div>\n\n# Hypothesis\n\n* [Website](https://hypothesis.works/)\n* [Documentation](https://hypothesis.readthedocs.io/en/latest/)\n* [Source code](https://github.com/hypothesisWorks/hypothesis/)\n* [Contributing](https://github.com/HypothesisWorks/hypothesis/blob/master/CONTRIBUTING.rst)\n* [Community](https://hypothesis.readthedocs.io/en/latest/community.html)\n\nHypothesis is the property-based testing library for Python. With Hypothesis, you write tests which should pass for all inputs in whatever range you describe, and let Hypothesis randomly choose which of those inputs to check - including edge cases you might not have thought about. For example:\n\n```python\nfrom hypothesis import given, strategies as st\n\n\n@given(st.lists(st.integers()))\ndef test_matches_builtin(ls):\n    assert sorted(ls) == my_sort(ls)\n```\n\nThis randomized testing can catch bugs and edge cases that you didn't think of and wouldn't have found. In addition, when Hypothesis does find a bug, it doesn't just report any failing example — it reports the simplest possible one. This makes property-based tests a powerful tool for debugging, as well as testing.\n\nFor instance,\n\n```python\ndef my_sort(ls):\n    return sorted(set(ls))\n```\n\nfails with the simplest possible failing example:\n\n```\nFalsifying example: test_matches_builtin(ls=[0, 0])\n```\n\n### Installation\n\nTo install Hypothesis:\n\n```\npip install hypothesis\n```\n\nThere are also [optional extras available](https://hypothesis.readthedocs.io/en/latest/extras.html).\n\"\"\"\ncontent-type = \"text/markdown\"\n\n[project.urls]\nhomepage = \"https://hypothesis.works\"\nsource = \"https://github.com/HypothesisWorks/hypothesis\"\nchangelog = \"https://hypothesis.readthedocs.io/en/latest/changelog.html\"\ndocumentation = \"https://hypothesis.readthedocs.io\"\nissues = \"https://github.com/HypothesisWorks/hypothesis/issues\"\n\n[project.optional-dependencies]\ncli = [\"click>=7.0\", \"black>=20.8b0\", \"rich>=9.0.0\"]\ncodemods = [\"libcst>=0.3.16\"]\nghostwriter = [\"black>=20.8b0\"]\npytz = [\"pytz>=2014.1\"]\ndateutil = [\"python-dateutil>=1.4\"]\nlark = [\"lark>=0.10.1\"]  # probably still works with old `lark-parser` too\nnumpy = [\"numpy>=1.21.6\"]  # oldest with wheels for non-EOL Python (for now)\npandas = [\"pandas>=1.1\"]\npytest = [\"pytest>=4.6\"]\ndpcontracts = [\"dpcontracts>=0.4\"]\nredis = [\"redis>=3.0.0\"]\ncrosshair = [\"hypothesis-crosshair>=0.0.27\", \"crosshair-tool>=0.0.102\"]\n# zoneinfo is an odd one: every dependency is platform-conditional.\nzoneinfo = [\"tzdata>=2025.3; sys_platform == 'win32' or sys_platform == 'emscripten'\"]\n# We only support Django versions with upstream support - see\n# https://www.djangoproject.com/download/#supported-versions\n# We also leave the choice of timezone library to the user, since it\n# might be zoneinfo or pytz depending on version and configuration.\ndjango = [\"django>=4.2\"]\nwatchdog = [\"watchdog>=4.0.0\"]\n# Avoid changing this by hand. This is automatically updated by update_changelog_and_version\nall = [\"black>=20.8b0\", \"click>=7.0\", \"crosshair-tool>=0.0.102\", \"django>=4.2\", \"dpcontracts>=0.4\", \"hypothesis-crosshair>=0.0.27\", \"lark>=0.10.1\", \"libcst>=0.3.16\", \"numpy>=1.21.6\", \"pandas>=1.1\", \"pytest>=4.6\", \"python-dateutil>=1.4\", \"pytz>=2014.1\", \"redis>=3.0.0\", \"rich>=9.0.0\", \"tzdata>=2025.3; sys_platform == 'win32' or sys_platform == 'emscripten'\", \"watchdog>=4.0.0\"]\n\n[tool.setuptools.dynamic]\nversion = {attr = \"hypothesis.version.__version__\"}\n\n[tool.setuptools.package-data]\nhypothesis = [\"vendor/tlds-alpha-by-domain.txt\"]\n\n[project.scripts]\nhypothesis = \"hypothesis.extra.cli:main\"\n\n[project.entry-points.pytest11]\nhypothesispytest = \"_hypothesis_pytestplugin\"\n\n[tool.coverage.run]\nparallel = true\nbranch = true\nsource = [\"hypothesis\"]\nomit = [\n    \"**/_hypothesis_ftz_detector.py\",\n    \"**/_hypothesis_pytestplugin.py\",\n    \"**/_hypothesis_globals.py\",\n    \"**/extra/array_api.py\",\n    \"**/extra/cli.py\",\n    \"**/extra/django/*.py\",\n    \"**/extra/ghostwriter.py\",\n    \"**/extra/pytestplugin.py\",\n    \"**/internal/scrutineer.py\",\n    \"**/utils/terminal.py\",\n    \"**/internal/conjecture/provider_conformance.py\",\n    # covered by our attrs tests in check-niche\n    \"**/strategies/_internal/attrs.py\"\n]\n\n[tool.coverage.report]\nfail_under = 100\nshow_missing = true\nskip_covered = true\nexclude_lines = [\n    \"pragma: no cover\",\n    \"raise NotImplementedError\",\n    \"def __repr__\",\n    \"def _repr_pretty_\",\n    \"def __ne__\",\n    \"def __copy__\",\n    \"def __deepcopy__\",\n    \"except ImportError:\",\n    \"except ModuleNotFoundError:\",\n    \"if PYPY:\",\n    \"if TYPE_CHECKING:\",\n    \"if sys\\\\.version_info\",\n    \"if \\\"[\\\\w\\\\.]+\\\" in sys\\\\.modules:\",\n    \"if .+ := sys\\\\.modules\\\\.get\\\\(\\\"[\\\\w\\\\.]+\\\"\\\\)\",\n    \"@overload\",\n    \"if .*\\\\bnot .*provider.avoid_realization\",\n]\n"
  },
  {
    "path": "hypothesis-python/pyrightconfig.json",
    "content": "{\n  \"include\": [\"src\"],\n  \"typeCheckingMode\": \"strict\"\n}\n"
  },
  {
    "path": "hypothesis-python/scripts/basic-test.sh",
    "content": "#!/bin/bash\nset -e -o xtrace\n\nHERE=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\ncd \"$HERE/..\"\n\npython -c '\nimport os\nfor k, v in sorted(dict(os.environ).items()):\n    print(\"%s=%s\" % (k, v))\n'\n\npip install .\n\n\nPYTEST=\"python -bb -X dev -m pytest -nauto --durations-min=1.0\"\n\n# Run all the no-extra-dependency tests for this version (except slow nocover tests)\n$PYTEST tests/cover tests/pytest\n\n# Run tests for each extra module while the requirements are installed\npip install \".[pytz, dateutil, zoneinfo]\"\n$PYTEST tests/datetime/\npip uninstall -y pytz python-dateutil\n\npip install \".[dpcontracts]\"\n$PYTEST tests/dpcontracts/\npip uninstall -y dpcontracts\n\n# use pinned redis version instead of inheriting from fakeredis\npip install \"$(grep '^redis==' ../requirements/coverage.txt)\"\npip install \"$(grep 'fakeredis==' ../requirements/coverage.txt)\"\n$PYTEST tests/redis/\npip uninstall -y redis fakeredis\n\npip install \"$(grep 'typing-extensions==' ../requirements/coverage.txt)\"\n$PYTEST tests/typing_extensions/\npip uninstall -y typing_extensions\n\npip install \".[lark]\"\npip install \"$(grep -m 1 -oE 'lark>=([0-9.]+)' ../hypothesis-python/pyproject.toml | tr '>' =)\"\n$PYTEST -Wignore tests/lark/\npip install \"$(grep 'lark==' ../requirements/coverage.txt)\"\n$PYTEST tests/lark/\npip uninstall -y lark\n\nif [ \"$(python -c $'import platform, sys; print(sys.version_info.releaselevel == \\'final\\' and platform.python_implementation() not in (\"PyPy\", \"GraalVM\"))')\" = \"True\" ] ; then\n  pip install \".[codemods,cli]\"\n  $PYTEST tests/codemods/\n  pip uninstall -y libcst click\n\n  if [ \"$(python -c 'import sys; print(sys.version_info[:2] == (3, 10))')\" = \"True\" ] ; then\n    # Per NEP-29, this is the last version to support Python 3.10\n    pip install numpy==2.2.6\n  else\n    pip install \"$(grep 'numpy==' ../requirements/coverage.txt)\"\n  fi\n\n  pip install \"$(grep -E 'black(==| @)' ../requirements/coverage.txt)\"\n  $PYTEST tests/ghostwriter/\n  pip uninstall -y black numpy\nfi\n\nif [ \"$(python -c 'import sys; print(sys.version_info[:2] == (3, 10))')\" = \"False\" ] ; then\n  exit 0\nfi\n\n$PYTEST tests/nocover/\n\n# Run some tests without docstrings or assertions, to catch bugs\n# like issue #822 in one of the test decorators.  See also #1541.\nPYTHONOPTIMIZE=2 $PYTEST \\\n    -W'ignore:assertions not in test modules or plugins will be ignored because assert statements are not executed by the underlying Python interpreter:pytest.PytestConfigWarning' \\\n    -W'ignore:Module already imported so cannot be rewritten:pytest.PytestAssertRewriteWarning' \\\n    tests/cover/test_testdecorators.py\n\ncase \"$(python -c 'import platform; print(platform.python_implementation())')\" in\n  PyPy|GraalVM)\n    ;;\n  *)\n    pip install .[django]\n    HYPOTHESIS_DJANGO_USETZ=TRUE python -m tests.django.manage test tests.django\n    HYPOTHESIS_DJANGO_USETZ=FALSE python -m tests.django.manage test tests.django\n    pip uninstall -y django pytz\n\n    pip install \"$(grep 'numpy==' ../requirements/coverage.txt)\"\n    $PYTEST tests/array_api\n    $PYTEST tests/numpy\n\n    pip install \"$(grep 'pandas==' ../requirements/coverage.txt)\"\n    $PYTEST tests/pandas\nesac\n"
  },
  {
    "path": "hypothesis-python/scripts/other-tests.sh",
    "content": "#!/bin/bash\nset -e -o xtrace\n\nHERE=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\ncd \"$HERE/..\"\n\npip install .\n\n\nPYTEST=\"python -bb -X dev -m pytest -nauto --durations-min=1.0\"\n\n# Run some tests without docstrings or assertions, to catch bugs\n# like issue #822 in one of the test decorators.  See also #1541.\nPYTHONOPTIMIZE=2 $PYTEST \\\n    -W'ignore:assertions not in test modules or plugins will be ignored because assert statements are not executed by the underlying Python interpreter:pytest.PytestConfigWarning' \\\n    -W'ignore:Module already imported so cannot be rewritten:pytest.PytestAssertRewriteWarning' \\\n    tests/cover/test_testdecorators.py\n\n# Run tests for each extra module while the requirements are installed\npip install \".[pytz, dateutil, zoneinfo]\"\n$PYTEST tests/datetime/\npip uninstall -y pytz python-dateutil\n\npip install \".[dpcontracts]\"\n$PYTEST tests/dpcontracts/\npip uninstall -y dpcontracts\n\npip install attrs\n$PYTEST tests/attrs/\npip uninstall -y attrs\n\n# use pinned redis version instead of inheriting from fakeredis\npip install \"$(grep '^redis==' ../requirements/coverage.txt)\"\npip install \"$(grep 'fakeredis==' ../requirements/coverage.txt)\"\npip install \"$(grep 'typing-extensions==' ../requirements/coverage.txt)\"\n$PYTEST tests/redis/\npip uninstall -y redis fakeredis\n\n$PYTEST tests/typing_extensions/\nif [ \"$HYPOTHESIS_PROFILE\" != \"crosshair\" ] && [ \"$(python -c 'import sys; print(sys.version_info[:2] > (3, 10))')\" = \"True\" ]; then\n  pip uninstall -y typing-extensions\nfi\n\npip install \"$(grep 'annotated-types==' ../requirements/coverage.txt)\"\n$PYTEST tests/test_annotated_types.py\npip uninstall -y annotated-types\n\npip install \".[lark]\"\npip install \"$(grep -m 1 -oE 'lark>=([0-9.]+)' ../hypothesis-python/pyproject.toml | tr '>' =)\"\n$PYTEST -Wignore tests/lark/\npip install \"$(grep 'lark==' ../requirements/coverage.txt)\"\n$PYTEST tests/lark/\npip uninstall -y lark\n\nif [ \"$(python -c $'import platform, sys; print(sys.version_info.releaselevel == \\'final\\' and platform.python_implementation() not in (\"PyPy\", \"GraalVM\"))')\" = \"True\" ] ; then\n  pip install \".[codemods,cli]\"\n  $PYTEST tests/codemods/\n\n  if [ \"$(python -c 'import sys; print(sys.version_info[:2] == (3, 10))')\" = \"True\" ] ; then\n    # Per NEP-29, this is the last version to support Python 3.10\n    pip install numpy==2.2.6\n  else\n    pip install \"$(grep 'numpy==' ../requirements/coverage.txt)\"\n  fi\n\n  pip install \"$(grep -E 'black(==| @)' ../requirements/coverage.txt)\"\n  $PYTEST tests/patching/\n  pip uninstall -y libcst\n\n  # One of the ghostwriter tests uses attrs (though hypothesis[ghostwriter] does not require attrs).\n  pip install attrs\n  $PYTEST tests/ghostwriter/\n  pip uninstall -y attrs\n  pip uninstall -y black\n\n  if [ \"$HYPOTHESIS_PROFILE\" != \"crosshair\" ] ; then\n    # Crosshair tracer is not compatible with no-gil\n    if [ \"$(python -c \"import sys; print('free-threading' in sys.version)\")\" != \"True\" ] ; then\n      # Run twice, interleaved by other tests, to make it more probable to tickle any problems\n      # from accidentally caching/retaining crosshair proxy objects\n      pip install pytest-repeat\n      pip install -r ../requirements/crosshair.txt\n      # requirements/crosshair.txt pins hypothesis. Re-override it with our local changes\n      pip install .\n      $PYTEST --count=2 --repeat-scope=session tests/numpy tests/crosshair\n      # ...but running twice takes time, don't overdo it\n      $PYTEST tests/array_api\n    else\n      $PYTEST tests/array_api tests/numpy\n    fi\n  fi\nfi\n"
  },
  {
    "path": "hypothesis-python/scripts/validate_branch_check.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport json\nimport sys\nfrom collections import defaultdict\nfrom pathlib import Path\n\nif __name__ == \"__main__\":\n    data = []\n    for p in Path.cwd().glob(\"branch-check*\"):\n        data.extend(json.loads(l) for l in p.read_text(\"utf-8\").splitlines())\n\n    checks = defaultdict(set)\n\n    for d in data:\n        checks[d[\"name\"]].add(d[\"value\"])\n\n    if not checks:\n        print(\"No branches found in the branch-check file?\")\n        sys.exit(1)\n\n    always_true = []\n    always_false = []\n\n    for c, vs in sorted(checks.items()):\n        if len(vs) < 2:\n            v = next(iter(vs))\n            assert v in (False, True)\n            if v:\n                always_true.append(c)\n            else:\n                always_false.append(c)\n\n    failure = always_true or always_false\n\n    if failure:\n        print(\"Some branches were not properly covered.\")\n\n    if always_true:\n        print()\n        print(\"The following were always True:\")\n        for c in always_true:\n            print(f\"  * {c}\")\n    if always_false:\n        print()\n        print(\"The following were always False:\")\n        for c in always_false:\n            print(f\"  * {c}\")\n    if failure:\n        sys.exit(1)\n\n    print(\n        f\"\"\"Successfully validated {len(checks)} branch{\"es\" if len(checks) > 1 else \"\"}.\"\"\"\n    )\n"
  },
  {
    "path": "hypothesis-python/src/_hypothesis_ftz_detector.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\nThis is a toolkit for determining which module set the \"flush to zero\" flag.\n\nFor details, see the docstring and comments in `identify_ftz_culprit()`.  This module\nis defined outside the main Hypothesis namespace so that we can avoid triggering\nimport of Hypothesis itself from each subprocess which must import the worker function.\n\"\"\"\n\nimport importlib\nimport sys\nfrom collections.abc import Callable\nfrom typing import TYPE_CHECKING, TypeAlias\n\nif TYPE_CHECKING:\n    from multiprocessing import Queue\n\nFTZCulprits: TypeAlias = tuple[bool | None, set[str]]\n\n\nKNOWN_EVER_CULPRITS = (\n    # https://moyix.blogspot.com/2022/09/someones-been-messing-with-my-subnormals.html\n    # fmt: off\n    \"archive-pdf-tools\", \"bgfx-python\", \"bicleaner-ai-glove\", \"BTrees\", \"cadbiom\",\n    \"ctranslate2\", \"dyNET\", \"dyNET38\", \"gevent\", \"glove-python-binary\", \"higra\",\n    \"hybridq\", \"ikomia\", \"ioh\", \"jij-cimod\", \"lavavu\", \"lavavu-osmesa\", \"MulticoreTSNE\",\n    \"neural-compressor\", \"nwhy\", \"openjij\", \"openturns\", \"perfmetrics\", \"pHashPy\",\n    \"pyace-lite\", \"pyapr\", \"pycompadre\", \"pycompadre-serial\", \"PyKEP\", \"pykep\",\n    \"pylimer-tools\", \"pyqubo\", \"pyscf\", \"PyTAT\", \"python-prtree\", \"qiskit-aer\",\n    \"qiskit-aer-gpu\", \"RelStorage\", \"sail-ml\", \"segmentation\", \"sente\", \"sinr\",\n    \"snapml\", \"superman\", \"symengine\", \"systran-align\", \"texture-tool\", \"tsne-mp\",\n    \"xcsf\",\n    # fmt: on\n)\n\n\ndef flush_to_zero() -> bool:\n    # If this subnormal number compares equal to zero we have a problem\n    return 2.0**-1073 == 0\n\n\ndef run_in_process(fn: Callable[..., FTZCulprits], *args: object) -> FTZCulprits:\n    import multiprocessing as mp\n\n    mp.set_start_method(\"spawn\", force=True)\n    q: Queue[FTZCulprits] = mp.Queue()\n    p = mp.Process(target=target, args=(q, fn, *args))\n    p.start()\n    retval = q.get()\n    p.join()\n    return retval\n\n\ndef target(\n    q: \"Queue[FTZCulprits]\", fn: Callable[..., FTZCulprits], *args: object\n) -> None:\n    q.put(fn(*args))\n\n\ndef always_imported_modules() -> FTZCulprits:\n    return flush_to_zero(), set(sys.modules)\n\n\ndef modules_imported_by(mod: str) -> FTZCulprits:\n    \"\"\"Return the set of modules imported transitively by mod.\"\"\"\n    before = set(sys.modules)\n    try:\n        importlib.import_module(mod)\n    except Exception:\n        return None, set()\n    imports = set(sys.modules) - before\n    return flush_to_zero(), imports\n\n\n# We don't want to redo all the expensive process-spawning checks when we've already\n# done them, so we cache known-good packages and a known-FTZ result if we have one.\nKNOWN_FTZ = None\nCHECKED_CACHE = set()\n\n\ndef identify_ftz_culprits() -> str:\n    \"\"\"Find the modules in sys.modules which cause \"mod\" to be imported.\"\"\"\n    # If we've run this function before, return the same result.\n    global KNOWN_FTZ\n    if KNOWN_FTZ:\n        return KNOWN_FTZ\n    # Start by determining our baseline: the FTZ and sys.modules state in a fresh\n    # process which has only imported this module and nothing else.\n    always_enables_ftz, always_imports = run_in_process(always_imported_modules)\n    if always_enables_ftz:\n        raise RuntimeError(\"Python is always in FTZ mode, even without imports!\")\n    CHECKED_CACHE.update(always_imports)\n\n    # Next, we'll search through sys.modules looking for a package (or packages) such\n    # that importing them in a new process sets the FTZ state.  As a heuristic, we'll\n    # start with packages known to have ever enabled FTZ, then top-level packages as\n    # a way to eliminate large fractions of the search space relatively quickly.\n    def key(name: str) -> tuple[bool, int, str]:\n        \"\"\"Prefer known-FTZ modules, then top-level packages, then alphabetical.\"\"\"\n        return (name not in KNOWN_EVER_CULPRITS, name.count(\".\"), name)\n\n    # We'll track the set of modules to be checked, and those which do trigger FTZ.\n    candidates = set(sys.modules) - CHECKED_CACHE\n    triggering_modules = {}\n    while candidates:\n        mod = min(candidates, key=key)\n        candidates.discard(mod)\n        enables_ftz, imports = run_in_process(modules_imported_by, mod)\n        imports -= CHECKED_CACHE\n        if enables_ftz:\n            triggering_modules[mod] = imports\n            candidates &= imports\n        else:\n            candidates -= imports\n            CHECKED_CACHE.update(imports)\n\n    # We only want to report the 'top level' packages which enable FTZ - for example,\n    # if the enabling code is in `a.b`, and `a` in turn imports `a.b`, we prefer to\n    # report `a`.  On the other hand, if `a` does _not_ import `a.b`, as is the case\n    # for `hypothesis.extra.*` modules, then `a` will not be in `triggering_modules`\n    # and we'll report `a.b` here instead.\n    prefixes = tuple(n + \".\" for n in triggering_modules)\n    result = {k for k in triggering_modules if not k.startswith(prefixes)}\n\n    # Suppose that `bar` enables FTZ, and `foo` imports `bar`.  At this point we're\n    # tracking both, but only want to report the latter.\n    for a in sorted(result):\n        for b in sorted(result):\n            if a in triggering_modules[b] and b not in triggering_modules[a]:\n                result.discard(b)\n\n    # There may be a cyclic dependency which that didn't handle, or simply two\n    # separate modules which both enable FTZ.  We already gave up comprehensive\n    # reporting for speed above (`candidates &= imports`), so we'll also buy\n    # simpler reporting by arbitrarily selecting the alphabetically first package.\n    KNOWN_FTZ = min(result)  # Cache the result - it's likely this will trigger again!\n    return KNOWN_FTZ\n\n\nif __name__ == \"__main__\":\n    # This would be really really annoying to write automated tests for, so I've\n    # done some manual exploratory testing: `pip install grequests gevent==21.12.0`,\n    # and call print() as desired to observe behavior.\n    import grequests  # noqa\n\n    # To test without skipping to a known answer, uncomment the following line and\n    # change the last element of key from `name` to `-len(name)` so that we check\n    # grequests before gevent.\n    # KNOWN_EVER_CULPRITS = [c for c in KNOWN_EVER_CULPRITS if c != \"gevent\"]\n    print(identify_ftz_culprits())\n"
  },
  {
    "path": "hypothesis-python/src/_hypothesis_globals.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\nModule for globals shared between plugin(s) and the main hypothesis module, without\ndepending on either. This file should have no imports outside of stdlib.\n\"\"\"\n\nimport os\n\nin_initialization = 1\n\"\"\"If >0, indicates that hypothesis is still initializing (importing or loading\nthe test environment). `import hypothesis` will cause this number to be decremented,\nand the pytest plugin increments at load time, then decrements it just before each test\nsession starts. However, this leads to a hole in coverage if another pytest plugin\nimports hypothesis before our plugin is loaded. HYPOTHESIS_EXTEND_INITIALIZATION may\nbe set to pre-increment the value on behalf of _hypothesis_pytestplugin, plugging the\nhole.\"\"\"\n\nif os.environ.get(\"HYPOTHESIS_EXTEND_INITIALIZATION\"):\n    in_initialization += 1\n"
  },
  {
    "path": "hypothesis-python/src/_hypothesis_pytestplugin.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\nThe pytest plugin for Hypothesis.\n\nWe move this from the old location at `hypothesis.extra.pytestplugin` so that it\ncan be loaded by Pytest without importing Hypothesis.  In turn, this means that\nHypothesis will not load our own third-party plugins (with associated side-effects)\nunless and until the user explicitly runs `import hypothesis`.\n\nSee https://github.com/HypothesisWorks/hypothesis/issues/3140 for details.\n\"\"\"\n\nimport base64\nimport json\nimport os\nimport sys\nimport warnings\nfrom fnmatch import fnmatch\nfrom inspect import signature\n\nimport _hypothesis_globals\nimport pytest\n\ntry:\n    from _pytest.junitxml import xml_key\nexcept ImportError:\n    xml_key = \"_xml\"  # type: ignore\n\nLOAD_PROFILE_OPTION = \"--hypothesis-profile\"\nVERBOSITY_OPTION = \"--hypothesis-verbosity\"\nPRINT_STATISTICS_OPTION = \"--hypothesis-show-statistics\"\nSEED_OPTION = \"--hypothesis-seed\"\nEXPLAIN_OPTION = \"--hypothesis-explain\"\n\n_VERBOSITY_NAMES = [\"quiet\", \"normal\", \"verbose\", \"debug\"]\n_ALL_OPTIONS = [\n    LOAD_PROFILE_OPTION,\n    VERBOSITY_OPTION,\n    PRINT_STATISTICS_OPTION,\n    SEED_OPTION,\n    EXPLAIN_OPTION,\n]\nSTATS_KEY = \"_hypothesis_stats\"\nFAILING_EXAMPLES_KEY = \"_hypothesis_failing_examples\"\n\n\nclass StoringReporter:\n    def __init__(self, config):\n        assert \"hypothesis\" in sys.modules\n        from hypothesis.reporting import default\n\n        self.report = default\n        self.config = config\n        self.results = []\n\n    def __call__(self, msg):\n        if self.config.getoption(\"capture\", \"fd\") == \"no\":\n            self.report(msg)\n        if not isinstance(msg, str):\n            msg = repr(msg)\n        self.results.append(msg)\n\n\n# Avoiding distutils.version.LooseVersion due to\n# https://github.com/HypothesisWorks/hypothesis/issues/2490\nif tuple(map(int, pytest.__version__.split(\".\")[:2])) < (4, 6):  # pragma: no cover\n    import warnings\n\n    PYTEST_TOO_OLD_MESSAGE = \"\"\"\n        You are using pytest version %s. Hypothesis tests work with any test\n        runner, but our pytest plugin requires pytest 4.6 or newer.\n        Note that the pytest developers no longer support your version either!\n        Disabling the Hypothesis pytest plugin...\n    \"\"\"\n    warnings.warn(PYTEST_TOO_OLD_MESSAGE % (pytest.__version__,), stacklevel=1)\n\nelse:\n    # Restart side-effect detection as early as possible, to maximize coverage. We\n    # need balanced increment/decrement in configure/sessionstart to support nested\n    # pytest (e.g. runpytest_inprocess), so this early increment in effect replaces\n    # the first one in pytest_configure.\n    if not os.environ.get(\"HYPOTHESIS_EXTEND_INITIALIZATION\"):\n        _hypothesis_globals.in_initialization += 1\n        if \"hypothesis\" in sys.modules:\n            # Some other plugin has imported hypothesis, so we'll check if there\n            # have been undetected side-effects and warn if so.\n            from hypothesis.configuration import notice_initialization_restarted\n\n            notice_initialization_restarted()\n\n    def pytest_addoption(parser):\n        group = parser.getgroup(\"hypothesis\", \"Hypothesis\")\n        group.addoption(\n            LOAD_PROFILE_OPTION,\n            action=\"store\",\n            help=\"Load in a registered hypothesis.settings profile\",\n        )\n        group.addoption(\n            VERBOSITY_OPTION,\n            action=\"store\",\n            choices=_VERBOSITY_NAMES,\n            help=\"Override profile with verbosity setting specified\",\n        )\n        group.addoption(\n            PRINT_STATISTICS_OPTION,\n            action=\"store_true\",\n            help=\"Configure when statistics are printed\",\n            default=False,\n        )\n        group.addoption(\n            SEED_OPTION,\n            action=\"store\",\n            help=\"Set a seed to use for all Hypothesis tests\",\n        )\n        group.addoption(\n            EXPLAIN_OPTION,\n            action=\"store_true\",\n            help=\"Enable the `explain` phase for failing Hypothesis tests\",\n            default=False,\n        )\n\n    def _any_hypothesis_option(config):\n        return bool(any(config.getoption(opt) for opt in _ALL_OPTIONS))\n\n    def pytest_report_header(config):\n        if not (\n            config.option.verbose >= 1\n            or \"hypothesis\" in sys.modules\n            or _any_hypothesis_option(config)\n        ):\n            return None\n\n        from hypothesis import Verbosity, settings\n\n        if config.option.verbose < 1 and settings.default.verbosity < Verbosity.verbose:\n            return None\n        settings_str = settings.default.show_changed()\n        if settings_str != \"\":\n            settings_str = f\" -> {settings_str}\"\n        return (\n            f\"hypothesis profile {settings.get_current_profile_name()!r}{settings_str}\"\n        )\n\n    def pytest_configure(config):\n        config.addinivalue_line(\"markers\", \"hypothesis: Tests which use hypothesis.\")\n        if not _any_hypothesis_option(config):\n            return\n        from hypothesis import Phase, Verbosity, core, settings\n\n        profile = config.getoption(LOAD_PROFILE_OPTION)\n        if profile:\n            settings.load_profile(profile)\n        verbosity_name = config.getoption(VERBOSITY_OPTION)\n        if verbosity_name and verbosity_name != settings.default.verbosity.name:\n            verbosity_value = Verbosity[verbosity_name]\n            name = (\n                f\"{settings.get_current_profile_name()}-with-{verbosity_name}-verbosity\"\n            )\n            # register_profile creates a new profile, exactly like the current one,\n            # with the extra values given (in this case 'verbosity')\n            settings.register_profile(name, verbosity=verbosity_value)\n            settings.load_profile(name)\n        if (\n            config.getoption(EXPLAIN_OPTION)\n            and Phase.explain not in settings.default.phases\n        ):\n            name = f\"{settings.get_current_profile_name()}-with-explain-phase\"\n            phases = (*settings.default.phases, Phase.explain)\n            settings.register_profile(name, phases=phases)\n            settings.load_profile(name)\n\n        seed = config.getoption(SEED_OPTION)\n        if seed is not None:\n            try:\n                seed = int(seed)\n            except ValueError:\n                pass\n            core.global_force_seed = seed\n\n    @pytest.hookimpl(hookwrapper=True)\n    def pytest_runtest_call(item):\n        __tracebackhide__ = True\n        if not (hasattr(item, \"obj\") and \"hypothesis\" in sys.modules):\n            yield\n            return\n\n        from hypothesis import core, is_hypothesis_test\n\n        # See https://github.com/pytest-dev/pytest/issues/9159\n        core.pytest_shows_exceptiongroups = (\n            getattr(pytest, \"version_tuple\", ())[:2] >= (7, 2)\n            or item.config.getoption(\"tbstyle\", \"auto\") == \"native\"\n        )\n        core.running_under_pytest = True\n\n        if not is_hypothesis_test(item.obj):\n            # If @given was not applied, check whether other hypothesis\n            # decorators were applied, and raise an error if they were.\n            # We add this frame of indirection to enable __tracebackhide__.\n            def raise_hypothesis_usage_error(msg):\n                raise InvalidArgument(msg)\n\n            if getattr(item.obj, \"is_hypothesis_strategy_function\", False):\n                from hypothesis.errors import InvalidArgument\n\n                raise_hypothesis_usage_error(\n                    f\"{item.nodeid} is a function that returns a Hypothesis strategy, \"\n                    \"but pytest has collected it as a test function.  This is useless \"\n                    \"as the function body will never be executed.  To define a test \"\n                    \"function, use @given instead of @composite.\"\n                )\n            message = \"Using `@%s` on a test without `@given` is completely pointless.\"\n            for name, attribute in [\n                (\"example\", \"hypothesis_explicit_examples\"),\n                (\"seed\", \"_hypothesis_internal_use_seed\"),\n                (\"settings\", \"_hypothesis_internal_settings_applied\"),\n                (\"reproduce_example\", \"_hypothesis_internal_use_reproduce_failure\"),\n            ]:\n                if hasattr(item.obj, attribute):\n                    from hypothesis.errors import InvalidArgument\n\n                    raise_hypothesis_usage_error(message % (name,))\n            yield\n            return\n\n        from hypothesis import HealthCheck, settings as Settings\n        from hypothesis.internal.escalation import current_pytest_item\n        from hypothesis.internal.healthcheck import fail_health_check\n        from hypothesis.reporting import with_reporter\n        from hypothesis.statistics import collector, describe_statistics\n\n        # Retrieve the settings for this test from the test object, which\n        # is normally a Hypothesis wrapped_test wrapper. If this doesn't\n        # work, the test object is probably something weird\n        # (e.g a stateful test wrapper), so we skip the function-scoped\n        # fixture check.\n        settings = getattr(\n            item.obj, \"_hypothesis_internal_use_settings\", Settings.default\n        )\n\n        # Check for suspicious use of function-scoped fixtures, but only\n        # if the corresponding health check is not suppressed.\n        fixture_params = False\n        if not set(settings.suppress_health_check).issuperset(\n            {HealthCheck.function_scoped_fixture, HealthCheck.differing_executors}\n        ):\n            # Warn about function-scoped fixtures, excluding autouse fixtures because\n            # the advice is probably not actionable and the status quo seems OK...\n            # See https://github.com/HypothesisWorks/hypothesis/issues/377 for detail.\n            argnames = None\n            for fx_defs in item._request._fixturemanager.getfixtureinfo(\n                node=item, func=item.function, cls=None\n            ).name2fixturedefs.values():\n                if argnames is None:\n                    argnames = frozenset(signature(item.function).parameters)\n                for fx in fx_defs:\n                    fixture_params |= bool(fx.params)\n                    if fx.argname not in argnames:\n                        continue\n                    active_fx = item._request._get_active_fixturedef(fx.argname)\n                    if active_fx.scope == \"function\":\n                        fail_health_check(\n                            settings,\n                            f\"{item.nodeid!r} uses a function-scoped fixture {fx.argname!r}.\"\n                            \"\\n\\n\"\n                            \"Function-scoped fixtures are not reset between inputs \"\n                            \"generated by `@given(...)`, which is often surprising and \"\n                            \"can cause subtle test bugs.\"\n                            \"\\n\\n\"\n                            \"If you were expecting the fixture to run separately \"\n                            \"for each generated input, then unfortunately you \"\n                            \"will need to find a different way to achieve your \"\n                            \"goal (for example, replacing the fixture with a similar \"\n                            \"context manager inside of the test).\"\n                            \"\\n\\n\"\n                            \"If you are confident that your test will work correctly \"\n                            \"even though the fixture is not reset between generated \"\n                            \"inputs, you can suppress this health check with \"\n                            \"@settings(suppress_health_check=[HealthCheck.function_scoped_fixture]). \"\n                            \"See \"\n                            \"https://hypothesis.readthedocs.io/en/latest/reference/api.html#hypothesis.HealthCheck \"\n                            \"for details.\",\n                            HealthCheck.function_scoped_fixture,\n                        )\n\n        if fixture_params or (item.get_closest_marker(\"parametrize\") is not None):\n            # Disable the differing_executors health check due to false alarms:\n            # see https://github.com/HypothesisWorks/hypothesis/issues/3733\n            fn = getattr(item.obj, \"__func__\", item.obj)\n            fn._hypothesis_internal_use_settings = Settings(\n                parent=settings,\n                suppress_health_check={HealthCheck.differing_executors}\n                | set(settings.suppress_health_check),\n            )\n\n            # Give every parametrized test invocation a unique database key\n            key = item.nodeid.encode()\n            item.obj.hypothesis.inner_test._hypothesis_internal_add_digest = key\n\n        store = StoringReporter(item.config)\n\n        def note_statistics(stats):\n            stats[\"nodeid\"] = item.nodeid\n            item.hypothesis_statistics = describe_statistics(stats)\n\n        with (\n            collector.with_value(note_statistics),\n            with_reporter(store),\n            current_pytest_item.with_value(item),\n        ):\n            yield\n\n        if store.results:\n            item.hypothesis_report_information = \"\\n\".join(store.results)\n\n    def _stash_get(config, key, default):\n        if hasattr(config, \"stash\"):\n            # pytest 7\n            return config.stash.get(key, default)\n        elif hasattr(config, \"_store\"):\n            # pytest 5.4\n            return config._store.get(key, default)\n        else:\n            return getattr(config, key, default)\n\n    @pytest.hookimpl(hookwrapper=True)\n    def pytest_runtest_makereport(item, call):\n        report = (yield).get_result()\n        if hasattr(item, \"hypothesis_report_information\"):\n            report.sections.append((\"Hypothesis\", item.hypothesis_report_information))\n        if report.when != \"teardown\":\n            return\n\n        terminalreporter = item.config.pluginmanager.getplugin(\"terminalreporter\")\n\n        if hasattr(item, \"hypothesis_statistics\"):\n            stats = item.hypothesis_statistics\n            stats_base64 = base64.b64encode(stats.encode()).decode()\n\n            name = \"hypothesis-statistics-\" + item.nodeid\n\n            # Include hypothesis information to the junit XML report.\n            #\n            # Note that when `pytest-xdist` is enabled, `xml_key` is not present in the\n            # stash, so we don't add anything to the junit XML report in that scenario.\n            # https://github.com/pytest-dev/pytest/issues/7767#issuecomment-1082436256\n            xml = _stash_get(item.config, xml_key, None)\n            if xml:\n                xml.add_global_property(name, stats_base64)\n\n            # If there's a terminal report, include our summary stats for each test\n            if terminalreporter is not None:\n                report.__dict__[STATS_KEY] = stats\n\n            # If there's an HTML report, include our summary stats for each test\n            pytest_html = item.config.pluginmanager.getplugin(\"html\")\n            if pytest_html is not None:  # pragma: no cover\n                report.extra = [\n                    *getattr(report, \"extra\", []),\n                    pytest_html.extras.text(stats, name=\"Hypothesis stats\"),\n                ]\n\n        # This doesn't intrinsically have anything to do with the terminalreporter;\n        # we're just cargo-culting a way to get strings back to a single function\n        # even if the test were distributed with pytest-xdist.\n        failing_examples = getattr(item, FAILING_EXAMPLES_KEY, None)\n        if failing_examples and terminalreporter is not None:\n            try:\n                from hypothesis.extra._patching import FAIL_MSG, get_patch_for\n            except ImportError:\n                return\n            # We'll save this as a triple of [filename, hunk_before, hunk_after].\n            triple = get_patch_for(item.obj, [(x, FAIL_MSG) for x in failing_examples])\n            if triple is not None:\n                report.__dict__[FAILING_EXAMPLES_KEY] = json.dumps(triple)\n\n    def pytest_terminal_summary(terminalreporter):\n        failing_examples = []\n        print_stats = terminalreporter.config.getoption(PRINT_STATISTICS_OPTION)\n        if print_stats:\n            terminalreporter.section(\"Hypothesis Statistics\")\n        for reports in terminalreporter.stats.values():\n            for report in reports:\n                stats = report.__dict__.get(STATS_KEY)\n                if stats and print_stats:\n                    terminalreporter.write_line(stats + \"\\n\\n\")\n                examples = report.__dict__.get(FAILING_EXAMPLES_KEY)\n                if examples:\n                    failing_examples.append(json.loads(examples))\n\n        from hypothesis.internal.observability import _WROTE_TO\n\n        if _WROTE_TO:\n            terminalreporter.section(\"Hypothesis\")\n            for fname in sorted(_WROTE_TO):\n                terminalreporter.write_line(f\"observations written to {fname}\")\n\n        if failing_examples:\n            # This must have been imported already to write the failing examples\n            from hypothesis.extra._patching import gc_patches, make_patch, save_patch\n\n            patch = make_patch(failing_examples)\n            try:\n                gc_patches()\n                fname = save_patch(patch)\n            except Exception:\n                # fail gracefully if we hit any filesystem or permissions problems\n                return\n            if not _WROTE_TO:\n                terminalreporter.section(\"Hypothesis\")\n            terminalreporter.write_line(\n                f\"`git apply {fname}` to add failing examples to your code.\"\n            )\n\n    def pytest_collection_modifyitems(items):\n        if \"hypothesis\" not in sys.modules:\n            return\n\n        from hypothesis import is_hypothesis_test\n\n        has_hypothesis_tests = False\n        for item in items:\n            if isinstance(item, pytest.Function) and is_hypothesis_test(item.obj):\n                item.add_marker(\"hypothesis\")\n                has_hypothesis_tests = True\n\n        if has_hypothesis_tests:\n            # Collect local constants now, during test collection, so that this\n            # time is not attributed to whatever test happens to run first.\n            # (see https://github.com/HypothesisWorks/hypothesis/issues/4627)\n            # We might miss weird wrapped uses (if there are no other PBTs!),\n            # in order to avoid the latency from inefficient 3rd party plugins.\n            from hypothesis.internal.conjecture.providers import _get_local_constants\n\n            _get_local_constants()\n\n    def pytest_sessionstart(session):\n        # Note: may be called multiple times, so we can go negative\n        _hypothesis_globals.in_initialization -= 1\n\n    # Monkeypatch some internals to prevent applying @pytest.fixture() to a\n    # function which has already been decorated with @hypothesis.given().\n    # (the reverse case is already an explicit error in Hypothesis)\n    # We do this here so that it catches people on old Pytest versions too.\n    from _pytest import fixtures\n\n    def _ban_given_call(self, function):\n        if \"hypothesis\" in sys.modules:\n            from hypothesis import is_hypothesis_test\n\n            if is_hypothesis_test(function):\n                raise RuntimeError(\n                    f\"Can't apply @pytest.fixture() to {function.__name__} because \"\n                    \"it is already decorated with @hypothesis.given()\"\n                )\n        return _orig_call(self, function)\n\n    _orig_call = fixtures.FixtureFunctionMarker.__call__\n    fixtures.FixtureFunctionMarker.__call__ = _ban_given_call  # type: ignore\n\n    if int(pytest.__version__.split(\".\")[0]) >= 7:  # pragma: no branch\n        # Hook has had this signature since Pytest 7.0, so skip on older versions\n\n        def pytest_ignore_collect(collection_path, config):\n            # Detect, warn about, and mititgate certain misconfigurations;\n            # this is mostly educational but can also speed up collection.\n            if (\n                (name := collection_path.name) == \".hypothesis\"\n                and collection_path.is_dir()\n                and not any(fnmatch(name, p) for p in config.getini(\"norecursedirs\"))\n            ):\n                warnings.warn(\n                    \"Skipping collection of '.hypothesis' directory - this usually \"\n                    \"means you've explicitly set the `norecursedirs` pytest config \"\n                    \"option, replacing rather than extending the default ignores.\",\n                    stacklevel=1,\n                )\n                return True\n            return None  # let other hooks decide\n\n\ndef load():\n    \"\"\"Required for `pluggy` to load a plugin from setuptools entrypoints.\"\"\"\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"Hypothesis is a library for writing unit tests which are parametrized by\nsome source of data.\n\nIt verifies your code against a wide range of input and minimizes any\nfailing examples it finds.\n\"\"\"\n\nimport _hypothesis_globals\n\nfrom hypothesis._settings import HealthCheck, Phase, Verbosity, settings\nfrom hypothesis.control import (\n    assume,\n    currently_in_test_context,\n    event,\n    note,\n    reject,\n    target,\n)\nfrom hypothesis.core import example, find, given, reproduce_failure, seed\nfrom hypothesis.entry_points import run\nfrom hypothesis.internal.detection import is_hypothesis_test\nfrom hypothesis.internal.entropy import register_random\nfrom hypothesis.utils.conventions import infer\nfrom hypothesis.version import __version__, __version_info__\n\n__all__ = [\n    \"HealthCheck\",\n    \"Phase\",\n    \"Verbosity\",\n    \"__version__\",\n    \"__version_info__\",\n    \"assume\",\n    \"currently_in_test_context\",\n    \"event\",\n    \"example\",\n    \"find\",\n    \"given\",\n    \"infer\",\n    \"is_hypothesis_test\",\n    \"note\",\n    \"register_random\",\n    \"reject\",\n    \"reproduce_failure\",\n    \"seed\",\n    \"settings\",\n    \"target\",\n]\n\nrun()\ndel run\n\n_hypothesis_globals.in_initialization -= 1\ndel _hypothesis_globals\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/_settings.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"The settings module configures runtime options for Hypothesis.\n\nEither an explicit settings object can be used or the default object on\nthis module can be modified.\n\"\"\"\n\nimport contextlib\nimport datetime\nimport inspect\nimport os\nfrom collections.abc import Collection, Generator, Sequence\nfrom enum import Enum, EnumMeta, unique\nfrom functools import total_ordering\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    ClassVar,\n    Optional,\n    TypeVar,\n)\n\nfrom hypothesis.errors import (\n    InvalidArgument,\n)\nfrom hypothesis.internal.conjecture.providers import AVAILABLE_PROVIDERS\nfrom hypothesis.internal.reflection import get_pretty_function_description\nfrom hypothesis.internal.validation import check_type, try_convert\nfrom hypothesis.utils.conventions import not_set\nfrom hypothesis.utils.deprecation import note_deprecation\nfrom hypothesis.utils.dynamicvariables import DynamicVariable\n\nif TYPE_CHECKING:\n    from hypothesis.database import ExampleDatabase\n\n__all__ = [\"settings\"]\n\nT = TypeVar(\"T\")\nall_settings: list[str] = [\n    \"max_examples\",\n    \"derandomize\",\n    \"database\",\n    \"verbosity\",\n    \"phases\",\n    \"stateful_step_count\",\n    \"report_multiple_bugs\",\n    \"suppress_health_check\",\n    \"deadline\",\n    \"print_blob\",\n    \"backend\",\n]\n\n\n@unique\n@total_ordering\nclass Verbosity(Enum):\n    \"\"\"Options for the |settings.verbosity| argument to |@settings|.\"\"\"\n\n    quiet = \"quiet\"\n    \"\"\"\n    Hypothesis will not print any output, not even the final falsifying example.\n    \"\"\"\n\n    normal = \"normal\"\n    \"\"\"\n    Standard verbosity. Hypothesis will print the falsifying example, alongside\n    any notes made with |note| (only for the falsfying example).\n    \"\"\"\n\n    verbose = \"verbose\"\n    \"\"\"\n    Increased verbosity. In addition to everything in |Verbosity.normal|, Hypothesis\n    will:\n\n    * Print each test case as it tries it\n    * Print any notes made with |note| for each test case\n    * Print each shrinking attempt\n    * Print all explicit failing examples when using |@example|, instead of only\n      the simplest one\n    \"\"\"\n\n    debug = \"debug\"\n    \"\"\"\n    Even more verbosity. Useful for debugging Hypothesis internals. You probably\n    don't want this.\n    \"\"\"\n\n    @classmethod\n    def _missing_(cls, value):\n        # deprecation pathway for integer values. Can be removed in Hypothesis 7.\n        if isinstance(value, int) and not isinstance(value, bool):\n            int_to_name = {0: \"quiet\", 1: \"normal\", 2: \"verbose\", 3: \"debug\"}\n            if value in int_to_name:\n                note_deprecation(\n                    f\"Passing Verbosity({value}) as an integer is deprecated. \"\n                    \"Hypothesis now treats Verbosity values as strings, not integers. \"\n                    f\"Use Verbosity.{int_to_name[value]} instead.\",\n                    since=\"2025-11-05\",\n                    has_codemod=False,\n                    stacklevel=2,\n                )\n                return cls(int_to_name[value])\n        return None\n\n    def __repr__(self) -> str:\n        return f\"Verbosity.{self.name}\"\n\n    @staticmethod\n    def _int_value(value: \"Verbosity\") -> int:\n        # we would just map Verbosity keys, except it's not hashable\n        mapping = {\n            Verbosity.quiet.name: 0,\n            Verbosity.normal.name: 1,\n            Verbosity.verbose.name: 2,\n            Verbosity.debug.name: 3,\n        }\n        # make sure we don't forget any new verbosity members\n        assert list(mapping.keys()) == [verbosity.name for verbosity in Verbosity]\n        return mapping[value.name]\n\n    def __eq__(self, other: Any) -> bool:\n        if isinstance(other, Verbosity):\n            return super().__eq__(other)\n        return Verbosity._int_value(self) == other\n\n    def __gt__(self, other: Any) -> bool:\n        value1 = Verbosity._int_value(self)\n        value2 = Verbosity._int_value(other) if isinstance(other, Verbosity) else other\n        return value1 > value2\n\n\n@unique\nclass Phase(Enum):\n    \"\"\"Options for the |settings.phases| argument to |@settings|.\"\"\"\n\n    explicit = \"explicit\"\n    \"\"\"\n    Controls whether explicit examples are run.\n    \"\"\"\n\n    reuse = \"reuse\"\n    \"\"\"\n    Controls whether previous examples will be reused.\n    \"\"\"\n\n    generate = \"generate\"\n    \"\"\"\n    Controls whether new examples will be generated.\n    \"\"\"\n\n    target = \"target\"\n    \"\"\"\n    Controls whether examples will be mutated for targeting.\n    \"\"\"\n\n    shrink = \"shrink\"\n    \"\"\"\n    Controls whether examples will be shrunk.\n    \"\"\"\n\n    explain = \"explain\"\n    \"\"\"\n    Controls whether Hypothesis attempts to explain test failures.\n\n    The explain phase has two parts, each of which is best-effort - if Hypothesis\n    can't find a useful explanation, we'll just print the minimal failing example.\n    \"\"\"\n\n    @classmethod\n    def _missing_(cls, value):\n        # deprecation pathway for integer values. Can be removed in Hypothesis 7.\n        if isinstance(value, int) and not isinstance(value, bool):\n            int_to_name = {\n                0: \"explicit\",\n                1: \"reuse\",\n                2: \"generate\",\n                3: \"target\",\n                4: \"shrink\",\n                5: \"explain\",\n            }\n            if value in int_to_name:\n                note_deprecation(\n                    f\"Passing Phase({value}) as an integer is deprecated. \"\n                    \"Hypothesis now treats Phase values as strings, not integers. \"\n                    f\"Use Phase.{int_to_name[value]} instead.\",\n                    since=\"2025-11-05\",\n                    has_codemod=False,\n                    stacklevel=2,\n                )\n                return cls(int_to_name[value])\n        return None\n\n    def __repr__(self) -> str:\n        return f\"Phase.{self.name}\"\n\n\nclass HealthCheckMeta(EnumMeta):\n    def __iter__(self):\n        deprecated = (HealthCheck.return_value, HealthCheck.not_a_test_method)\n        return iter(x for x in super().__iter__() if x not in deprecated)\n\n\n@unique\nclass HealthCheck(Enum, metaclass=HealthCheckMeta):\n    \"\"\"\n    A |HealthCheck| is proactively raised by Hypothesis when Hypothesis detects\n    that your test has performance problems, which may result in less rigorous\n    testing than you expect. For example, if your test takes a long time to generate\n    inputs, or filters away too many  inputs using |assume| or |filter|, Hypothesis\n    will raise a corresponding health check.\n\n    A health check is a proactive warning, not an error. We encourage suppressing\n    health checks where you have evaluated they will not pose a problem, or where\n    you have evaluated that fixing the underlying issue is not worthwhile.\n\n    With the exception of |HealthCheck.function_scoped_fixture| and\n    |HealthCheck.differing_executors|, all health checks warn about performance\n    problems, not correctness errors.\n\n    Disabling health checks\n    -----------------------\n\n    Health checks can be disabled by |settings.suppress_health_check|. To suppress\n    all health checks, you can pass ``suppress_health_check=list(HealthCheck)``.\n\n    .. seealso::\n\n        See also the :doc:`/how-to/suppress-healthchecks` how-to.\n\n    Correctness health checks\n    -------------------------\n\n    Some health checks report potential correctness errors, rather than performance\n    problems.\n\n    * |HealthCheck.function_scoped_fixture| indicates that a function-scoped\n      pytest fixture is used by an |@given| test. Many Hypothesis users expect\n      function-scoped fixtures to reset once per input, but they actually reset once\n      per test. We proactively raise |HealthCheck.function_scoped_fixture| to\n      ensure you have considered this case.\n    * |HealthCheck.differing_executors| indicates that the same |@given| test has\n      been executed multiple times with multiple distinct executors.\n\n    We recommend treating these particular health checks with more care, as\n    suppressing them may result in an unsound test.\n    \"\"\"\n\n    @classmethod\n    def _missing_(cls, value):\n        # deprecation pathway for integer values. Can be removed in Hypothesis 7.\n        if isinstance(value, int) and not isinstance(value, bool):\n            int_to_name = {\n                1: \"data_too_large\",\n                2: \"filter_too_much\",\n                3: \"too_slow\",\n                5: \"return_value\",\n                7: \"large_base_example\",\n                8: \"not_a_test_method\",\n                9: \"function_scoped_fixture\",\n                10: \"differing_executors\",\n                11: \"nested_given\",\n            }\n            if value in int_to_name:\n                note_deprecation(\n                    f\"Passing HealthCheck({value}) as an integer is deprecated. \"\n                    \"Hypothesis now treats HealthCheck values as strings, not integers. \"\n                    f\"Use HealthCheck.{int_to_name[value]} instead.\",\n                    since=\"2025-11-05\",\n                    has_codemod=False,\n                    stacklevel=2,\n                )\n                return cls(int_to_name[value])\n        return None\n\n    def __repr__(self) -> str:\n        return f\"{self.__class__.__name__}.{self.name}\"\n\n    @classmethod\n    def all(cls) -> list[\"HealthCheck\"]:\n        # Skipping of deprecated attributes is handled in HealthCheckMeta.__iter__\n        note_deprecation(\n            \"`HealthCheck.all()` is deprecated; use `list(HealthCheck)` instead.\",\n            since=\"2023-04-16\",\n            has_codemod=True,\n            stacklevel=1,\n        )\n        return list(HealthCheck)\n\n    data_too_large = \"data_too_large\"\n    \"\"\"Checks if too many examples are aborted for being too large.\n\n    This is measured by the number of random choices that Hypothesis makes\n    in order to generate something, not the size of the generated object.\n    For example, choosing a 100MB object from a predefined list would take\n    only a few bits, while generating 10KB of JSON from scratch might trigger\n    this health check.\n    \"\"\"\n\n    filter_too_much = \"filter_too_much\"\n    \"\"\"Check for when the test is filtering out too many examples, either\n    through use of |assume| or |.filter|, or occasionally for Hypothesis\n    internal reasons.\"\"\"\n\n    too_slow = \"too_slow\"\n    \"\"\"\n    Check for when input generation is very slow. Since Hypothesis generates 100\n    (by default) inputs per test execution, a slowdown in generating each input\n    can result in very slow tests overall.\n    \"\"\"\n\n    return_value = \"return_value\"\n    \"\"\"Deprecated; we always error if a test returns a non-None value.\"\"\"\n\n    large_base_example = \"large_base_example\"\n    \"\"\"\n    Checks if the smallest natural input to your test is very large. This makes\n    it difficult for Hypothesis to generate good inputs, especially when trying to\n    shrink failing inputs.\n    \"\"\"\n\n    not_a_test_method = \"not_a_test_method\"\n    \"\"\"Deprecated; we always error if |@given| is applied\n    to a method defined by :class:`python:unittest.TestCase` (i.e. not a test).\"\"\"\n\n    function_scoped_fixture = \"function_scoped_fixture\"\n    \"\"\"Checks if |@given| has been applied to a test\n    with a pytest function-scoped fixture. Function-scoped fixtures run once\n    for the whole function, not once per example, and this is usually not what\n    you want.\n\n    Because of this limitation, tests that need to set up or reset\n    state for every example need to do so manually within the test itself,\n    typically using an appropriate context manager.\n\n    Suppress this health check only in the rare case that you are using a\n    function-scoped fixture that does not need to be reset between individual\n    examples, but for some reason you cannot use a wider fixture scope\n    (e.g. session scope, module scope, class scope).\n\n    This check requires the :ref:`Hypothesis pytest plugin<pytest-plugin>`,\n    which is enabled by default when running Hypothesis inside pytest.\"\"\"\n\n    differing_executors = \"differing_executors\"\n    \"\"\"Checks if |@given| has been applied to a test\n    which is executed by different :ref:`executors<custom-function-execution>`.\n    If your test function is defined as a method on a class, that class will be\n    your executor, and subclasses executing an inherited test is a common way\n    for things to go wrong.\n\n    The correct fix is often to bring the executor instance under the control\n    of hypothesis by explicit parametrization over, or sampling from,\n    subclasses, or to refactor so that |@given| is\n    specified on leaf subclasses.\"\"\"\n\n    nested_given = \"nested_given\"\n    \"\"\"Checks if |@given| is used inside another\n    |@given|. This results in quadratic generation and\n    shrinking behavior, and can usually be expressed more cleanly by using\n    :func:`~hypothesis.strategies.data` to replace the inner\n    |@given|.\n\n    Nesting @given can be appropriate if you set appropriate limits for the\n    quadratic behavior and cannot easily reexpress the inner function with\n    :func:`~hypothesis.strategies.data`. To suppress this health check, set\n    ``suppress_health_check=[HealthCheck.nested_given]`` on the outer\n    |@given|. Setting it on the inner\n    |@given| has no effect. If you have more than one\n    level of nesting, add a suppression for this health check to every\n    |@given| except the innermost one.\n    \"\"\"\n\n\nclass duration(datetime.timedelta):\n    \"\"\"A timedelta specifically measured in milliseconds.\"\"\"\n\n    def __repr__(self) -> str:\n        ms = self.total_seconds() * 1000\n        return f\"timedelta(milliseconds={int(ms) if ms == int(ms) else ms!r})\"\n\n\n# see https://adamj.eu/tech/2020/03/09/detect-if-your-tests-are-running-on-ci\n# initially from https://github.com/tox-dev/tox/blob/e911788a/src/tox/util/ci.py\n_CI_VARS = {\n    \"CI\": None,  # various, including GitHub Actions, Travis CI, and AppVeyor\n    # see https://github.com/tox-dev/tox/issues/3442\n    \"__TOX_ENVIRONMENT_VARIABLE_ORIGINAL_CI\": None,\n    \"TF_BUILD\": \"true\",  # Azure Pipelines\n    \"bamboo.buildKey\": None,  # Bamboo\n    \"BUILDKITE\": \"true\",  # Buildkite\n    \"CIRCLECI\": \"true\",  # Circle CI\n    \"CIRRUS_CI\": \"true\",  # Cirrus CI\n    \"CODEBUILD_BUILD_ID\": None,  # CodeBuild\n    \"GITHUB_ACTIONS\": \"true\",  # GitHub Actions\n    \"GITLAB_CI\": None,  # GitLab CI\n    \"HEROKU_TEST_RUN_ID\": None,  # Heroku CI\n    \"TEAMCITY_VERSION\": None,  # TeamCity\n}\n\n\ndef is_in_ci() -> bool:\n    return any(\n        key in os.environ and (value is None or os.environ[key] == value)\n        for key, value in _CI_VARS.items()\n    )\n\n\ndefault_variable = DynamicVariable[Optional[\"settings\"]](None)\n\n\ndef _validate_choices(name: str, value: T, *, choices: Sequence[object]) -> T:\n    if value not in choices:\n        msg = f\"Invalid {name}, {value!r}. Valid choices: {choices!r}\"\n        raise InvalidArgument(msg)\n    return value\n\n\ndef _validate_enum_value(cls: Any, value: object, *, name: str) -> Any:\n    try:\n        return cls(value)\n    except ValueError:\n        raise InvalidArgument(\n            f\"{name}={value} is not a valid value. The options \"\n            f\"are: {', '.join(repr(m.name) for m in cls)}\"\n        ) from None\n\n\ndef _validate_max_examples(max_examples: int) -> int:\n    check_type(int, max_examples, name=\"max_examples\")\n    if max_examples < 1:\n        raise InvalidArgument(\n            f\"max_examples={max_examples!r} must be at least one. If you want \"\n            \"to disable generation entirely, use phases=[Phase.explicit] instead.\"\n        )\n    return max_examples\n\n\ndef _validate_database(\n    database: Optional[\"ExampleDatabase\"],\n) -> Optional[\"ExampleDatabase\"]:\n    from hypothesis.database import ExampleDatabase\n\n    if database is None or isinstance(database, ExampleDatabase):\n        return database\n    raise InvalidArgument(\n        \"Arguments to the database setting must be None or an instance of \"\n        \"ExampleDatabase. Use one of the database classes in \"\n        \"hypothesis.database\"\n    )\n\n\ndef _validate_phases(phases: Collection[Phase]) -> Sequence[Phase]:\n    phases = try_convert(tuple, phases, \"phases\")\n    phases = tuple(\n        _validate_enum_value(Phase, phase, name=\"phases\") for phase in phases\n    )\n    # sort by definition order\n    return tuple(phase for phase in list(Phase) if phase in phases)\n\n\ndef _validate_stateful_step_count(stateful_step_count: int) -> int:\n    check_type(int, stateful_step_count, name=\"stateful_step_count\")\n    if stateful_step_count < 1:\n        raise InvalidArgument(\n            f\"stateful_step_count={stateful_step_count!r} must be at least one.\"\n        )\n    return stateful_step_count\n\n\ndef _validate_suppress_health_check(suppressions: object) -> tuple[HealthCheck, ...]:\n    suppressions = try_convert(tuple, suppressions, \"suppress_health_check\")\n    for health_check in suppressions:\n        if health_check in (HealthCheck.return_value, HealthCheck.not_a_test_method):\n            note_deprecation(\n                f\"The {health_check.name} health check is deprecated, because this is always an error.\",\n                since=\"2023-03-15\",\n                has_codemod=False,\n                stacklevel=2,\n            )\n    return tuple(\n        _validate_enum_value(HealthCheck, health_check, name=\"suppress_health_check\")\n        for health_check in suppressions\n    )\n\n\ndef _validate_deadline(\n    deadline: int | float | datetime.timedelta | None,\n) -> duration | None:\n    if deadline is None:\n        return deadline\n    invalid_deadline_error = InvalidArgument(\n        f\"deadline={deadline!r} (type {type(deadline).__name__}) must be a timedelta object, \"\n        \"an integer or float number of milliseconds, or None to disable the \"\n        \"per-test-case deadline.\"\n    )\n    if isinstance(deadline, (int, float)):\n        if isinstance(deadline, bool):\n            raise invalid_deadline_error\n        try:\n            deadline = duration(milliseconds=deadline)\n        except OverflowError:\n            raise InvalidArgument(\n                f\"deadline={deadline!r} is invalid, because it is too large to represent \"\n                \"as a timedelta. Use deadline=None to disable deadlines.\"\n            ) from None\n    if isinstance(deadline, datetime.timedelta):\n        if deadline <= datetime.timedelta(0):\n            raise InvalidArgument(\n                f\"deadline={deadline!r} is invalid, because it is impossible to meet a \"\n                \"deadline <= 0. Use deadline=None to disable deadlines.\"\n            )\n        return duration(seconds=deadline.total_seconds())\n    raise invalid_deadline_error\n\n\ndef _validate_backend(backend: str) -> str:\n    if backend not in AVAILABLE_PROVIDERS:\n        if backend == \"crosshair\":  # pragma: no cover\n            install = '`pip install \"hypothesis[crosshair]\"` and try again.'\n            raise InvalidArgument(f\"backend={backend!r} is not available.  {install}\")\n        raise InvalidArgument(\n            f\"backend={backend!r} is not available - maybe you need to install a plugin?\"\n            f\"\\n    Installed backends: {sorted(AVAILABLE_PROVIDERS)!r}\"\n        )\n    return backend\n\n\nclass settingsMeta(type):\n    def __init__(cls, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n    @property\n    def default(cls) -> Optional[\"settings\"]:\n        v = default_variable.value\n        if v is not None:\n            return v\n        if getattr(settings, \"_current_profile\", None) is not None:\n            assert settings._current_profile is not None\n            settings.load_profile(settings._current_profile)\n            assert default_variable.value is not None\n        return default_variable.value\n\n    def __setattr__(cls, name: str, value: object) -> None:\n        if name == \"default\":\n            raise AttributeError(\n                \"Cannot assign to the property settings.default - \"\n                \"consider using settings.load_profile instead.\"\n            )\n        elif not name.startswith(\"_\"):\n            raise AttributeError(\n                f\"Cannot assign hypothesis.settings.{name}={value!r} - the settings \"\n                \"class is immutable.  You can change the global default \"\n                \"settings with settings.load_profile, or use @settings(...) \"\n                \"to decorate your test instead.\"\n            )\n        super().__setattr__(name, value)\n\n    def __repr__(cls):\n        return \"hypothesis.settings\"\n\n\nclass settings(metaclass=settingsMeta):\n    \"\"\"\n    A settings object controls the following aspects of test behavior:\n    |~settings.max_examples|, |~settings.derandomize|, |~settings.database|,\n    |~settings.verbosity|, |~settings.phases|, |~settings.stateful_step_count|,\n    |~settings.report_multiple_bugs|, |~settings.suppress_health_check|,\n    |~settings.deadline|, |~settings.print_blob|, and |~settings.backend|.\n\n    A settings object can be applied as a decorator to a test function, in which\n    case that test function will use those settings. A test may only have one\n    settings object applied to it. A settings object can also be passed to\n    |settings.register_profile| or as a parent to another |settings|.\n\n    Attribute inheritance\n    ---------------------\n\n    Settings objects are immutable once created. When a settings object is created,\n    it uses the value specified for each attribute. Any attribute which is\n    not specified will inherit from its value in the ``parent`` settings object.\n    If ``parent`` is not passed, any attributes which are not specified will inherit\n    from the current settings profile instead.\n\n    For instance, ``settings(max_examples=10)`` will have a ``max_examples`` of ``10``,\n    and the value of all other attributes will be equal to its value in the\n    current settings profile.\n\n    Changes made from activating a new settings profile with |settings.load_profile|\n    will be reflected in settings objects created after the profile was loaded,\n    but not in existing settings objects.\n\n    .. _builtin-profiles:\n\n    Built-in profiles\n    -----------------\n\n    While you can register additional profiles with |settings.register_profile|,\n    Hypothesis comes with two built-in profiles: ``default`` and ``ci``.\n\n    By default, the ``default`` profile is active. If the ``CI`` environment\n    variable is set to any value, the ``ci`` profile is active by default. Hypothesis\n    also automatically detects various vendor-specific CI environment variables.\n\n    The attributes of the currently active settings profile can be retrieved with\n    ``settings()`` (so ``settings().max_examples`` is the currently active default\n    for |settings.max_examples|).\n\n    The settings attributes for the built-in profiles are as follows:\n\n    .. code-block:: python\n\n        default = settings.register_profile(\n            \"default\",\n            max_examples=100,\n            derandomize=False,\n            database=not_set,  # see settings.database for default behavior\n            verbosity=Verbosity.normal,\n            phases=tuple(Phase),\n            stateful_step_count=50,\n            report_multiple_bugs=True,\n            suppress_health_check=(),\n            deadline=duration(milliseconds=200),\n            print_blob=False,\n            backend=\"hypothesis\",\n        )\n\n        ci = settings.register_profile(\n            \"ci\",\n            parent=default,\n            derandomize=True,\n            deadline=None,\n            database=None,\n            print_blob=True,\n            suppress_health_check=[HealthCheck.too_slow],\n        )\n\n    You can replace either of the built-in profiles with |settings.register_profile|:\n\n    .. code-block:: python\n\n        # run more examples in CI\n        settings.register_profile(\n            \"ci\",\n            settings.get_profile(\"ci\"),\n            max_examples=1000,\n        )\n    \"\"\"\n\n    _profiles: ClassVar[dict[str, \"settings\"]] = {}\n    _current_profile: ClassVar[str | None] = None\n\n    def __init__(\n        self,\n        parent: Optional[\"settings\"] = None,\n        *,\n        # This looks pretty strange, but there's good reason: we want Mypy to detect\n        # bad calls downstream, but not to freak out about the `= not_set` part even\n        # though it's not semantically valid to pass that as an argument value.\n        # The intended use is \"like **kwargs, but more tractable for tooling\".\n        max_examples: int = not_set,  # type: ignore\n        derandomize: bool = not_set,  # type: ignore\n        database: Optional[\"ExampleDatabase\"] = not_set,  # type: ignore\n        verbosity: \"Verbosity\" = not_set,  # type: ignore\n        phases: Collection[\"Phase\"] = not_set,  # type: ignore\n        stateful_step_count: int = not_set,  # type: ignore\n        report_multiple_bugs: bool = not_set,  # type: ignore\n        suppress_health_check: Collection[\"HealthCheck\"] = not_set,  # type: ignore\n        deadline: int | float | datetime.timedelta | None = not_set,  # type: ignore\n        print_blob: bool = not_set,  # type: ignore\n        backend: str = not_set,  # type: ignore\n    ) -> None:\n        self._in_definition = True\n\n        if parent is not None:\n            check_type(settings, parent, \"parent\")\n        if derandomize not in (not_set, False):\n            if database not in (not_set, None):  # type: ignore\n                raise InvalidArgument(\n                    \"derandomize=True implies database=None, so passing \"\n                    f\"{database=} too is invalid.\"\n                )\n            database = None\n\n        # fallback is None if we're creating the default settings object, and\n        # the parent (or default settings object) otherwise\n        self._fallback = parent or settings.default\n        self._max_examples = (\n            self._fallback.max_examples  # type: ignore\n            if max_examples is not_set  # type: ignore\n            else _validate_max_examples(max_examples)\n        )\n        self._derandomize = (\n            self._fallback.derandomize  # type: ignore\n            if derandomize is not_set  # type: ignore\n            else _validate_choices(\"derandomize\", derandomize, choices=[True, False])\n        )\n        if database is not not_set:  # type: ignore\n            database = _validate_database(database)\n        self._database = database\n        self._cached_database = None\n        self._verbosity = (\n            self._fallback.verbosity  # type: ignore\n            if verbosity is not_set  # type: ignore\n            else _validate_enum_value(Verbosity, verbosity, name=\"verbosity\")\n        )\n        self._phases = (\n            self._fallback.phases  # type: ignore\n            if phases is not_set  # type: ignore\n            else _validate_phases(phases)\n        )\n        self._stateful_step_count = (\n            self._fallback.stateful_step_count  # type: ignore\n            if stateful_step_count is not_set  # type: ignore\n            else _validate_stateful_step_count(stateful_step_count)\n        )\n        self._report_multiple_bugs = (\n            self._fallback.report_multiple_bugs  # type: ignore\n            if report_multiple_bugs is not_set  # type: ignore\n            else _validate_choices(\n                \"report_multiple_bugs\", report_multiple_bugs, choices=[True, False]\n            )\n        )\n        self._suppress_health_check = (\n            self._fallback.suppress_health_check  # type: ignore\n            if suppress_health_check is not_set  # type: ignore\n            else _validate_suppress_health_check(suppress_health_check)\n        )\n        self._deadline = (\n            self._fallback.deadline  # type: ignore\n            if deadline is not_set  # type: ignore\n            else _validate_deadline(deadline)\n        )\n        self._print_blob = (\n            self._fallback.print_blob  # type: ignore\n            if print_blob is not_set  # type: ignore\n            else _validate_choices(\"print_blob\", print_blob, choices=[True, False])\n        )\n        self._backend = (\n            self._fallback.backend  # type: ignore\n            if backend is not_set  # type: ignore\n            else _validate_backend(backend)\n        )\n\n        self._in_definition = False\n\n    @property\n    def max_examples(self):\n        \"\"\"\n        Once this many satisfying examples have been considered without finding any\n        counter-example, Hypothesis will stop looking.\n\n        Note that we might call your test function fewer times if we find a bug early\n        or can tell that we've exhausted the search space; or more if we discard some\n        examples due to use of .filter(), assume(), or a few other things that can\n        prevent the test case from completing successfully.\n\n        The default value is chosen to suit a workflow where the test will be part of\n        a suite that is regularly executed locally or on a CI server, balancing total\n        running time against the chance of missing a bug.\n\n        If you are writing one-off tests, running tens of thousands of examples is\n        quite reasonable as Hypothesis may miss uncommon bugs with default settings.\n        For very complex code, we have observed Hypothesis finding novel bugs after\n        *several million* examples while testing :pypi:`SymPy <sympy>`.\n        If you are running more than 100k examples for a test, consider using our\n        :ref:`integration for coverage-guided fuzzing <fuzz_one_input>` - it really\n        shines when given minutes or hours to run.\n\n        The default max examples is ``100``.\n        \"\"\"\n        return self._max_examples\n\n    @property\n    def derandomize(self):\n        \"\"\"\n        If True, seed Hypothesis' random number generator using a hash of the test\n        function, so that every run will test the same set of examples until you\n        update Hypothesis, Python, or the test function.\n\n        This allows you to `check for regressions and look for bugs\n        <https://blog.nelhage.com/post/two-kinds-of-testing/>`__ using separate\n        settings profiles - for example running\n        quick deterministic tests on every commit, and a longer non-deterministic\n        nightly testing run.\n\n        The default is ``False``. If running on CI, the default is ``True`` instead.\n        \"\"\"\n        return self._derandomize\n\n    @property\n    def database(self):\n        \"\"\"\n        An instance of |ExampleDatabase| that will be used to save examples to\n        and load previous examples from.\n\n        If not set, a |DirectoryBasedExampleDatabase| is created in the current\n        working directory under ``.hypothesis/examples``. If this location is\n        unusable, e.g. due to the lack of read or write permissions, Hypothesis\n        will emit a warning and fall back to an |InMemoryExampleDatabase|.\n\n        If ``None``, no storage will be used.\n\n        See the :ref:`database documentation <database>` for a list of database\n        classes, and how to define custom database classes.\n        \"\"\"\n        from hypothesis.database import _db_for_path\n\n        # settings.database has two conflicting requirements:\n        # * The default settings should respect changes to set_hypothesis_home_dir\n        #   in-between accesses\n        # * `s.database is s.database` should be true, except for the default settings\n        #\n        # We therefore cache s.database for everything except the default settings,\n        # which always recomputes dynamically.\n        if self._fallback is None:\n            # if self._fallback is None, we are the default settings, at which point\n            # we should recompute the database dynamically\n            assert self._database is not_set\n            return _db_for_path(not_set)\n\n        # otherwise, we cache the database\n        if self._cached_database is None:\n            self._cached_database = (\n                self._fallback.database if self._database is not_set else self._database\n            )\n        return self._cached_database\n\n    @property\n    def verbosity(self):\n        \"\"\"\n        Control the verbosity level of Hypothesis messages.\n\n        To see what's going on while Hypothesis runs your tests, you can turn\n        up the verbosity setting.\n\n        .. code-block:: pycon\n\n            >>> from hypothesis import settings, Verbosity\n            >>> from hypothesis.strategies import lists, integers\n            >>> @given(lists(integers()))\n            ... @settings(verbosity=Verbosity.verbose)\n            ... def f(x):\n            ...     assert not any(x)\n            ... f()\n            Trying example: []\n            Falsifying example: [-1198601713, -67, 116, -29578]\n            Shrunk example to [-1198601713]\n            Shrunk example to [-128]\n            Shrunk example to [32]\n            Shrunk example to [1]\n            [1]\n\n        The four levels are |Verbosity.quiet|, |Verbosity.normal|,\n        |Verbosity.verbose|, and |Verbosity.debug|. |Verbosity.normal| is the\n        default. For |Verbosity.quiet|, Hypothesis will not print anything out,\n        not even the final falsifying example. |Verbosity.debug| is basically\n        |Verbosity.verbose| but a bit more so. You probably don't want it.\n\n        Verbosity can be passed either as a |Verbosity| enum value, or as the\n        corresponding string value, or as the corresponding integer value. For\n        example:\n\n        .. code-block:: python\n\n            # these three are equivalent\n            settings(verbosity=Verbosity.verbose)\n            settings(verbosity=\"verbose\")\n\n        If you are using :pypi:`pytest`, you may also need to :doc:`disable\n        output capturing for passing tests <pytest:how-to/capture-stdout-stderr>`\n        to see verbose output as tests run.\n        \"\"\"\n        return self._verbosity\n\n    @property\n    def phases(self):\n        \"\"\"\n        Control which phases should be run.\n\n        Hypothesis divides tests into logically distinct phases.\n\n        - |Phase.explicit|: Running explicit examples from |@example|.\n        - |Phase.reuse|: Running examples from the database which previously failed.\n        - |Phase.generate|: Generating new random examples.\n        - |Phase.target|: Mutating examples for :ref:`targeted property-based\n          testing <targeted>`. Requires |Phase.generate|.\n        - |Phase.shrink|: Shrinking failing examples.\n        - |Phase.explain|: Attempting to explain why a failure occurred.\n          Requires |Phase.shrink|.\n\n        The phases argument accepts a collection with any subset of these. E.g.\n        ``settings(phases=[Phase.generate, Phase.shrink])`` will generate new examples\n        and shrink them, but will not run explicit examples or reuse previous failures,\n        while ``settings(phases=[Phase.explicit])`` will only run explicit examples\n        from |@example|.\n\n        Phases can be passed either as a |Phase| enum value, or as the corresponding\n        string value. For example:\n\n        .. code-block:: python\n\n            # these two are equivalent\n            settings(phases=[Phase.explicit])\n            settings(phases=[\"explicit\"])\n\n        Following the first failure, Hypothesis will (usually, depending on\n        which |Phase| is enabled) track which lines of code are always run on\n        failing but never on passing inputs. On 3.12+, this uses\n        :mod:`sys.monitoring`, while 3.11 and earlier uses :func:`python:sys.settrace`.\n        For python 3.11 and earlier, we therefore automatically disable the explain\n        phase on PyPy, or if you are using :pypi:`coverage` or a debugger. If\n        there are no clearly suspicious lines of code, :pep:`we refuse the\n        temptation to guess <20>`.\n\n        After shrinking to a minimal failing example, Hypothesis will try to find\n        parts of the example -- e.g. separate args to |@given|\n        -- which can vary freely without changing the result\n        of that minimal failing example. If the automated experiments run without\n        finding a passing variation, we leave a comment in the final report:\n\n        .. code-block:: python\n\n            test_x_divided_by_y(\n                x=0,  # or any other generated value\n                y=0,\n            )\n\n        Just remember that the *lack* of an explanation sometimes just means that\n        Hypothesis couldn't efficiently find one, not that no explanation (or\n        simpler failing example) exists.\n        \"\"\"\n\n        return self._phases\n\n    @property\n    def stateful_step_count(self):\n        \"\"\"\n        The maximum number of times to call an additional |@rule| method in\n        :ref:`stateful testing <stateful>` before we give up on finding a bug.\n\n        Note that this setting is effectively multiplicative with max_examples,\n        as each example will run for a maximum of ``stateful_step_count`` steps.\n\n        The default stateful step count is ``50``.\n        \"\"\"\n        return self._stateful_step_count\n\n    @property\n    def report_multiple_bugs(self):\n        \"\"\"\n        Because Hypothesis runs the test many times, it can sometimes find multiple\n        bugs in a single run.  Reporting all of them at once is usually very useful,\n        but replacing the exceptions can occasionally clash with debuggers.\n        If disabled, only the exception with the smallest minimal example is raised.\n\n        The default value is ``True``.\n        \"\"\"\n        return self._report_multiple_bugs\n\n    @property\n    def suppress_health_check(self):\n        \"\"\"\n        Suppress the given |HealthCheck| exceptions. Those health checks will not\n        be raised by Hypothesis. To suppress all health checks, you can pass\n        ``suppress_health_check=list(HealthCheck)``.\n\n        Health checks can be passed either as a |HealthCheck| enum value, or as\n        the corresponding string value. For example:\n\n        .. code-block:: python\n\n            # these two are equivalent\n            settings(suppress_health_check=[HealthCheck.filter_too_much])\n            settings(suppress_health_check=[\"filter_too_much\"])\n\n        Health checks are proactive warnings, not correctness errors, so we\n        encourage suppressing health checks where you have evaluated they will\n        not pose a problem, or where you have evaluated that fixing the underlying\n        issue is not worthwhile.\n\n        .. seealso::\n\n            See also the :doc:`/how-to/suppress-healthchecks` how-to.\n        \"\"\"\n        return self._suppress_health_check\n\n    @property\n    def deadline(self):\n        \"\"\"\n        The maximum allowed duration of an individual test case, in milliseconds.\n        You can pass an integer, float, or timedelta. If ``None``, the deadline\n        is disabled entirely.\n\n        We treat the deadline as a soft limit in some cases, where that would\n        avoid flakiness due to timing variability.\n\n        The default deadline is 200 milliseconds. If running on CI, the default is\n        ``None`` instead.\n        \"\"\"\n        return self._deadline\n\n    @property\n    def print_blob(self):\n        \"\"\"\n        If set to ``True``, Hypothesis will print code for failing examples that\n        can be used with |@reproduce_failure| to reproduce the failing example.\n\n        The default value is ``False``. If running on CI, the default is ``True`` instead.\n        \"\"\"\n        return self._print_blob\n\n    @property\n    def backend(self):\n        \"\"\"\n        .. warning::\n\n            EXPERIMENTAL AND UNSTABLE - see :ref:`alternative-backends`.\n\n        The importable name of a backend which Hypothesis should use to generate\n        primitive types. We support heuristic-random, solver-based, and fuzzing-based\n        backends.\n        \"\"\"\n        return self._backend\n\n    def __call__(self, test: T) -> T:\n        \"\"\"Make the settings object (self) an attribute of the test.\n\n        The settings are later discovered by looking them up on the test itself.\n        \"\"\"\n        # Aliasing as Any avoids mypy errors (attr-defined) when accessing and\n        # setting custom attributes on the decorated function or class.\n        _test: Any = test\n\n        # Using the alias here avoids a mypy error (return-value) later when\n        # ``test`` is returned, because this check results in type refinement.\n        if not callable(_test):\n            raise InvalidArgument(\n                \"settings objects can be called as a decorator with @given, \"\n                f\"but decorated {test=} is not callable.\"\n            )\n        if inspect.isclass(test):\n            from hypothesis.stateful import RuleBasedStateMachine\n\n            if issubclass(_test, RuleBasedStateMachine):\n                attr_name = \"_hypothesis_internal_settings_applied\"\n                if getattr(test, attr_name, False):\n                    raise InvalidArgument(\n                        \"Applying the @settings decorator twice would \"\n                        \"overwrite the first version; merge their arguments \"\n                        \"instead.\"\n                    )\n                setattr(test, attr_name, True)\n                _test.TestCase.settings = self\n                return test\n            else:\n                raise InvalidArgument(\n                    \"@settings(...) can only be used as a decorator on \"\n                    \"functions, or on subclasses of RuleBasedStateMachine.\"\n                )\n        if hasattr(_test, \"_hypothesis_internal_settings_applied\"):\n            # Can't use _hypothesis_internal_use_settings as an indicator that\n            # @settings was applied, because @given also assigns that attribute.\n            descr = get_pretty_function_description(test)\n            raise InvalidArgument(\n                f\"{descr} has already been decorated with a settings object.\\n\"\n                f\"    Previous:  {_test._hypothesis_internal_use_settings!r}\\n\"\n                f\"    This:  {self!r}\"\n            )\n\n        _test._hypothesis_internal_use_settings = self\n        _test._hypothesis_internal_settings_applied = True\n        return test\n\n    def __setattr__(self, name: str, value: object) -> None:\n        if not name.startswith(\"_\") and not self._in_definition:\n            raise AttributeError(\"settings objects are immutable\")\n        return super().__setattr__(name, value)\n\n    def __repr__(self) -> str:\n        bits = sorted(\n            f\"{name}={getattr(self, name)!r}\"\n            for name in all_settings\n            if (name != \"backend\" or len(AVAILABLE_PROVIDERS) > 1)  # experimental\n        )\n        return \"settings({})\".format(\", \".join(bits))\n\n    def show_changed(self) -> str:\n        bits = []\n        for name in all_settings:\n            value = getattr(self, name)\n            if value != getattr(default, name):\n                bits.append(f\"{name}={value!r}\")\n        return \", \".join(sorted(bits, key=len))\n\n    @staticmethod\n    def register_profile(\n        name: str,\n        parent: Optional[\"settings\"] = None,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"\n        Register a settings object as a settings profile, under the name ``name``.\n        The ``parent`` and ``kwargs`` arguments to this method are as for\n        |settings|.\n\n        If a settings profile already exists under ``name``, it will be overwritten.\n        Registering a profile with the same name as the currently active profile\n        will cause those changes to take effect in the active profile immediately,\n        and do not require reloading the profile.\n\n        Registered settings profiles can be retrieved later by name with\n        |settings.get_profile|.\n        \"\"\"\n        check_type(str, name, \"name\")\n\n        if (\n            default_variable.value\n            and settings._current_profile\n            and default_variable.value != settings._profiles[settings._current_profile]\n        ):\n            note_deprecation(\n                \"Cannot register a settings profile when the current settings differ \"\n                \"from the current profile (usually due to an @settings decorator). \"\n                \"Register profiles at module level instead.\",\n                since=\"2025-11-15\",\n                has_codemod=False,\n            )\n\n        # if we just pass the parent and no kwargs, like\n        #   settings.register_profile(settings(max_examples=10))\n        # then optimize out the pointless intermediate settings object which\n        # would just forward everything to the parent.\n        settings._profiles[name] = (\n            parent\n            if parent is not None and not kwargs\n            else settings(parent=parent, **kwargs)\n        )\n        if settings._current_profile == name:\n            settings.load_profile(name)\n\n    @staticmethod\n    def get_profile(name: str) -> \"settings\":\n        \"\"\"\n        Returns the settings profile registered under ``name``. If no settings\n        profile is registered under ``name``, raises |InvalidArgument|.\n        \"\"\"\n        check_type(str, name, \"name\")\n        try:\n            return settings._profiles[name]\n        except KeyError:\n            raise InvalidArgument(f\"Profile {name!r} is not registered\") from None\n\n    @staticmethod\n    def load_profile(name: str) -> None:\n        \"\"\"\n        Makes the settings profile registered under ``name`` the active profile.\n\n        If no settings profile is registered under ``name``, raises |InvalidArgument|.\n        \"\"\"\n        check_type(str, name, \"name\")\n        settings._current_profile = name\n        default_variable.value = settings.get_profile(name)\n\n    @staticmethod\n    def get_current_profile_name() -> str:\n        \"\"\"\n        The name of the current settings profile. For example:\n\n        .. code-block:: python\n\n            >>> settings.load_profile(\"myprofile\")\n            >>> settings.get_current_profile_name()\n            'myprofile'\n        \"\"\"\n        assert settings._current_profile is not None\n        return settings._current_profile\n\n\n@contextlib.contextmanager\ndef local_settings(s: settings) -> Generator[settings, None, None]:\n    with default_variable.with_value(s):\n        yield s\n\n\ndefault = settings(\n    max_examples=100,\n    derandomize=False,\n    database=not_set,  # type: ignore\n    verbosity=Verbosity.normal,\n    phases=tuple(Phase),\n    stateful_step_count=50,\n    report_multiple_bugs=True,\n    suppress_health_check=(),\n    deadline=duration(milliseconds=200),\n    print_blob=False,\n    backend=\"hypothesis\",\n)\nsettings.register_profile(\"default\", default)\nsettings.load_profile(\"default\")\n\nassert settings.default is not None\n\nCI = settings(\n    derandomize=True,\n    deadline=None,\n    database=None,\n    print_blob=True,\n    suppress_health_check=[HealthCheck.too_slow],\n)\n\nsettings.register_profile(\"ci\", CI)\n\n\nif is_in_ci():  # pragma: no cover # covered in ci, but not locally\n    settings.load_profile(\"ci\")\n\nassert settings.default is not None\n\n\n# Check that the kwonly args to settings.__init__ is the same as the set of\n# defined settings - in case we've added or remove something from one but\n# not the other.\nassert set(all_settings) == {\n    p.name\n    for p in inspect.signature(settings.__init__).parameters.values()\n    if p.kind == inspect.Parameter.KEYWORD_ONLY\n}\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/configuration.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport sys\nimport warnings\nfrom pathlib import Path\n\nimport _hypothesis_globals\n\nfrom hypothesis.errors import HypothesisSideeffectWarning\n\n__hypothesis_home_directory_default = Path.cwd() / \".hypothesis\"\n__hypothesis_home_directory = None\n\n\ndef set_hypothesis_home_dir(directory: str | Path | None) -> None:\n    global __hypothesis_home_directory\n    __hypothesis_home_directory = None if directory is None else Path(directory)\n\n\ndef storage_directory(*names: str, intent_to_write: bool = True) -> Path:\n    if intent_to_write:\n        check_sideeffect_during_initialization(\n            \"accessing storage for {}\", \"/\".join(names)\n        )\n\n    global __hypothesis_home_directory\n    if not __hypothesis_home_directory:\n        if where := os.getenv(\"HYPOTHESIS_STORAGE_DIRECTORY\"):\n            __hypothesis_home_directory = Path(where)\n    if not __hypothesis_home_directory:\n        __hypothesis_home_directory = __hypothesis_home_directory_default\n    return __hypothesis_home_directory.joinpath(*names)\n\n\n_first_postinit_what = None\n\n\ndef check_sideeffect_during_initialization(\n    what: str, *fmt_args: object, is_restart: bool = False\n) -> None:\n    \"\"\"Called from locations that should not be executed during initialization, for example\n    touching disk or materializing lazy/deferred strategies from plugins. If initialization\n    is in progress, a warning is emitted.\n\n    Note that computing the repr can take nontrivial time or memory, so we avoid doing so\n    unless (and until) we're actually emitting the warning.\n    \"\"\"\n    global _first_postinit_what\n    # This is not a particularly hot path, but neither is it doing productive work, so we want to\n    # minimize the cost by returning immediately. The drawback is that we require\n    # notice_initialization_restarted() to be called if in_initialization changes away from zero.\n    if _first_postinit_what is not None:\n        return\n    elif _hypothesis_globals.in_initialization > 0:\n        msg = what.format(*fmt_args)\n        if is_restart:\n            when = \"between importing hypothesis and loading the hypothesis plugin\"\n        elif \"_hypothesis_pytestplugin\" in sys.modules or os.getenv(\n            \"HYPOTHESIS_EXTEND_INITIALIZATION\"\n        ):\n            when = \"during pytest plugin or conftest initialization\"\n        else:  # pragma: no cover\n            # This can be triggered by Hypothesis plugins, but is really annoying\n            # to test automatically - drop st.text().example() in hypothesis.run()\n            # to manually confirm that we get the warning.\n            when = \"at import time\"\n        # Note: -Werror is insufficient under pytest, as doesn't take effect until\n        # test session start.\n        text = (\n            f\"Slow code in plugin: avoid {msg} {when}!  Set PYTHONWARNINGS=error \"\n            \"to get a traceback and show which plugin is responsible.\"\n        )\n        if is_restart:\n            text += \" Additionally, set HYPOTHESIS_EXTEND_INITIALIZATION=1 to pinpoint the exact location.\"\n        warnings.warn(\n            text,\n            HypothesisSideeffectWarning,\n            stacklevel=3,\n        )\n    else:\n        _first_postinit_what = (what, fmt_args)\n\n\ndef notice_initialization_restarted(*, warn: bool = True) -> None:\n    \"\"\"Reset _first_postinit_what, so that we don't think we're in post-init. Additionally, if it\n    was set that means that there has been a sideeffect that we haven't warned about, so do that\n    now (the warning text will be correct, and we also hint that the stacktrace can be improved).\n    \"\"\"\n    global _first_postinit_what\n    if _first_postinit_what is not None:\n        what, *fmt_args = _first_postinit_what\n        _first_postinit_what = None\n        if warn:\n            check_sideeffect_during_initialization(\n                what,\n                *fmt_args,\n                is_restart=True,\n            )\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/control.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport inspect\nimport math\nimport random\nfrom collections import defaultdict\nfrom collections.abc import Callable, Generator, Sequence\nfrom contextlib import contextmanager\nfrom typing import Any, Literal, NoReturn, Optional, overload\nfrom weakref import WeakKeyDictionary\n\nfrom hypothesis import Verbosity, settings\nfrom hypothesis.errors import InvalidArgument, UnsatisfiedAssumption\nfrom hypothesis.internal.compat import BaseExceptionGroup\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.observability import observability_enabled\nfrom hypothesis.internal.reflection import get_pretty_function_description\nfrom hypothesis.internal.validation import check_type\nfrom hypothesis.reporting import report, verbose_report\nfrom hypothesis.utils.deprecation import note_deprecation\nfrom hypothesis.utils.dynamicvariables import DynamicVariable\nfrom hypothesis.vendor.pretty import ArgLabelsT, IDKey, PrettyPrintFunction, pretty\n\n\ndef _calling_function_location(what: str, frame: Any) -> str:\n    where = frame.f_back\n    return f\"{what}() in {where.f_code.co_name} (line {where.f_lineno})\"\n\n\ndef reject() -> NoReturn:\n    if _current_build_context.value is None:\n        note_deprecation(\n            \"Using `reject` outside a property-based test is deprecated\",\n            since=\"2023-09-25\",\n            has_codemod=False,\n        )\n    where = _calling_function_location(\"reject\", inspect.currentframe())\n    if currently_in_test_context():\n        counts = current_build_context().data._observability_predicates[where]\n        counts.update_count(condition=False)\n    raise UnsatisfiedAssumption(where)\n\n\n@overload\ndef assume(condition: Literal[False] | None) -> NoReturn: ...\n@overload\ndef assume(condition: object) -> Literal[True]: ...\n\n\ndef assume(condition: object) -> Literal[True]:\n    \"\"\"Calling ``assume`` is like an :ref:`assert <python:assert>` that marks\n    the example as bad, rather than failing the test.\n\n    This allows you to specify properties that you *assume* will be\n    true, and let Hypothesis try to avoid similar examples in future.\n    \"\"\"\n    if _current_build_context.value is None:\n        note_deprecation(\n            \"Using `assume` outside a property-based test is deprecated\",\n            since=\"2023-09-25\",\n            has_codemod=False,\n        )\n    if observability_enabled() or not condition:\n        where = _calling_function_location(\"assume\", inspect.currentframe())\n        if observability_enabled() and currently_in_test_context():\n            counts = current_build_context().data._observability_predicates[where]\n            counts.update_count(condition=bool(condition))\n        if not condition:\n            raise UnsatisfiedAssumption(f\"failed to satisfy {where}\")\n    return True\n\n\n_current_build_context = DynamicVariable[Optional[\"BuildContext\"]](None)\n\n\ndef currently_in_test_context() -> bool:\n    \"\"\"Return ``True`` if the calling code is currently running inside an\n    |@given| or :ref:`stateful <stateful>` test, and ``False`` otherwise.\n\n    This is useful for third-party integrations and assertion helpers which\n    may be called from either traditional or property-based tests, and can only\n    use e.g. |assume| or |target| in the latter case.\n    \"\"\"\n    return _current_build_context.value is not None\n\n\ndef current_build_context() -> \"BuildContext\":\n    context = _current_build_context.value\n    if context is None:\n        raise InvalidArgument(\"No build context registered\")\n    return context\n\n\n@contextmanager\ndef deprecate_random_in_strategy(fmt, *args):\n    from hypothesis.internal import entropy\n\n    state_before = random.getstate()\n    yield\n    state_after = random.getstate()\n    if (\n        # there is a threading race condition here with deterministic_PRNG. Say\n        # we have two threads 1 and 2. We start in global random state A, and\n        # deterministic_PRNG sets to global random state B (which is constant across\n        # threads since we seed to 0 unconditionally). Then we might have state\n        # transitions:\n        #\n        #  [1]        [2]\n        # A -> B                           deterministic_PRNG().__enter__\n        #            B ->B                 deterministic_PRNG().__enter__\n        #            state_before = B      deprecate_random_in_strategy.__enter__\n        # B -> A                           deterministic_PRNG().__exit__\n        #            state_after  = A      deprecate_random_in_strategy.__exit__\n        #\n        # where state_before != state_after because a different thread has reset\n        # the global random state.\n        #\n        # To fix this, we track the known random states set by deterministic_PRNG,\n        # and will not note a deprecation if it matches one of those.\n        state_after != state_before\n        and hash(state_after) not in entropy._known_random_state_hashes\n    ):\n        note_deprecation(\n            \"Do not use the `random` module inside strategies; instead \"\n            \"consider `st.randoms()`, `st.sampled_from()`, etc.  \" + fmt.format(*args),\n            since=\"2024-02-05\",\n            has_codemod=False,\n            stacklevel=1,\n        )\n\n\nclass BuildContext:\n    def __init__(\n        self,\n        data: ConjectureData,\n        *,\n        is_final: bool = False,\n        wrapped_test: Callable,\n    ) -> None:\n        self.data = data\n        self.tasks: list[Callable[[], Any]] = []\n        self.is_final = is_final\n        self.wrapped_test = wrapped_test\n\n        # Use defaultdict(list) here to handle the possibility of having multiple\n        # functions registered for the same object (due to caching, small ints, etc).\n        # The printer will discard duplicates which return different representations.\n        self.known_object_printers: dict[IDKey, list[PrettyPrintFunction]] = (\n            defaultdict(list)\n        )\n\n        # Track nested strategy calls for explain-phase label paths\n        self._label_path: list[str] = []\n\n    @contextmanager\n    def track_arg_label(self, label: str) -> Generator[ArgLabelsT, None, None]:\n        start = len(self.data.nodes)\n        self._label_path.append(label)\n        arg_labels: ArgLabelsT = {}\n        try:\n            yield arg_labels\n        finally:\n            self._label_path.pop()\n\n            # This high up the stack, we can't see or really do much with\n            # Span / SpanRecord - not least because they're only materialized\n            # after the test case is completed.\n            #\n            # Instead, we'll stash the (start_idx, end_idx) pair on our data object\n            # for the ConjectureRunner engine to deal with, and mutate the arg_labels\n            # dict so that the pretty-printer knows where to place the\n            # which-parts-matter comments later.\n            end = len(self.data.nodes)\n            assert start <= end\n            if start != end:\n                arg_labels[label] = (start, end)\n                self.data.arg_slices.add((start, end))\n\n    def record_call(\n        self,\n        obj: object,\n        func: object,\n        *,\n        args: Sequence[object],\n        kwargs: dict[str, object],\n        arg_labels: ArgLabelsT | None = None,\n    ) -> None:\n        self.known_object_printers[IDKey(obj)].append(\n            lambda obj, p, cycle, *, _func=func, _arg_labels=arg_labels: p.maybe_repr_known_object_as_call(  # type: ignore\n                obj,\n                cycle,\n                get_pretty_function_description(_func),\n                args,\n                kwargs,\n                arg_labels=_arg_labels,\n            )\n        )\n\n    def prep_args_kwargs_from_strategies(\n        self,\n        kwarg_strategies: dict[str, Any],\n    ) -> tuple[dict[str, Any], ArgLabelsT]:\n        arg_labels: ArgLabelsT = {}\n        kwargs: dict[str, Any] = {}\n\n        for k, s in kwarg_strategies.items():\n            with (\n                self.track_arg_label(k) as arg_label,\n                deprecate_random_in_strategy(\"from {}={!r}\", k, s),\n            ):\n                kwargs[k] = self.data.draw(s, observe_as=f\"generate:{k}\")\n            arg_labels |= arg_label\n\n        return kwargs, arg_labels\n\n    def __enter__(self):\n        self.assign_variable = _current_build_context.with_value(self)\n        self.assign_variable.__enter__()\n        return self\n\n    def __exit__(self, exc_type, exc_value, tb):\n        self.assign_variable.__exit__(exc_type, exc_value, tb)\n        errors = []\n        for task in self.tasks:\n            try:\n                task()\n            except BaseException as err:\n                errors.append(err)\n        if errors:\n            if len(errors) == 1:\n                raise errors[0] from exc_value\n            raise BaseExceptionGroup(\"Cleanup failed\", errors) from exc_value\n\n\ndef cleanup(teardown):\n    \"\"\"Register a function to be called when the current test has finished\n    executing. Any exceptions thrown in teardown will be printed but not\n    rethrown.\n\n    Inside a test this isn't very interesting, because you can just use\n    a finally block, but note that you can use this inside map, flatmap,\n    etc. in order to e.g. insist that a value is closed at the end.\n    \"\"\"\n    context = _current_build_context.value\n    if context is None:\n        raise InvalidArgument(\"Cannot register cleanup outside of build context\")\n    context.tasks.append(teardown)\n\n\ndef should_note():\n    context = _current_build_context.value\n    if context is None:\n        raise InvalidArgument(\"Cannot make notes outside of a test\")\n    return context.is_final or settings.default.verbosity >= Verbosity.verbose\n\n\ndef note(value: object) -> None:\n    \"\"\"Report this value for the minimal failing example.\"\"\"\n    if should_note():\n        if not isinstance(value, str):\n            value = pretty(value)\n        report(value)\n\n\ndef event(value: str, payload: str | int | float = \"\") -> None:\n    \"\"\"Record an event that occurred during this test. Statistics on the number of test\n    runs with each event will be reported at the end if you run Hypothesis in\n    statistics reporting mode.\n\n    Event values should be strings or convertible to them.  If an optional\n    payload is given, it will be included in the string for :ref:`statistics`.\n    \"\"\"\n    context = _current_build_context.value\n    if context is None:\n        raise InvalidArgument(\"Cannot record events outside of a test\")\n\n    avoid_realization = context.data.provider.avoid_realization\n    payload = _event_to_string(\n        payload, allowed_types=(str, int, float), avoid_realization=avoid_realization\n    )\n    value = _event_to_string(value, avoid_realization=avoid_realization)\n    context.data.events[value] = payload\n\n\n_events_to_strings: WeakKeyDictionary = WeakKeyDictionary()\n\n\ndef _event_to_string(event, *, allowed_types=str, avoid_realization):\n    if isinstance(event, allowed_types):\n        return event\n\n    # _events_to_strings is a cache which persists across iterations, causing\n    # problems for symbolic backends. see\n    # https://github.com/pschanely/hypothesis-crosshair/issues/41\n    if avoid_realization:\n        return str(event)\n\n    try:\n        return _events_to_strings[event]\n    except (KeyError, TypeError):\n        pass\n\n    result = str(event)\n    try:\n        _events_to_strings[event] = result\n    except TypeError:\n        pass\n    return result\n\n\ndef target(observation: int | float, *, label: str = \"\") -> int | float:\n    \"\"\"Calling this function with an ``int`` or ``float`` observation gives it feedback\n    with which to guide our search for inputs that will cause an error, in\n    addition to all the usual heuristics.  Observations must always be finite.\n\n    Hypothesis will try to maximize the observed value over several examples;\n    almost any metric will work so long as it makes sense to increase it.\n    For example, ``-abs(error)`` is a metric that increases as ``error``\n    approaches zero.\n\n    Example metrics:\n\n    - Number of elements in a collection, or tasks in a queue\n    - Mean or maximum runtime of a task (or both, if you use ``label``)\n    - Compression ratio for data (perhaps per-algorithm or per-level)\n    - Number of steps taken by a state machine\n\n    The optional ``label`` argument can be used to distinguish between\n    and therefore separately optimise distinct observations, such as the\n    mean and standard deviation of a dataset.  It is an error to call\n    ``target()`` with any label more than once per test case.\n\n    .. note::\n        The more examples you run, the better this technique works.\n\n        As a rule of thumb, the targeting effect is noticeable above\n        :obj:`max_examples=1000 <hypothesis.settings.max_examples>`,\n        and immediately obvious by around ten thousand examples\n        *per label* used by your test.\n\n    :ref:`statistics` include the best score seen for each label,\n    which can help avoid `the threshold problem\n    <https://hypothesis.works/articles/threshold-problem/>`__ when the minimal\n    example shrinks right down to the threshold of failure (:issue:`2180`).\n    \"\"\"\n    check_type((int, float), observation, \"observation\")\n    if not math.isfinite(observation):\n        raise InvalidArgument(f\"{observation=} must be a finite float.\")\n    check_type(str, label, \"label\")\n\n    context = _current_build_context.value\n    if context is None:\n        raise InvalidArgument(\n            \"Calling target() outside of a test is invalid.  \"\n            \"Consider guarding this call with `if currently_in_test_context(): ...`\"\n        )\n    elif context.data.provider.avoid_realization:\n        # We could in principle realize this in the engine, but it seems more\n        # efficient to have our alternative backend optimize it for us.\n        # See e.g. https://github.com/pschanely/hypothesis-crosshair/issues/3\n        return observation  # pragma: no cover\n    verbose_report(f\"Saw target({observation!r}, {label=})\")\n\n    if label in context.data.target_observations:\n        raise InvalidArgument(\n            f\"Calling target({observation!r}, {label=}) would overwrite \"\n            f\"target({context.data.target_observations[label]!r}, {label=})\"\n        )\n    else:\n        context.data.target_observations[label] = observation\n\n    return observation\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/core.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"This module provides the core primitives of Hypothesis, such as given.\"\"\"\n\nimport base64\nimport contextlib\nimport dataclasses\nimport datetime\nimport inspect\nimport io\nimport math\nimport os\nimport sys\nimport threading\nimport time\nimport traceback\nimport types\nimport unittest\nimport warnings\nimport zlib\nfrom collections import defaultdict\nfrom collections.abc import Callable, Coroutine, Generator, Hashable, Iterable, Sequence\nfrom dataclasses import dataclass, field\nfrom functools import partial\nfrom inspect import Parameter\nfrom random import Random\nfrom threading import Lock\nfrom types import EllipsisType\nfrom typing import (\n    Any,\n    BinaryIO,\n    TypeVar,\n    overload,\n)\nfrom unittest import TestCase\n\nfrom hypothesis import strategies as st\nfrom hypothesis._settings import (\n    HealthCheck,\n    Phase,\n    Verbosity,\n    all_settings,\n    local_settings,\n    settings as Settings,\n)\nfrom hypothesis.control import BuildContext, currently_in_test_context\nfrom hypothesis.database import choices_from_bytes, choices_to_bytes\nfrom hypothesis.errors import (\n    BackendCannotProceed,\n    DeadlineExceeded,\n    DidNotReproduce,\n    FailedHealthCheck,\n    FlakyFailure,\n    FlakyReplay,\n    Found,\n    Frozen,\n    HypothesisException,\n    HypothesisWarning,\n    InvalidArgument,\n    NoSuchExample,\n    StopTest,\n    Unsatisfiable,\n    UnsatisfiedAssumption,\n)\nfrom hypothesis.internal import observability\nfrom hypothesis.internal.compat import (\n    PYPY,\n    BaseExceptionGroup,\n    add_note,\n    bad_django_TestCase,\n    get_type_hints,\n    int_from_bytes,\n)\nfrom hypothesis.internal.conjecture.choice import ChoiceT\nfrom hypothesis.internal.conjecture.data import ConjectureData, Status\nfrom hypothesis.internal.conjecture.engine import BUFFER_SIZE, ConjectureRunner\nfrom hypothesis.internal.conjecture.junkdrawer import (\n    ensure_free_stackframes,\n    gc_cumulative_time,\n)\nfrom hypothesis.internal.conjecture.providers import (\n    BytestringProvider,\n    PrimitiveProvider,\n)\nfrom hypothesis.internal.conjecture.shrinker import sort_key\nfrom hypothesis.internal.entropy import deterministic_PRNG\nfrom hypothesis.internal.escalation import (\n    InterestingOrigin,\n    current_pytest_item,\n    format_exception,\n    get_trimmed_traceback,\n    is_hypothesis_file,\n)\nfrom hypothesis.internal.healthcheck import fail_health_check\nfrom hypothesis.internal.observability import (\n    InfoObservation,\n    InfoObservationType,\n    deliver_observation,\n    make_testcase,\n    observability_enabled,\n)\nfrom hypothesis.internal.reflection import (\n    convert_positional_arguments,\n    define_function_signature,\n    function_digest,\n    get_pretty_function_description,\n    get_signature,\n    impersonate,\n    is_mock,\n    nicerepr,\n    proxies,\n    repr_call,\n)\nfrom hypothesis.internal.scrutineer import (\n    MONITORING_TOOL_ID,\n    Trace,\n    Tracer,\n    explanatory_lines,\n    tractable_coverage_report,\n)\nfrom hypothesis.internal.validation import check_type\nfrom hypothesis.reporting import (\n    current_verbosity,\n    report,\n    verbose_report,\n    with_reporter,\n)\nfrom hypothesis.statistics import describe_statistics, describe_targets, note_statistics\nfrom hypothesis.strategies._internal.misc import NOTHING\nfrom hypothesis.strategies._internal.strategies import (\n    Ex,\n    SearchStrategy,\n    check_strategy,\n)\nfrom hypothesis.utils.conventions import not_set\nfrom hypothesis.utils.threading import ThreadLocal\nfrom hypothesis.vendor.pretty import RepresentationPrinter\nfrom hypothesis.version import __version__\n\nTestFunc = TypeVar(\"TestFunc\", bound=Callable)\n\n\nrunning_under_pytest = False\npytest_shows_exceptiongroups = True\nglobal_force_seed = None\n# this variable stores \"engine-global\" constants, which are global relative to a\n# ConjectureRunner instance (roughly speaking). Since only one conjecture runner\n# instance can be active per thread, making engine constants thread-local prevents\n# the ConjectureRunner instances of concurrent threads from treading on each other.\nthreadlocal = ThreadLocal(_hypothesis_global_random=lambda: None)\n\n\n@dataclass(slots=True, frozen=False)\nclass Example:\n    args: Any\n    kwargs: Any\n    # Plus two optional arguments for .xfail()\n    raises: Any = field(default=None)\n    reason: Any = field(default=None)\n\n\n@dataclass(slots=True, frozen=True)\nclass ReportableError:\n    fragments: list[str]\n    exception: BaseException\n\n\n# TODO_DOCS link to not-yet-existent patch-dumping docs\n\n\nclass example:\n    \"\"\"\n    Add an explicit input to a Hypothesis test, which Hypothesis will always\n    try before generating random inputs. This combines the randomized nature of\n    Hypothesis generation with a traditional parametrized test.\n\n    For example:\n\n    .. code-block:: python\n\n        @example(\"Hello world\")\n        @example(\"some string with special significance\")\n        @given(st.text())\n        def test_strings(s):\n            pass\n\n    will call ``test_strings(\"Hello World\")`` and\n    ``test_strings(\"some string with special significance\")`` before generating\n    any random inputs. |@example| may be placed in any order relative to |@given|\n    and |@settings|.\n\n    Explicit inputs from |@example| are run in the |Phase.explicit| phase.\n    Explicit inputs do not count towards |settings.max_examples|. Note that\n    explicit inputs added by |@example| do not shrink. If an explicit input\n    fails, Hypothesis will stop and report the failure without generating any\n    random inputs.\n\n    |@example| can also be used to easily reproduce a failure. For instance, if\n    Hypothesis reports that ``f(n=[0, math.nan])`` fails, you can add\n    ``@example(n=[0, math.nan])`` to your test to quickly reproduce that failure.\n\n    Arguments to ``@example``\n    -------------------------\n\n    Arguments to |@example| have the same behavior and restrictions as arguments\n    to |@given|. This means they may be either positional or keyword arguments\n    (but not both in the same |@example|):\n\n    .. code-block:: python\n\n        @example(1, 2)\n        @example(x=1, y=2)\n        @given(st.integers(), st.integers())\n        def test(x, y):\n            pass\n\n    Noting that while arguments to |@given| are strategies (like |st.integers|),\n    arguments to |@example| are values instead (like ``1``).\n\n    See the :ref:`given-arguments` section for full details.\n    \"\"\"\n\n    def __init__(self, *args: Any, **kwargs: Any) -> None:\n        if args and kwargs:\n            raise InvalidArgument(\n                \"Cannot mix positional and keyword arguments for examples\"\n            )\n        if not (args or kwargs):\n            raise InvalidArgument(\"An example must provide at least one argument\")\n\n        self.hypothesis_explicit_examples: list[Example] = []\n        self._this_example = Example(tuple(args), kwargs)\n\n    def __call__(self, test: TestFunc) -> TestFunc:\n        if not hasattr(test, \"hypothesis_explicit_examples\"):\n            test.hypothesis_explicit_examples = self.hypothesis_explicit_examples  # type: ignore\n        test.hypothesis_explicit_examples.append(self._this_example)  # type: ignore\n        return test\n\n    def xfail(\n        self,\n        condition: bool = True,  # noqa: FBT002\n        *,\n        reason: str = \"\",\n        raises: type[BaseException] | tuple[type[BaseException], ...] = BaseException,\n    ) -> \"example\":\n        \"\"\"Mark this example as an expected failure, similarly to\n        :obj:`pytest.mark.xfail(strict=True) <pytest.mark.xfail>`.\n\n        Expected-failing examples allow you to check that your test does fail on\n        some examples, and therefore build confidence that *passing* tests are\n        because your code is working, not because the test is missing something.\n\n        .. code-block:: python\n\n            @example(...).xfail()\n            @example(...).xfail(reason=\"Prices must be non-negative\")\n            @example(...).xfail(raises=(KeyError, ValueError))\n            @example(...).xfail(sys.version_info[:2] >= (3, 12), reason=\"needs py 3.12\")\n            @example(...).xfail(condition=sys.platform != \"linux\", raises=OSError)\n            def test(x):\n                pass\n\n        .. note::\n\n            Expected-failing examples are handled separately from those generated\n            by strategies, so you should usually ensure that there is no overlap.\n\n            .. code-block:: python\n\n                @example(x=1, y=0).xfail(raises=ZeroDivisionError)\n                @given(x=st.just(1), y=st.integers())  # Missing `.filter(bool)`!\n                def test_fraction(x, y):\n                    # This test will try the explicit example and see it fail as\n                    # expected, then go on to generate more examples from the\n                    # strategy.  If we happen to generate y=0, the test will fail\n                    # because only the explicit example is treated as xfailing.\n                    x / y\n        \"\"\"\n        check_type(bool, condition, \"condition\")\n        check_type(str, reason, \"reason\")\n        if not (\n            isinstance(raises, type) and issubclass(raises, BaseException)\n        ) and not (\n            isinstance(raises, tuple)\n            and raises  # () -> expected to fail with no error, which is impossible\n            and all(\n                isinstance(r, type) and issubclass(r, BaseException) for r in raises\n            )\n        ):\n            raise InvalidArgument(\n                f\"{raises=} must be an exception type or tuple of exception types\"\n            )\n        if condition:\n            self._this_example = dataclasses.replace(\n                self._this_example, raises=raises, reason=reason\n            )\n        return self\n\n    def via(self, whence: str, /) -> \"example\":\n        \"\"\"Attach a machine-readable label noting what the origin of this example\n        was. |example.via| is completely optional and does not change runtime\n        behavior.\n\n        |example.via| is intended to support self-documenting behavior, as well as\n        tooling which might add (or remove) |@example| decorators automatically.\n        For example:\n\n        .. code-block:: python\n\n            # Annotating examples is optional and does not change runtime behavior\n            @example(...)\n            @example(...).via(\"regression test for issue #42\")\n            @example(...).via(\"discovered failure\")\n            def test(x):\n                pass\n\n        .. note::\n\n            `HypoFuzz <https://hypofuzz.com/>`_ uses |example.via| to tag examples\n            in the patch of its high-coverage set of explicit inputs, on\n            `the patches page <https://hypofuzz.com/example-dashboard/#/patches>`_.\n        \"\"\"\n        if not isinstance(whence, str):\n            raise InvalidArgument(\".via() must be passed a string\")\n        # This is deliberately a no-op at runtime; the tools operate on source code.\n        return self\n\n\ndef seed(seed: Hashable) -> Callable[[TestFunc], TestFunc]:\n    \"\"\"\n    Seed the randomness for this test.\n\n    ``seed`` may be any hashable object. No exact meaning for ``seed`` is provided\n    other than that for a fixed seed value Hypothesis will produce the same\n    examples (assuming that there are no other sources of nondeterminisim, such\n    as timing, hash randomization, or external state).\n\n    For example, the following test function and |RuleBasedStateMachine| will\n    each generate the same series of examples each time they are executed:\n\n    .. code-block:: python\n\n        @seed(1234)\n        @given(st.integers())\n        def test(n): ...\n\n        @seed(6789)\n        class MyMachine(RuleBasedStateMachine): ...\n\n    If using pytest, you can alternatively pass ``--hypothesis-seed`` on the\n    command line.\n\n    Setting a seed overrides |settings.derandomize|, which is designed to enable\n    deterministic CI tests rather than reproducing observed failures.\n\n    Hypothesis will only print the seed which would reproduce a failure if a test\n    fails in an unexpected way, for instance inside Hypothesis internals.\n    \"\"\"\n\n    def accept(test):\n        test._hypothesis_internal_use_seed = seed\n        current_settings = getattr(test, \"_hypothesis_internal_use_settings\", None)\n        test._hypothesis_internal_use_settings = Settings(\n            current_settings, database=None\n        )\n        return test\n\n    return accept\n\n\n# TODO_DOCS: link to /explanation/choice-sequence\n\n\ndef reproduce_failure(version: str, blob: bytes) -> Callable[[TestFunc], TestFunc]:\n    \"\"\"\n    Run the example corresponding to the binary ``blob`` in order to reproduce a\n    failure. ``blob`` is a serialized version of the internal input representation\n    of Hypothesis.\n\n    A test decorated with |@reproduce_failure| always runs exactly one example,\n    which is expected to cause a failure. If the provided ``blob`` does not\n    cause a failure, Hypothesis will raise |DidNotReproduce|.\n\n    Hypothesis will print an |@reproduce_failure| decorator if\n    |settings.print_blob| is ``True`` (which is the default in CI).\n\n    |@reproduce_failure| is intended to be temporarily added to your test suite in\n    order to reproduce a failure. It is not intended to be a permanent addition to\n    your test suite. Because of this, no compatibility guarantees are made across\n    Hypothesis versions, and |@reproduce_failure| will error if used on a different\n    Hypothesis version than it was created for.\n\n    .. seealso::\n\n        See also the :doc:`/tutorial/replaying-failures` tutorial.\n    \"\"\"\n\n    def accept(test):\n        test._hypothesis_internal_use_reproduce_failure = (version, blob)\n        return test\n\n    return accept\n\n\ndef reproduction_decorator(choices: Iterable[ChoiceT]) -> str:\n    return f\"@reproduce_failure({__version__!r}, {encode_failure(choices)!r})\"\n\n\ndef encode_failure(choices: Iterable[ChoiceT]) -> bytes:\n    blob = choices_to_bytes(choices)\n    compressed = zlib.compress(blob)\n    if len(compressed) < len(blob):\n        blob = b\"\\1\" + compressed\n    else:\n        blob = b\"\\0\" + blob\n    return base64.b64encode(blob)\n\n\ndef decode_failure(blob: bytes) -> Sequence[ChoiceT]:\n    try:\n        decoded = base64.b64decode(blob)\n    except Exception:\n        raise InvalidArgument(f\"Invalid base64 encoded string: {blob!r}\") from None\n\n    prefix = decoded[:1]\n    if prefix == b\"\\0\":\n        decoded = decoded[1:]\n    elif prefix == b\"\\1\":\n        try:\n            decoded = zlib.decompress(decoded[1:])\n        except zlib.error as err:\n            raise InvalidArgument(\n                f\"Invalid zlib compression for blob {blob!r}\"\n            ) from err\n    else:\n        raise InvalidArgument(\n            f\"Could not decode blob {blob!r}: Invalid start byte {prefix!r}\"\n        )\n\n    choices = choices_from_bytes(decoded)\n    if choices is None:\n        raise InvalidArgument(f\"Invalid serialized choice sequence for blob {blob!r}\")\n\n    return choices\n\n\ndef _invalid(message, *, exc=InvalidArgument, test, given_kwargs):\n    @impersonate(test)\n    def wrapped_test(*arguments, **kwargs):  # pragma: no cover  # coverage limitation\n        raise exc(message)\n\n    wrapped_test.is_hypothesis_test = True\n    wrapped_test.hypothesis = HypothesisHandle(\n        inner_test=test,\n        _get_fuzz_target=wrapped_test,\n        _given_kwargs=given_kwargs,\n    )\n    return wrapped_test\n\n\ndef is_invalid_test(test, original_sig, given_arguments, given_kwargs):\n    \"\"\"Check the arguments to ``@given`` for basic usage constraints.\n\n    Most errors are not raised immediately; instead we return a dummy test\n    function that will raise the appropriate error if it is actually called.\n    When the user runs a subset of tests (e.g via ``pytest -k``), errors will\n    only be reported for tests that actually ran.\n    \"\"\"\n    invalid = partial(_invalid, test=test, given_kwargs=given_kwargs)\n\n    if not (given_arguments or given_kwargs):\n        return invalid(\"given must be called with at least one argument\")\n\n    params = list(original_sig.parameters.values())\n    pos_params = [p for p in params if p.kind is p.POSITIONAL_OR_KEYWORD]\n    kwonly_params = [p for p in params if p.kind is p.KEYWORD_ONLY]\n    if given_arguments and params != pos_params:\n        return invalid(\n            \"positional arguments to @given are not supported with varargs, \"\n            \"varkeywords, positional-only, or keyword-only arguments\"\n        )\n\n    if len(given_arguments) > len(pos_params):\n        return invalid(\n            f\"Too many positional arguments for {test.__name__}() were passed to \"\n            f\"@given - expected at most {len(pos_params)} \"\n            f\"arguments, but got {len(given_arguments)} {given_arguments!r}\"\n        )\n\n    if ... in given_arguments:\n        return invalid(\n            \"... was passed as a positional argument to @given, but may only be \"\n            \"passed as a keyword argument or as the sole argument of @given\"\n        )\n\n    if given_arguments and given_kwargs:\n        return invalid(\"cannot mix positional and keyword arguments to @given\")\n    extra_kwargs = [\n        k for k in given_kwargs if k not in {p.name for p in pos_params + kwonly_params}\n    ]\n    if extra_kwargs and (params == [] or params[-1].kind is not params[-1].VAR_KEYWORD):\n        arg = extra_kwargs[0]\n        extra = \"\"\n        if arg in all_settings:\n            extra = f\". Did you mean @settings({arg}={given_kwargs[arg]!r})?\"\n        return invalid(\n            f\"{test.__name__}() got an unexpected keyword argument {arg!r}, \"\n            f\"from `{arg}={given_kwargs[arg]!r}` in @given{extra}\"\n        )\n    if any(p.default is not p.empty for p in params):\n        return invalid(\"Cannot apply @given to a function with defaults.\")\n\n    # This case would raise Unsatisfiable *anyway*, but by detecting it here we can\n    # provide a much more helpful error message for people e.g. using the Ghostwriter.\n    empty = [\n        f\"{s!r} (arg {idx})\" for idx, s in enumerate(given_arguments) if s is NOTHING\n    ] + [f\"{name}={s!r}\" for name, s in given_kwargs.items() if s is NOTHING]\n    if empty:\n        strats = \"strategies\" if len(empty) > 1 else \"strategy\"\n        return invalid(\n            f\"Cannot generate examples from empty {strats}: \" + \", \".join(empty),\n            exc=Unsatisfiable,\n        )\n\n\ndef execute_explicit_examples(state, wrapped_test, arguments, kwargs, original_sig):\n    assert isinstance(state, StateForActualGivenExecution)\n    posargs = [\n        p.name\n        for p in original_sig.parameters.values()\n        if p.kind is p.POSITIONAL_OR_KEYWORD\n    ]\n\n    for example in reversed(getattr(wrapped_test, \"hypothesis_explicit_examples\", ())):\n        assert isinstance(example, Example)\n        # All of this validation is to check that @example() got \"the same\" arguments\n        # as @given, i.e. corresponding to the same parameters, even though they might\n        # be any mixture of positional and keyword arguments.\n        if example.args:\n            assert not example.kwargs\n            if any(\n                p.kind is p.POSITIONAL_ONLY for p in original_sig.parameters.values()\n            ):\n                raise InvalidArgument(\n                    \"Cannot pass positional arguments to @example() when decorating \"\n                    \"a test function which has positional-only parameters.\"\n                )\n            if len(example.args) > len(posargs):\n                raise InvalidArgument(\n                    \"example has too many arguments for test. Expected at most \"\n                    f\"{len(posargs)} but got {len(example.args)}\"\n                )\n            example_kwargs = dict(\n                zip(posargs[-len(example.args) :], example.args, strict=True)\n            )\n        else:\n            example_kwargs = dict(example.kwargs)\n        given_kws = \", \".join(\n            repr(k) for k in sorted(wrapped_test.hypothesis._given_kwargs)\n        )\n        example_kws = \", \".join(repr(k) for k in sorted(example_kwargs))\n        if given_kws != example_kws:\n            raise InvalidArgument(\n                f\"Inconsistent args: @given() got strategies for {given_kws}, \"\n                f\"but @example() got arguments for {example_kws}\"\n            ) from None\n\n        # This is certainly true because the example_kwargs exactly match the params\n        # reserved by @given(), which are then remove from the function signature.\n        assert set(example_kwargs).isdisjoint(kwargs)\n        example_kwargs.update(kwargs)\n\n        if Phase.explicit not in state.settings.phases:\n            continue\n\n        with local_settings(state.settings):\n            fragments_reported = []\n            empty_data = ConjectureData.for_choices([])\n            try:\n                execute_example = partial(\n                    state.execute_once,\n                    empty_data,\n                    is_final=True,\n                    print_example=True,\n                    example_kwargs=example_kwargs,\n                )\n                with with_reporter(fragments_reported.append):\n                    if example.raises is None:\n                        execute_example()\n                    else:\n                        # @example(...).xfail(...)\n                        bits = \", \".join(nicerepr(x) for x in arguments) + \", \".join(\n                            f\"{k}={nicerepr(v)}\" for k, v in example_kwargs.items()\n                        )\n                        try:\n                            execute_example()\n                        except failure_exceptions_to_catch() as err:\n                            if not isinstance(err, example.raises):\n                                raise\n                            # Save a string form of this example; we'll warn if it's\n                            # ever generated by the strategy (which can't be xfailed)\n                            state.xfail_example_reprs.add(\n                                repr_call(state.test, arguments, example_kwargs)\n                            )\n                        except example.raises as err:\n                            # We'd usually check this as early as possible, but it's\n                            # possible for failure_exceptions_to_catch() to grow when\n                            # e.g. pytest is imported between import- and test-time.\n                            raise InvalidArgument(\n                                f\"@example({bits}) raised an expected {err!r}, \"\n                                \"but Hypothesis does not treat this as a test failure\"\n                            ) from err\n                        else:\n                            # Unexpectedly passing; always raise an error in this case.\n                            reason = f\" because {example.reason}\" * bool(example.reason)\n                            if example.raises is BaseException:\n                                name = \"exception\"  # special-case no raises= arg\n                            elif not isinstance(example.raises, tuple):\n                                name = example.raises.__name__\n                            elif len(example.raises) == 1:\n                                name = example.raises[0].__name__\n                            else:\n                                name = (\n                                    \", \".join(ex.__name__ for ex in example.raises[:-1])\n                                    + f\", or {example.raises[-1].__name__}\"\n                                )\n                            vowel = name.upper()[0] in \"AEIOU\"\n                            raise AssertionError(\n                                f\"Expected a{'n' * vowel} {name} from @example({bits})\"\n                                f\"{reason}, but no exception was raised.\"\n                            )\n            except UnsatisfiedAssumption:\n                # Odd though it seems, we deliberately support explicit examples that\n                # are then rejected by a call to `assume()`.  As well as iterative\n                # development, this is rather useful to replay Hypothesis' part of\n                # a saved failure when other arguments are supplied by e.g. pytest.\n                # See https://github.com/HypothesisWorks/hypothesis/issues/2125\n                with contextlib.suppress(StopTest):\n                    empty_data.conclude_test(Status.INVALID)\n            except BaseException as err:\n                # In order to support reporting of multiple failing examples, we yield\n                # each of the (report text, error) pairs we find back to the top-level\n                # runner.  This also ensures that user-facing stack traces have as few\n                # frames of Hypothesis internals as possible.\n                err = err.with_traceback(get_trimmed_traceback())\n\n                # One user error - whether misunderstanding or typo - we've seen a few\n                # times is to pass strategies to @example() where values are expected.\n                # Checking is easy, and false-positives not much of a problem, so:\n                if isinstance(err, failure_exceptions_to_catch()) and any(\n                    isinstance(arg, SearchStrategy)\n                    for arg in example.args + tuple(example.kwargs.values())\n                ):\n                    new = HypothesisWarning(\n                        \"The @example() decorator expects to be passed values, but \"\n                        \"you passed strategies instead.  See https://hypothesis.\"\n                        \"readthedocs.io/en/latest/reference/api.html#hypothesis\"\n                        \".example for details.\"\n                    )\n                    new.__cause__ = err\n                    err = new\n\n                with contextlib.suppress(StopTest):\n                    empty_data.conclude_test(Status.INVALID)\n                yield ReportableError(fragments_reported, err)\n                if (\n                    state.settings.report_multiple_bugs\n                    and pytest_shows_exceptiongroups\n                    and isinstance(err, failure_exceptions_to_catch())\n                    and not isinstance(err, skip_exceptions_to_reraise())\n                ):\n                    continue\n                break\n            finally:\n                if fragments_reported:\n                    assert fragments_reported[0].startswith(\"Falsifying example\")\n                    fragments_reported[0] = fragments_reported[0].replace(\n                        \"Falsifying example\", \"Falsifying explicit example\", 1\n                    )\n\n                empty_data.freeze()\n                if observability_enabled():\n                    tc = make_testcase(\n                        run_start=state._start_timestamp,\n                        property=state.test_identifier,\n                        data=empty_data,\n                        how_generated=\"explicit example\",\n                        representation=state._string_repr,\n                        timing=state._timing_features,\n                    )\n                    deliver_observation(tc)\n\n            if fragments_reported:\n                verbose_report(fragments_reported[0].replace(\"Falsifying\", \"Trying\", 1))\n                for f in fragments_reported[1:]:\n                    verbose_report(f)\n\n\ndef get_random_for_wrapped_test(test, wrapped_test):\n    settings = wrapped_test._hypothesis_internal_use_settings\n    wrapped_test._hypothesis_internal_use_generated_seed = None\n\n    if wrapped_test._hypothesis_internal_use_seed is not None:\n        return Random(wrapped_test._hypothesis_internal_use_seed)\n\n    if settings.derandomize:\n        return Random(int_from_bytes(function_digest(test)))\n\n    if global_force_seed is not None:\n        return Random(global_force_seed)\n\n    if threadlocal._hypothesis_global_random is None:  # pragma: no cover\n        threadlocal._hypothesis_global_random = Random()\n    seed = threadlocal._hypothesis_global_random.getrandbits(128)\n    wrapped_test._hypothesis_internal_use_generated_seed = seed\n    return Random(seed)\n\n\n@dataclass(slots=True, frozen=False)\nclass Stuff:\n    selfy: Any\n    args: tuple\n    kwargs: dict\n    given_kwargs: dict\n\n\ndef process_arguments_to_given(\n    wrapped_test: Any,\n    arguments: Sequence[object],\n    kwargs: dict[str, object],\n    given_kwargs: dict[str, SearchStrategy],\n    params: dict[str, Parameter],\n) -> tuple[Sequence[object], dict[str, object], Stuff]:\n    selfy = None\n    arguments, kwargs = convert_positional_arguments(wrapped_test, arguments, kwargs)\n\n    # If the test function is a method of some kind, the bound object\n    # will be the first named argument if there are any, otherwise the\n    # first vararg (if any).\n    posargs = [p.name for p in params.values() if p.kind is p.POSITIONAL_OR_KEYWORD]\n    if posargs:\n        selfy = kwargs.get(posargs[0])\n    elif arguments:\n        selfy = arguments[0]\n\n    # Ensure that we don't mistake mocks for self here.\n    # This can cause the mock to be used as the test runner.\n    if is_mock(selfy):\n        selfy = None\n\n    arguments = tuple(arguments)\n\n    with ensure_free_stackframes():\n        for k, s in given_kwargs.items():\n            check_strategy(s, name=k)\n            s.validate()\n\n    stuff = Stuff(selfy=selfy, args=arguments, kwargs=kwargs, given_kwargs=given_kwargs)\n\n    return arguments, kwargs, stuff\n\n\ndef skip_exceptions_to_reraise():\n    \"\"\"Return a tuple of exceptions meaning 'skip this test', to re-raise.\n\n    This is intended to cover most common test runners; if you would\n    like another to be added please open an issue or pull request adding\n    it to this function and to tests/cover/test_lazy_import.py\n    \"\"\"\n    # This is a set in case any library simply re-exports another's Skip exception\n    exceptions = set()\n    # We use this sys.modules trick to avoid importing libraries -\n    # you can't be an instance of a type from an unimported module!\n    # This is fast enough that we don't need to cache the result,\n    # and more importantly it avoids possible side-effects :-)\n    if \"unittest\" in sys.modules:\n        exceptions.add(sys.modules[\"unittest\"].SkipTest)\n    if \"_pytest.outcomes\" in sys.modules:\n        exceptions.add(sys.modules[\"_pytest.outcomes\"].Skipped)\n    return tuple(sorted(exceptions, key=str))\n\n\ndef failure_exceptions_to_catch() -> tuple[type[BaseException], ...]:\n    \"\"\"Return a tuple of exceptions meaning 'this test has failed', to catch.\n\n    This is intended to cover most common test runners; if you would\n    like another to be added please open an issue or pull request.\n    \"\"\"\n    # While SystemExit and GeneratorExit are instances of BaseException, we also\n    # expect them to be deterministic - unlike KeyboardInterrupt - and so we treat\n    # them as standard exceptions, check for flakiness, etc.\n    # See https://github.com/HypothesisWorks/hypothesis/issues/2223 for details.\n    exceptions = [Exception, SystemExit, GeneratorExit]\n    if \"_pytest.outcomes\" in sys.modules:\n        exceptions.append(sys.modules[\"_pytest.outcomes\"].Failed)\n    return tuple(exceptions)\n\n\ndef new_given_signature(original_sig, given_kwargs):\n    \"\"\"Make an updated signature for the wrapped test.\"\"\"\n    return original_sig.replace(\n        parameters=[\n            p\n            for p in original_sig.parameters.values()\n            if not (\n                p.name in given_kwargs\n                and p.kind in (p.POSITIONAL_OR_KEYWORD, p.KEYWORD_ONLY)\n            )\n        ],\n        return_annotation=None,\n    )\n\n\ndef default_executor(data, function):\n    return function(data)\n\n\ndef get_executor(runner):\n    try:\n        execute_example = runner.execute_example\n    except AttributeError:\n        pass\n    else:\n        return lambda data, function: execute_example(partial(function, data))\n\n    if hasattr(runner, \"setup_example\") or hasattr(runner, \"teardown_example\"):\n        setup = getattr(runner, \"setup_example\", None) or (lambda: None)\n        teardown = getattr(runner, \"teardown_example\", None) or (lambda ex: None)\n\n        def execute(data, function):\n            token = None\n            try:\n                token = setup()\n                return function(data)\n            finally:\n                teardown(token)\n\n        return execute\n\n    return default_executor\n\n\n# This function is a crude solution, a better way of resolving it would probably\n# be to rewrite a bunch of exception handlers to use except*.\nT = TypeVar(\"T\", bound=BaseException)\n\n\ndef _flatten_group(excgroup: BaseExceptionGroup[T]) -> list[T]:\n    found_exceptions: list[T] = []\n    for exc in excgroup.exceptions:\n        if isinstance(exc, BaseExceptionGroup):\n            found_exceptions.extend(_flatten_group(exc))\n        else:\n            found_exceptions.append(exc)\n    return found_exceptions\n\n\n@contextlib.contextmanager\ndef unwrap_markers_from_group() -> Generator[None, None, None]:\n    try:\n        yield\n    except BaseExceptionGroup as excgroup:\n        _frozen_exceptions, non_frozen_exceptions = excgroup.split(Frozen)\n\n        # group only contains Frozen, reraise the group\n        # it doesn't matter what we raise, since any exceptions get disregarded\n        # and reraised as StopTest if data got frozen.\n        if non_frozen_exceptions is None:\n            raise\n        # in all other cases they are discarded\n\n        # Can RewindRecursive end up in this group?\n        _, user_exceptions = non_frozen_exceptions.split(\n            lambda e: isinstance(e, (StopTest, HypothesisException))\n        )\n\n        # this might contain marker exceptions, or internal errors, but not frozen.\n        if user_exceptions is not None:\n            raise\n\n        # single marker exception - reraise it\n        flattened_non_frozen_exceptions: list[BaseException] = _flatten_group(\n            non_frozen_exceptions\n        )\n        if len(flattened_non_frozen_exceptions) == 1:\n            e = flattened_non_frozen_exceptions[0]\n            # preserve the cause of the original exception to not hinder debugging\n            # note that __context__ is still lost though\n            raise e from e.__cause__\n\n        # multiple marker exceptions. If we re-raise the whole group we break\n        # a bunch of logic so ....?\n        stoptests, non_stoptests = non_frozen_exceptions.split(StopTest)\n\n        # TODO: stoptest+hypothesisexception ...? Is it possible? If so, what do?\n\n        if non_stoptests:\n            # TODO: multiple marker exceptions is easy to produce, but the logic in the\n            # engine does not handle it... so we just reraise the first one for now.\n            e = _flatten_group(non_stoptests)[0]\n            raise e from e.__cause__\n        assert stoptests is not None\n\n        # multiple stoptests: raising the one with the lowest testcounter\n        raise min(_flatten_group(stoptests), key=lambda s_e: s_e.testcounter)\n\n\nclass StateForActualGivenExecution:\n    def __init__(\n        self,\n        stuff: Stuff,\n        test: Callable[..., Any],\n        settings: Settings,\n        random: Random,\n        wrapped_test: Any,\n        *,\n        thread_overlap: dict[int, bool] | None = None,\n    ):\n        self.stuff = stuff\n        self.test = test\n        self.settings = settings\n        self.random = random\n        self.wrapped_test = wrapped_test\n        self.thread_overlap = {} if thread_overlap is None else thread_overlap\n\n        self.test_runner = get_executor(stuff.selfy)\n        self.print_given_args = getattr(\n            wrapped_test, \"_hypothesis_internal_print_given_args\", True\n        )\n\n        self.last_exception = None\n        self.falsifying_examples = ()\n        self.ever_executed = False\n        self.xfail_example_reprs: set[str] = set()\n        self.failed_normally = False\n        self.failed_due_to_deadline = False\n\n        self.explain_traces: dict[None | InterestingOrigin, set[Trace]] = defaultdict(\n            set\n        )\n        self._start_timestamp = time.time()\n        self._string_repr = \"\"\n        self._timing_features: dict[str, float] = {}\n\n        self._runner: ConjectureRunner | None = None\n\n    @property\n    def test_identifier(self) -> str:\n        return getattr(\n            current_pytest_item.value, \"nodeid\", None\n        ) or get_pretty_function_description(self.wrapped_test)\n\n    def _should_trace(self):\n        # NOTE: we explicitly support monkeypatching this. Keep the namespace\n        # access intact.\n        _trace_obs = (\n            observability_enabled() and observability.OBSERVABILITY_COLLECT_COVERAGE\n        )\n        _trace_failure = (\n            self.failed_normally\n            and not self.failed_due_to_deadline\n            and {Phase.shrink, Phase.explain}.issubset(self.settings.phases)\n        )\n        return _trace_obs or _trace_failure\n\n    def execute_once(\n        self,\n        data,\n        *,\n        print_example=False,\n        is_final=False,\n        expected_failure=None,\n        example_kwargs=None,\n    ):\n        \"\"\"Run the test function once, using ``data`` as input.\n\n        If the test raises an exception, it will propagate through to the\n        caller of this method. Depending on its type, this could represent\n        an ordinary test failure, or a fatal error, or a control exception.\n\n        If this method returns normally, the test might have passed, or\n        it might have placed ``data`` in an unsuccessful state and then\n        swallowed the corresponding control exception.\n        \"\"\"\n\n        self.ever_executed = True\n\n        self._string_repr = \"\"\n        text_repr = None\n        if self.settings.deadline is None and not observability_enabled():\n\n            @proxies(self.test)\n            def test(*args, **kwargs):\n                with unwrap_markers_from_group(), ensure_free_stackframes():\n                    return self.test(*args, **kwargs)\n\n        else:\n\n            @proxies(self.test)\n            def test(*args, **kwargs):\n                arg_drawtime = math.fsum(data.draw_times.values())\n                arg_stateful = math.fsum(data._stateful_run_times.values())\n                arg_gctime = gc_cumulative_time()\n                with unwrap_markers_from_group(), ensure_free_stackframes():\n                    start = time.perf_counter()\n                    try:\n                        result = self.test(*args, **kwargs)\n                    finally:\n                        finish = time.perf_counter()\n                        in_drawtime = math.fsum(data.draw_times.values()) - arg_drawtime\n                        in_stateful = (\n                            math.fsum(data._stateful_run_times.values()) - arg_stateful\n                        )\n                        in_gctime = gc_cumulative_time() - arg_gctime\n                        runtime = finish - start - in_drawtime - in_stateful - in_gctime\n                        self._timing_features = {\n                            \"execute:test\": runtime,\n                            \"overall:gc\": in_gctime,\n                            **data.draw_times,\n                            **data._stateful_run_times,\n                        }\n\n                if (\n                    (current_deadline := self.settings.deadline) is not None\n                    # we disable the deadline check under concurrent threads, since\n                    # cpython may switch away from a thread for arbitrarily long.\n                    and not self.thread_overlap.get(threading.get_ident(), False)\n                ):\n                    if not is_final:\n                        current_deadline = (current_deadline // 4) * 5\n                    if runtime >= current_deadline.total_seconds():\n                        raise DeadlineExceeded(\n                            datetime.timedelta(seconds=runtime), self.settings.deadline\n                        )\n                return result\n\n        def run(data: ConjectureData) -> None:\n            # Set up dynamic context needed by a single test run.\n            if self.stuff.selfy is not None:\n                data.hypothesis_runner = self.stuff.selfy\n            # Generate all arguments to the test function.\n            args = self.stuff.args\n            kwargs = dict(self.stuff.kwargs)\n            if example_kwargs is None:\n                kw, argslices = context.prep_args_kwargs_from_strategies(\n                    self.stuff.given_kwargs\n                )\n            else:\n                kw = example_kwargs\n                argslices = {}\n            kwargs.update(kw)\n            if expected_failure is not None:\n                nonlocal text_repr\n                text_repr = repr_call(test, args, kwargs)\n\n            if print_example or current_verbosity() >= Verbosity.verbose:\n                printer = RepresentationPrinter(context=context)\n                if print_example:\n                    printer.text(\"Falsifying example:\")\n                else:\n                    printer.text(\"Trying example:\")\n\n                if self.print_given_args:\n                    printer.text(\" \")\n                    printer.repr_call(\n                        test.__name__,\n                        args,\n                        kwargs,\n                        force_split=True,\n                        arg_slices=argslices,\n                        leading_comment=(\n                            \"# \" + context.data.slice_comments[(0, 0)]\n                            if (0, 0) in context.data.slice_comments\n                            else None\n                        ),\n                        avoid_realization=data.provider.avoid_realization,\n                    )\n                report(printer.getvalue())\n\n            if observability_enabled():\n                printer = RepresentationPrinter(context=context)\n                printer.repr_call(\n                    test.__name__,\n                    args,\n                    kwargs,\n                    force_split=True,\n                    arg_slices=argslices,\n                    leading_comment=(\n                        \"# \" + context.data.slice_comments[(0, 0)]\n                        if (0, 0) in context.data.slice_comments\n                        else None\n                    ),\n                    avoid_realization=data.provider.avoid_realization,\n                )\n                self._string_repr = printer.getvalue()\n\n            try:\n                return test(*args, **kwargs)\n            except TypeError as e:\n                # If we sampled from a sequence of strategies, AND failed with a\n                # TypeError, *AND that exception mentions SearchStrategy*, add a note:\n                if (\n                    \"SearchStrategy\" in str(e)\n                    and data._sampled_from_all_strategies_elements_message is not None\n                ):\n                    msg, format_arg = data._sampled_from_all_strategies_elements_message\n                    add_note(e, msg.format(format_arg))\n                raise\n            finally:\n                if data._stateful_repr_parts is not None:\n                    self._string_repr = \"\\n\".join(data._stateful_repr_parts)\n\n                if observability_enabled():\n                    printer = RepresentationPrinter(context=context)\n                    for name, value in data._observability_args.items():\n                        if name.startswith(\"generate:Draw \"):\n                            try:\n                                value = data.provider.realize(value)\n                            except BackendCannotProceed:  # pragma: no cover\n                                value = \"<backend failed to realize symbolic>\"\n                            printer.text(f\"\\n{name.removeprefix('generate:')}: \")\n                            printer.pretty(value)\n\n                    self._string_repr += printer.getvalue()\n\n        # self.test_runner can include the execute_example method, or setup/teardown\n        # _example, so it's important to get the PRNG and build context in place first.\n        with (\n            local_settings(self.settings),\n            deterministic_PRNG(),\n            BuildContext(\n                data, is_final=is_final, wrapped_test=self.wrapped_test\n            ) as context,\n        ):\n            # providers may throw in per_case_context_fn, and we'd like\n            # `result` to still be set in these cases.\n            result = None\n            with data.provider.per_test_case_context_manager():\n                # Run the test function once, via the executor hook.\n                # In most cases this will delegate straight to `run(data)`.\n                result = self.test_runner(data, run)\n\n        # If a failure was expected, it should have been raised already, so\n        # instead raise an appropriate diagnostic error.\n        if expected_failure is not None:\n            exception, traceback = expected_failure\n            if isinstance(exception, DeadlineExceeded) and (\n                runtime_secs := math.fsum(\n                    v\n                    for k, v in self._timing_features.items()\n                    if k.startswith(\"execute:\")\n                )\n            ):\n                report(\n                    \"Unreliable test timings! On an initial run, this \"\n                    f\"test took {exception.runtime.total_seconds() * 1000:.2f}ms, \"\n                    \"which exceeded the deadline of \"\n                    f\"{self.settings.deadline.total_seconds() * 1000:.2f}ms, but \"\n                    f\"on a subsequent run it took {runtime_secs * 1000:.2f} ms, \"\n                    \"which did not. If you expect this sort of \"\n                    \"variability in your test timings, consider turning \"\n                    \"deadlines off for this test by setting deadline=None.\"\n                )\n            else:\n                report(\"Failed to reproduce exception. Expected: \\n\" + traceback)\n            raise FlakyFailure(\n                f\"Hypothesis {text_repr} produces unreliable results: \"\n                \"Falsified on the first call but did not on a subsequent one\",\n                [exception],\n            )\n        return result\n\n    def _flaky_replay_to_failure(\n        self, err: FlakyReplay, context: BaseException\n    ) -> FlakyFailure:\n        assert self._runner is not None\n        # Note that in the mark_interesting case, _context_ itself\n        # is part of err._interesting_examples - but it's not in\n        # _runner.interesting_examples - this is fine, as the context\n        # (i.e., immediate exception) is appended.\n        interesting_examples = [\n            self._runner.interesting_examples[origin]\n            for origin in err._interesting_origins\n            if origin in self._runner.interesting_examples\n        ]\n        exceptions = [result.expected_exception for result in interesting_examples]\n        exceptions.append(context)  # the immediate exception\n        return FlakyFailure(err.reason, exceptions)\n\n    def _execute_once_for_engine(self, data: ConjectureData) -> None:\n        \"\"\"Wrapper around ``execute_once`` that intercepts test failure\n        exceptions and single-test control exceptions, and turns them into\n        appropriate method calls to `data` instead.\n\n        This allows the engine to assume that any exception other than\n        ``StopTest`` must be a fatal error, and should stop the entire engine.\n        \"\"\"\n        trace: Trace = frozenset()\n        try:\n            with Tracer(should_trace=self._should_trace()) as tracer:\n                try:\n                    result = self.execute_once(data)\n                    if (\n                        data.status == Status.VALID and tracer.branches\n                    ):  # pragma: no cover\n                        # This is in fact covered by our *non-coverage* tests, but due\n                        # to the settrace() contention *not* by our coverage tests.\n                        self.explain_traces[None].add(tracer.branches)\n                finally:\n                    trace = tracer.branches\n            if result is not None:\n                fail_health_check(\n                    self.settings,\n                    \"Tests run under @given should return None, but \"\n                    f\"{self.test.__name__} returned {result!r} instead.\",\n                    HealthCheck.return_value,\n                )\n        except UnsatisfiedAssumption as e:\n            # An \"assume\" check failed, so instead we inform the engine that\n            # this test run was invalid.\n            try:\n                data.mark_invalid(e.reason)\n            except FlakyReplay as err:\n                # This was unexpected, meaning that the assume was flaky.\n                # Report it as such.\n                raise self._flaky_replay_to_failure(err, e) from None\n        except (StopTest, BackendCannotProceed):\n            # The engine knows how to handle this control exception, so it's\n            # OK to re-raise it.\n            raise\n        except (\n            FailedHealthCheck,\n            *skip_exceptions_to_reraise(),\n        ):\n            # These are fatal errors or control exceptions that should stop the\n            # engine, so we re-raise them.\n            raise\n        except failure_exceptions_to_catch() as e:\n            # If an unhandled (i.e., non-Hypothesis) error was raised by\n            # Hypothesis-internal code, re-raise it as a fatal error instead\n            # of treating it as a test failure.\n            if isinstance(e, BaseExceptionGroup) and len(e.exceptions) == 1:\n                # When a naked exception is implicitly wrapped in an ExceptionGroup\n                # due to a re-raising \"except*\", the ExceptionGroup is constructed in\n                # the caller's stack frame (see #4183). This workaround is specifically\n                # for implicit wrapping of naked exceptions by \"except*\", since explicit\n                # raising of ExceptionGroup gets the proper traceback in the first place\n                # - there's no need to handle hierarchical groups here, at least if no\n                # such implicit wrapping happens inside hypothesis code (we only care\n                # about the hypothesis-or-not distinction).\n                #\n                # 01-25-2025: this was patched to give the correct\n                # stacktrace in cpython https://github.com/python/cpython/issues/128799.\n                # can remove once python3.11 is EOL.\n                tb = e.exceptions[0].__traceback__ or e.__traceback__\n            else:\n                tb = e.__traceback__\n            filepath = traceback.extract_tb(tb)[-1][0]\n            if (\n                is_hypothesis_file(filepath)\n                and not isinstance(e, HypothesisException)\n                # We expect backend authors to use the provider_conformance test\n                # to test their backends. If an error occurs there, it is probably\n                # from their backend, and we would like to treat it as a standard\n                # error, not a hypothesis-internal error.\n                and not filepath.endswith(\n                    f\"internal{os.sep}conjecture{os.sep}provider_conformance.py\"\n                )\n            ):\n                raise\n\n            if data.frozen:\n                # This can happen if an error occurred in a finally\n                # block somewhere, suppressing our original StopTest.\n                # We raise a new one here to resume normal operation.\n                raise StopTest(data.testcounter) from e\n            else:\n                # The test failed by raising an exception, so we inform the\n                # engine that this test run was interesting. This is the normal\n                # path for test runs that fail.\n                tb = get_trimmed_traceback()\n                data.expected_traceback = format_exception(e, tb)\n                data.expected_exception = e\n                assert data.expected_traceback is not None  # for mypy\n                verbose_report(data.expected_traceback)\n\n                self.failed_normally = True\n\n                interesting_origin = InterestingOrigin.from_exception(e)\n                if trace:  # pragma: no cover\n                    # Trace collection is explicitly disabled under coverage.\n                    self.explain_traces[interesting_origin].add(trace)\n                if interesting_origin.exc_type == DeadlineExceeded:\n                    self.failed_due_to_deadline = True\n                    self.explain_traces.clear()\n                try:\n                    data.mark_interesting(interesting_origin)\n                except FlakyReplay as err:\n                    raise self._flaky_replay_to_failure(err, e) from None\n\n        finally:\n            # Conditional here so we can save some time constructing the payload; in\n            # other cases (without coverage) it's cheap enough to do that regardless.\n            #\n            # Note that we have to unconditionally realize data.events, because\n            # the statistics reported by the pytest plugin use a different flow\n            # than observability, but still access symbolic events.\n\n            try:\n                data.events = data.provider.realize(data.events)\n            except BackendCannotProceed:\n                data.events = {}\n\n            if observability_enabled():\n                if runner := getattr(self, \"_runner\", None):\n                    phase = runner._current_phase\n                else:  # pragma: no cover  # in case of messing with internals\n                    if self.failed_normally or self.failed_due_to_deadline:\n                        phase = \"shrink\"\n                    else:\n                        phase = \"unknown\"\n                backend_desc = f\", using backend={self.settings.backend!r}\" * (\n                    self.settings.backend != \"hypothesis\"\n                    and not getattr(runner, \"_switch_to_hypothesis_provider\", False)\n                )\n                try:\n                    data._observability_args = data.provider.realize(\n                        data._observability_args\n                    )\n                except BackendCannotProceed:\n                    data._observability_args = {}\n\n                try:\n                    self._string_repr = data.provider.realize(self._string_repr)\n                except BackendCannotProceed:\n                    self._string_repr = \"<backend failed to realize symbolic arguments>\"\n\n                data.freeze()\n                tc = make_testcase(\n                    run_start=self._start_timestamp,\n                    property=self.test_identifier,\n                    data=data,\n                    how_generated=f\"during {phase} phase{backend_desc}\",\n                    representation=self._string_repr,\n                    arguments=data._observability_args,\n                    timing=self._timing_features,\n                    coverage=tractable_coverage_report(trace) or None,\n                    phase=phase,\n                    backend_metadata=data.provider.observe_test_case(),\n                )\n                deliver_observation(tc)\n\n                for msg in data.provider.observe_information_messages(\n                    lifetime=\"test_case\"\n                ):\n                    self._deliver_information_message(**msg)\n            self._timing_features = {}\n\n    def _deliver_information_message(\n        self, *, type: InfoObservationType, title: str, content: str | dict\n    ) -> None:\n        deliver_observation(\n            InfoObservation(\n                type=type,\n                run_start=self._start_timestamp,\n                property=self.test_identifier,\n                title=title,\n                content=content,\n            )\n        )\n\n    def run_engine(self):\n        \"\"\"Run the test function many times, on database input and generated\n        input, using the Conjecture engine.\n        \"\"\"\n        # Tell pytest to omit the body of this function from tracebacks\n        __tracebackhide__ = True\n        try:\n            database_key = self.wrapped_test._hypothesis_internal_database_key\n        except AttributeError:\n            if global_force_seed is None:\n                database_key = function_digest(self.test)\n            else:\n                database_key = None\n\n        runner = ConjectureRunner(\n            self._execute_once_for_engine,\n            settings=self.settings,\n            random=self.random,\n            database_key=database_key,\n            thread_overlap=self.thread_overlap,\n        )\n        self._runner = runner\n        # Use the Conjecture engine to run the test function many times\n        # on different inputs.\n        runner.run()\n        note_statistics(runner.statistics)\n        if observability_enabled():\n            self._deliver_information_message(\n                type=\"info\",\n                title=\"Hypothesis Statistics\",\n                content=describe_statistics(runner.statistics),\n            )\n            for msg in (\n                p if isinstance(p := runner.provider, PrimitiveProvider) else p(None)\n            ).observe_information_messages(lifetime=\"test_function\"):\n                self._deliver_information_message(**msg)\n\n        if runner.call_count == 0:\n            return\n        if runner.interesting_examples:\n            self.falsifying_examples = sorted(\n                runner.interesting_examples.values(),\n                key=lambda d: sort_key(d.nodes),\n                reverse=True,\n            )\n        else:\n            if runner.valid_examples == 0:\n                explanations = []\n                # use a somewhat arbitrary cutoff to avoid recommending spurious\n                # fixes.\n                # eg, a few invalid examples from internal filters when the\n                # problem is the user generating large inputs, or a\n                # few overruns during internal mutation when the problem is\n                # impossible user filters/assumes.\n                if runner.invalid_examples > min(20, runner.call_count // 5):\n                    explanations.append(\n                        f\"{runner.invalid_examples} of {runner.call_count} \"\n                        \"examples failed a .filter() or assume() condition. Try \"\n                        \"making your filters or assumes less strict, or rewrite \"\n                        \"using strategy parameters: \"\n                        \"st.integers().filter(lambda x: x > 0) fails less often \"\n                        \"(that is, never) when rewritten as st.integers(min_value=1).\"\n                    )\n                if runner.overrun_examples > min(20, runner.call_count // 5):\n                    explanations.append(\n                        f\"{runner.overrun_examples} of {runner.call_count} \"\n                        \"examples were too large to finish generating; try \"\n                        \"reducing the typical size of your inputs?\"\n                    )\n                rep = get_pretty_function_description(self.test)\n                raise Unsatisfiable(\n                    f\"Unable to satisfy assumptions of {rep}. \"\n                    f\"{' Also, '.join(explanations)}\"\n                )\n\n        # If we have not traced executions, warn about that now (but only when\n        # we'd expect to do so reliably, i.e. on CPython>=3.12)\n        if (\n            hasattr(sys, \"monitoring\")\n            and not PYPY\n            and self._should_trace()\n            and not Tracer.can_trace()\n        ):  # pragma: no cover\n            # actually covered by our tests, but only on >= 3.12\n            warnings.warn(\n                \"avoiding tracing test function because tool id \"\n                f\"{MONITORING_TOOL_ID} is already taken by tool \"\n                f\"{sys.monitoring.get_tool(MONITORING_TOOL_ID)}.\",\n                HypothesisWarning,\n                stacklevel=3,\n            )\n\n        if not self.falsifying_examples:\n            return\n        elif not (self.settings.report_multiple_bugs and pytest_shows_exceptiongroups):\n            # Pretend that we only found one failure, by discarding the others.\n            del self.falsifying_examples[:-1]\n\n        # The engine found one or more failures, so we need to reproduce and\n        # report them.\n\n        errors_to_report = []\n\n        report_lines = describe_targets(runner.best_observed_targets)\n        if report_lines:\n            report_lines.append(\"\")\n\n        explanations = explanatory_lines(self.explain_traces, self.settings)\n        for falsifying_example in self.falsifying_examples:\n            fragments = []\n\n            ran_example = runner.new_conjecture_data(\n                falsifying_example.choices, max_choices=len(falsifying_example.choices)\n            )\n            ran_example.slice_comments = falsifying_example.slice_comments\n            tb = None\n            origin = None\n            assert falsifying_example.expected_exception is not None\n            assert falsifying_example.expected_traceback is not None\n            try:\n                with with_reporter(fragments.append):\n                    self.execute_once(\n                        ran_example,\n                        print_example=True,\n                        is_final=True,\n                        expected_failure=(\n                            falsifying_example.expected_exception,\n                            falsifying_example.expected_traceback,\n                        ),\n                    )\n            except StopTest as e:\n                # Link the expected exception from the first run. Not sure\n                # how to access the current exception, if it failed\n                # differently on this run. In fact, in the only known\n                # reproducer, the StopTest is caused by OVERRUN before the\n                # test is even executed. Possibly because all initial examples\n                # failed until the final non-traced replay, and something was\n                # exhausted? Possibly a FIXME, but sufficiently weird to\n                # ignore for now.\n                err = FlakyFailure(\n                    \"Inconsistent results: An example failed on the \"\n                    \"first run but now succeeds (or fails with another \"\n                    \"error, or is for some reason not runnable).\",\n                    # (note: e is a BaseException)\n                    [falsifying_example.expected_exception or e],\n                )\n                errors_to_report.append(ReportableError(fragments, err))\n            except UnsatisfiedAssumption as e:  # pragma: no cover  # ironically flaky\n                err = FlakyFailure(\n                    \"Unreliable assumption: An example which satisfied \"\n                    \"assumptions on the first run now fails it.\",\n                    [e],\n                )\n                errors_to_report.append(ReportableError(fragments, err))\n            except BaseException as e:\n                # If we have anything for explain-mode, this is the time to report.\n                fragments.extend(explanations[falsifying_example.interesting_origin])\n                error_with_tb = e.with_traceback(get_trimmed_traceback())\n                errors_to_report.append(ReportableError(fragments, error_with_tb))\n                tb = format_exception(e, get_trimmed_traceback(e))\n                origin = InterestingOrigin.from_exception(e)\n            else:\n                # execute_once() will always raise either the expected error, or Flaky.\n                raise NotImplementedError(\"This should be unreachable\")\n            finally:\n                ran_example.freeze()\n                if observability_enabled():\n                    # log our observability line for the final failing example\n                    tc = make_testcase(\n                        run_start=self._start_timestamp,\n                        property=self.test_identifier,\n                        data=ran_example,\n                        how_generated=\"minimal failing example\",\n                        representation=self._string_repr,\n                        arguments=ran_example._observability_args,\n                        timing=self._timing_features,\n                        coverage=None,  # Not recorded when we're replaying the MFE\n                        status=\"passed\" if sys.exc_info()[0] else \"failed\",\n                        status_reason=str(origin or \"unexpected/flaky pass\"),\n                        metadata={\"traceback\": tb},\n                    )\n                    deliver_observation(tc)\n\n                # Whether or not replay actually raised the exception again, we want\n                # to print the reproduce_failure decorator for the failing example.\n                if self.settings.print_blob:\n                    fragments.append(\n                        \"\\nYou can reproduce this example by temporarily adding \"\n                        f\"{reproduction_decorator(falsifying_example.choices)} \"\n                        \"as a decorator on your test case\"\n                    )\n\n        _raise_to_user(\n            errors_to_report,\n            self.settings,\n            report_lines,\n            # A backend might report a failure and then report verified afterwards,\n            # which is to be interpreted as \"there are no more failures *other\n            # than what we already reported*\". Do not report this as unsound.\n            unsound_backend=(\n                runner._verified_by_backend\n                if runner._verified_by_backend and not runner._backend_found_failure\n                else None\n            ),\n        )\n\n\ndef _simplify_explicit_errors(errors: list[ReportableError]) -> list[ReportableError]:\n    \"\"\"\n    Group explicit example errors by their InterestingOrigin, keeping only the\n    simplest one, and adding a note of how many other examples failed with the same\n    error.\n    \"\"\"\n    by_origin: dict[InterestingOrigin, list[ReportableError]] = defaultdict(list)\n    for error in errors:\n        origin = InterestingOrigin.from_exception(error.exception)\n        by_origin[origin].append(error)\n\n    result = []\n    for group in by_origin.values():\n        if len(group) == 1:\n            result.append(group[0])\n        else:\n            # Sort by shortlex of representation (first fragment)\n            def shortlex_key(error):\n                repr_str = error.fragments[0] if error.fragments else \"\"\n                return (len(repr_str), repr_str)\n\n            sorted_group = sorted(group, key=shortlex_key)\n            simplest = sorted_group[0]\n            other_count = len(group) - 1\n            add_note(\n                simplest.exception,\n                f\"(note: {other_count} other explicit example{'s' * (other_count > 1)} \"\n                \"also failed with this error; use Verbosity.verbose to view)\",\n            )\n            result.append(simplest)\n\n    return result\n\n\ndef _raise_to_user(\n    errors_to_report, settings, target_lines, trailer=\"\", *, unsound_backend=None\n):\n    \"\"\"Helper function for attaching notes and grouping multiple errors.\"\"\"\n    failing_prefix = \"Falsifying example: \"\n    ls = []\n    for error in errors_to_report:\n        for note in error.fragments:\n            add_note(error.exception, note)\n            if note.startswith(failing_prefix):\n                ls.append(note.removeprefix(failing_prefix))\n    if current_pytest_item.value:\n        current_pytest_item.value._hypothesis_failing_examples = ls\n\n    if len(errors_to_report) == 1:\n        the_error_hypothesis_found = errors_to_report[0].exception\n    else:\n        assert errors_to_report\n        the_error_hypothesis_found = BaseExceptionGroup(\n            f\"Hypothesis found {len(errors_to_report)} distinct failures{trailer}.\",\n            [error.exception for error in errors_to_report],\n        )\n\n    if settings.verbosity >= Verbosity.normal:\n        for line in target_lines:\n            add_note(the_error_hypothesis_found, line)\n\n    if unsound_backend:\n        add_note(\n            the_error_hypothesis_found,\n            f\"backend={unsound_backend!r} claimed to verify this test passes - \"\n            \"please send them a bug report!\",\n        )\n\n    raise the_error_hypothesis_found\n\n\n@contextlib.contextmanager\ndef fake_subTest(self, msg=None, **__):\n    \"\"\"Monkeypatch for `unittest.TestCase.subTest` during `@given`.\n\n    If we don't patch this out, each failing example is reported as a\n    separate failing test by the unittest test runner, which is\n    obviously incorrect. We therefore replace it for the duration with\n    this version.\n    \"\"\"\n    warnings.warn(\n        \"subTest per-example reporting interacts badly with Hypothesis \"\n        \"trying hundreds of examples, so we disable it for the duration of \"\n        \"any test that uses `@given`.\",\n        HypothesisWarning,\n        stacklevel=2,\n    )\n    yield\n\n\n@dataclass(slots=False, frozen=False)\nclass HypothesisHandle:\n    \"\"\"This object is provided as the .hypothesis attribute on @given tests.\n\n    Downstream users can reassign its attributes to insert custom logic into\n    the execution of each case, for example by converting an async into a\n    sync function.\n\n    This must be an attribute of an attribute, because reassignment of a\n    first-level attribute would not be visible to Hypothesis if the function\n    had been decorated before the assignment.\n\n    See https://github.com/HypothesisWorks/hypothesis/issues/1257 for more\n    information.\n    \"\"\"\n\n    inner_test: Any\n    _get_fuzz_target: Any\n    _given_kwargs: Any\n\n    @property\n    def fuzz_one_input(\n        self,\n    ) -> Callable[[bytes | bytearray | memoryview | BinaryIO], bytes | None]:\n        \"\"\"\n        Run the test as a fuzz target, driven with the ``buffer`` of bytes.\n\n        Depending on the passed ``buffer`` one of three things will happen:\n\n        * If the bytestring was invalid, for example because it was too short or was\n          filtered out by |assume| or |.filter|, |fuzz_one_input| returns ``None``.\n        * If the bytestring was valid and the test passed, |fuzz_one_input| returns\n          a canonicalised and pruned bytestring which will replay that test case.\n          This is provided as an option to improve the performance of mutating\n          fuzzers, but can safely be ignored.\n        * If the test *failed*, i.e. raised an exception, |fuzz_one_input| will\n          add the pruned buffer to :ref:`the Hypothesis example database <database>`\n          and then re-raise that exception.  All you need to do to reproduce,\n          minimize, and de-duplicate all the failures found via fuzzing is run\n          your test suite!\n\n        To reduce the performance impact of database writes, |fuzz_one_input| only\n        records failing inputs which would be valid shrinks for a known failure -\n        meaning writes are somewhere between constant and log(N) rather than linear\n        in runtime.  However, this tracking only works within a persistent fuzzing\n        process; for forkserver fuzzers we recommend ``database=None`` for the main\n        run, and then replaying with a database enabled if you need to analyse\n        failures.\n\n        Note that the interpretation of both input and output bytestrings is\n        specific to the exact version of Hypothesis you are using and the strategies\n        given to the test, just like the :ref:`database <database>` and\n        |@reproduce_failure|.\n\n        Interaction with |@settings|\n        ----------------------------\n\n        |fuzz_one_input| uses just enough of Hypothesis' internals to drive your\n        test function with a bytestring, and most settings therefore have no effect\n        in this mode.  We recommend running your tests the usual way before fuzzing\n        to get the benefits of health checks, as well as afterwards to replay,\n        shrink, deduplicate, and report whatever errors were discovered.\n\n        * |settings.database| *is* used by |fuzz_one_input| - adding failures to\n          the database to be replayed when\n          you next run your tests is our preferred reporting mechanism and response\n          to `the 'fuzzer taming' problem <https://blog.regehr.org/archives/925>`__.\n        * |settings.verbosity| and |settings.stateful_step_count| work as usual.\n        * The |~settings.deadline|, |~settings.derandomize|, |~settings.max_examples|,\n          |~settings.phases|, |~settings.print_blob|, |~settings.report_multiple_bugs|,\n          and |~settings.suppress_health_check| settings do not affect |fuzz_one_input|.\n\n        Example Usage\n        -------------\n\n        .. code-block:: python\n\n            @given(st.text())\n            def test_foo(s): ...\n\n            # This is a traditional fuzz target - call it with a bytestring,\n            # or a binary IO object, and it runs the test once.\n            fuzz_target = test_foo.hypothesis.fuzz_one_input\n\n            # For example:\n            fuzz_target(b\"\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\\\\x00\")\n            fuzz_target(io.BytesIO(b\"\\\\x01\"))\n\n        .. tip::\n\n            If you expect to discover many failures while using |fuzz_one_input|,\n            consider wrapping your database with |BackgroundWriteDatabase|, for\n            low-overhead writes of failures.\n\n        .. tip::\n\n            | Want an integrated workflow for your team's local tests, CI, and continuous fuzzing?\n            | Use `HypoFuzz <https://hypofuzz.com/>`__ to fuzz your whole test suite, and find more bugs with the same tests!\n\n        .. seealso::\n\n            See also the :doc:`/how-to/external-fuzzers` how-to.\n        \"\"\"\n        # Note: most users, if they care about fuzzer performance, will access the\n        # property and assign it to a local variable to move the attribute lookup\n        # outside their fuzzing loop / before the fork point.  We cache it anyway,\n        # so that naive or unusual use-cases get the best possible performance too.\n        try:\n            return self.__cached_target  # type: ignore\n        except AttributeError:\n            self.__cached_target = self._get_fuzz_target()\n            return self.__cached_target\n\n\n@overload\ndef given(\n    _: EllipsisType, /\n) -> Callable[\n    [Callable[..., Coroutine[Any, Any, None] | None]], Callable[[], None]\n]:  # pragma: no cover\n    ...\n\n\n@overload\ndef given(\n    *_given_arguments: SearchStrategy[Any],\n) -> Callable[\n    [Callable[..., Coroutine[Any, Any, None] | None]], Callable[..., None]\n]:  # pragma: no cover\n    ...\n\n\n@overload\ndef given(\n    **_given_kwargs: SearchStrategy[Any] | EllipsisType,\n) -> Callable[\n    [Callable[..., Coroutine[Any, Any, None] | None]], Callable[..., None]\n]:  # pragma: no cover\n    ...\n\n\ndef given(\n    *_given_arguments: SearchStrategy[Any] | EllipsisType,\n    **_given_kwargs: SearchStrategy[Any] | EllipsisType,\n) -> Callable[[Callable[..., Coroutine[Any, Any, None] | None]], Callable[..., None]]:\n    \"\"\"\n    The |@given| decorator turns a function into a Hypothesis test. This is the\n    main entry point to Hypothesis.\n\n    .. seealso::\n\n        See also the :doc:`/tutorial/introduction` tutorial, which introduces\n        defining Hypothesis tests with |@given|.\n\n    .. _given-arguments:\n\n    Arguments to ``@given``\n    -----------------------\n\n    Arguments to |@given| may be either positional or keyword arguments:\n\n    .. code-block:: python\n\n        @given(st.integers(), st.floats())\n        def test_one(x, y):\n            pass\n\n        @given(x=st.integers(), y=st.floats())\n        def test_two(x, y):\n            pass\n\n    If using keyword arguments, the arguments may appear in any order, as with\n    standard Python functions:\n\n    .. code-block:: python\n\n        # different order, but still equivalent to before\n        @given(y=st.floats(), x=st.integers())\n        def test(x, y):\n            assert isinstance(x, int)\n            assert isinstance(y, float)\n\n    If |@given| is provided fewer positional arguments than the decorated test,\n    the test arguments are filled in on the right side, leaving the leftmost\n    positional arguments unfilled:\n\n    .. code-block:: python\n\n        @given(st.integers(), st.floats())\n        def test(manual_string, y, z):\n            assert manual_string == \"x\"\n            assert isinstance(y, int)\n            assert isinstance(z, float)\n\n        # `test` is now a callable which takes one argument `manual_string`\n\n        test(\"x\")\n        # or equivalently:\n        test(manual_string=\"x\")\n\n    The reason for this \"from the right\" behavior is to support using |@given|\n    with instance methods, by automatically passing through ``self``:\n\n    .. code-block:: python\n\n        class MyTest(TestCase):\n            @given(st.integers())\n            def test(self, x):\n                assert isinstance(self, MyTest)\n                assert isinstance(x, int)\n\n    If (and only if) using keyword arguments, |@given| may be combined with\n    ``**kwargs`` or ``*args``:\n\n    .. code-block:: python\n\n        @given(x=integers(), y=integers())\n        def test(x, **kwargs):\n            assert \"y\" in kwargs\n\n        @given(x=integers(), y=integers())\n        def test(x, *args, **kwargs):\n            assert args == ()\n            assert \"x\" not in kwargs\n            assert \"y\" in kwargs\n\n    It is an error to:\n\n    * Mix positional and keyword arguments to |@given|.\n    * Use |@given| with a function that has a default value for an argument.\n    * Use |@given| with positional arguments with a function that uses ``*args``,\n      ``**kwargs``, or keyword-only arguments.\n\n    The function returned by given has all the same arguments as the original\n    test, minus those that are filled in by |@given|. See the :ref:`notes on\n    framework compatibility <framework-compatibility>` for how this interacts\n    with features of other testing libraries, such as :pypi:`pytest` fixtures.\n    \"\"\"\n\n    if currently_in_test_context():\n        fail_health_check(\n            Settings(),\n            \"Nesting @given tests results in quadratic generation and shrinking \"\n            \"behavior, and can usually be more cleanly expressed by replacing the \"\n            \"inner function with an st.data() parameter on the outer @given.\"\n            \"\\n\\n\"\n            \"If it is difficult or impossible to refactor this test to remove the \"\n            \"nested @given, you can disable this health check with \"\n            \"@settings(suppress_health_check=[HealthCheck.nested_given]) on the \"\n            \"outer @given. See \"\n            \"https://hypothesis.readthedocs.io/en/latest/reference/api.html#hypothesis.HealthCheck \"\n            \"for details.\",\n            HealthCheck.nested_given,\n        )\n\n    def run_test_as_given(test):\n        if inspect.isclass(test):\n            # Provide a meaningful error to users, instead of exceptions from\n            # internals that assume we're dealing with a function.\n            raise InvalidArgument(\"@given cannot be applied to a class\")\n\n        if (\n            \"_pytest\" in sys.modules\n            and \"_pytest.fixtures\" in sys.modules\n            and (\n                tuple(map(int, sys.modules[\"_pytest\"].__version__.split(\".\")[:2]))\n                >= (8, 4)\n            )\n            and isinstance(\n                test, sys.modules[\"_pytest.fixtures\"].FixtureFunctionDefinition\n            )\n        ):  # pragma: no cover # covered by pytest/test_fixtures, but not by cover/\n            raise InvalidArgument(\"@given cannot be applied to a pytest fixture\")\n\n        given_arguments = tuple(_given_arguments)\n        given_kwargs = dict(_given_kwargs)\n\n        original_sig = get_signature(test)\n        if given_arguments == (Ellipsis,) and not given_kwargs:\n            # user indicated that they want to infer all arguments\n            given_kwargs = {\n                p.name: Ellipsis\n                for p in original_sig.parameters.values()\n                if p.kind in (p.POSITIONAL_OR_KEYWORD, p.KEYWORD_ONLY)\n            }\n            given_arguments = ()\n\n        check_invalid = is_invalid_test(\n            test, original_sig, given_arguments, given_kwargs\n        )\n\n        # If the argument check found problems, return a dummy test function\n        # that will raise an error if it is actually called.\n        if check_invalid is not None:\n            return check_invalid\n\n        # Because the argument check succeeded, we can convert @given's\n        # positional arguments into keyword arguments for simplicity.\n        if given_arguments:\n            assert not given_kwargs\n            posargs = [\n                p.name\n                for p in original_sig.parameters.values()\n                if p.kind is p.POSITIONAL_OR_KEYWORD\n            ]\n            given_kwargs = dict(\n                list(zip(posargs[::-1], given_arguments[::-1], strict=False))[::-1]\n            )\n        # These have been converted, so delete them to prevent accidental use.\n        del given_arguments\n\n        new_signature = new_given_signature(original_sig, given_kwargs)\n\n        # Use type information to convert \"infer\" arguments into appropriate strategies.\n        if ... in given_kwargs.values():\n            hints = get_type_hints(test)\n        for name in [name for name, value in given_kwargs.items() if value is ...]:\n            if name not in hints:\n                return _invalid(\n                    f\"passed {name}=... for {test.__name__}, but {name} has \"\n                    \"no type annotation\",\n                    test=test,\n                    given_kwargs=given_kwargs,\n                )\n            given_kwargs[name] = st.from_type(hints[name])\n\n        # only raise if the same thread uses two different executors, not if two\n        # different threads use different executors.\n        thread_local = ThreadLocal(prev_self=lambda: not_set)\n        # maps thread_id to whether that thread overlaps in execution with any\n        # other thread in this @given. We use this to detect whether an @given is\n        # being run from multiple different threads at once, which informs\n        # decisions like whether to raise DeadlineExceeded or HealthCheck.too_slow.\n        thread_overlap: dict[int, bool] = {}\n        thread_overlap_lock = Lock()\n\n        @impersonate(test)\n        @define_function_signature(test.__name__, test.__doc__, new_signature)\n        def wrapped_test(*arguments, **kwargs):\n            # Tell pytest to omit the body of this function from tracebacks\n            __tracebackhide__ = True\n            with thread_overlap_lock:\n                for overlap_thread_id in thread_overlap:\n                    thread_overlap[overlap_thread_id] = True\n\n                threadid = threading.get_ident()\n                # if there are existing threads when this thread starts, then\n                # this thread starts at an overlapped state.\n                has_existing_threads = len(thread_overlap) > 0\n                thread_overlap[threadid] = has_existing_threads\n\n            try:\n                test = wrapped_test.hypothesis.inner_test\n                if getattr(test, \"is_hypothesis_test\", False):\n                    raise InvalidArgument(\n                        f\"You have applied @given to the test {test.__name__} more than \"\n                        \"once, which wraps the test several times and is extremely slow. \"\n                        \"A similar effect can be gained by combining the arguments \"\n                        \"of the two calls to given. For example, instead of \"\n                        \"@given(booleans()) @given(integers()), you could write \"\n                        \"@given(booleans(), integers())\"\n                    )\n\n                settings = wrapped_test._hypothesis_internal_use_settings\n                random = get_random_for_wrapped_test(test, wrapped_test)\n                arguments, kwargs, stuff = process_arguments_to_given(\n                    wrapped_test,\n                    arguments,\n                    kwargs,\n                    given_kwargs,\n                    new_signature.parameters,\n                )\n\n                if (\n                    inspect.iscoroutinefunction(test)\n                    and get_executor(stuff.selfy) is default_executor\n                ):\n                    # See https://github.com/HypothesisWorks/hypothesis/issues/3054\n                    # If our custom executor doesn't handle coroutines, or we return an\n                    # awaitable from a non-async-def function, we just rely on the\n                    # return_value health check.  This catches most user errors though.\n                    raise InvalidArgument(\n                        \"Hypothesis doesn't know how to run async test functions like \"\n                        f\"{test.__name__}.  You'll need to write a custom executor, \"\n                        \"or use a library like pytest-asyncio or pytest-trio which can \"\n                        \"handle the translation for you.\\n    See https://hypothesis.\"\n                        \"readthedocs.io/en/latest/details.html#custom-function-execution\"\n                    )\n\n                runner = stuff.selfy\n                if isinstance(stuff.selfy, TestCase) and test.__name__ in dir(TestCase):\n                    fail_health_check(\n                        settings,\n                        f\"You have applied @given to the method {test.__name__}, which is \"\n                        \"used by the unittest runner but is not itself a test. \"\n                        \"This is not useful in any way.\",\n                        HealthCheck.not_a_test_method,\n                    )\n                if bad_django_TestCase(runner):  # pragma: no cover\n                    # Covered by the Django tests, but not the pytest coverage task\n                    raise InvalidArgument(\n                        \"You have applied @given to a method on \"\n                        f\"{type(runner).__qualname__}, but this \"\n                        \"class does not inherit from the supported versions in \"\n                        \"`hypothesis.extra.django`.  Use the Hypothesis variants \"\n                        \"to ensure that each example is run in a separate \"\n                        \"database transaction.\"\n                    )\n\n                nonlocal thread_local\n                # Check selfy really is self (not e.g. a mock) before we health-check\n                cur_self = (\n                    stuff.selfy\n                    if getattr(type(stuff.selfy), test.__name__, None) is wrapped_test\n                    else None\n                )\n                if thread_local.prev_self is not_set:\n                    thread_local.prev_self = cur_self\n                elif cur_self is not thread_local.prev_self:\n                    fail_health_check(\n                        settings,\n                        f\"The method {test.__qualname__} was called from multiple \"\n                        \"different executors. This may lead to flaky tests and \"\n                        \"nonreproducible errors when replaying from database.\"\n                        \"\\n\\n\"\n                        \"Unlike most health checks, HealthCheck.differing_executors \"\n                        \"warns about a correctness issue with your test. We \"\n                        \"therefore recommend fixing the underlying issue, rather \"\n                        \"than suppressing this health check. However, if you are \"\n                        \"confident this health check can be safely disabled, you can \"\n                        \"do so with \"\n                        \"@settings(suppress_health_check=[HealthCheck.differing_executors]). \"\n                        \"See \"\n                        \"https://hypothesis.readthedocs.io/en/latest/reference/api.html#hypothesis.HealthCheck \"\n                        \"for details.\",\n                        HealthCheck.differing_executors,\n                    )\n\n                state = StateForActualGivenExecution(\n                    stuff,\n                    test,\n                    settings,\n                    random,\n                    wrapped_test,\n                    thread_overlap=thread_overlap,\n                )\n\n                # If there was a @reproduce_failure decorator, use it to reproduce\n                # the error (or complain that we couldn't). Either way, this will\n                # always raise some kind of error.\n                if (\n                    reproduce_failure := wrapped_test._hypothesis_internal_use_reproduce_failure\n                ) is not None:\n                    expected_version, failure = reproduce_failure\n                    if expected_version != __version__:\n                        raise InvalidArgument(\n                            \"Attempting to reproduce a failure from a different \"\n                            f\"version of Hypothesis. This failure is from {expected_version}, but \"\n                            f\"you are currently running {__version__!r}. Please change your \"\n                            \"Hypothesis version to a matching one.\"\n                        )\n                    try:\n                        state.execute_once(\n                            ConjectureData.for_choices(decode_failure(failure)),\n                            print_example=True,\n                            is_final=True,\n                        )\n                        raise DidNotReproduce(\n                            \"Expected the test to raise an error, but it \"\n                            \"completed successfully.\"\n                        )\n                    except StopTest:\n                        raise DidNotReproduce(\n                            \"The shape of the test data has changed in some way \"\n                            \"from where this blob was defined. Are you sure \"\n                            \"you're running the same test?\"\n                        ) from None\n                    except UnsatisfiedAssumption:\n                        raise DidNotReproduce(\n                            \"The test data failed to satisfy an assumption in the \"\n                            \"test. Have you added it since this blob was generated?\"\n                        ) from None\n\n                # There was no @reproduce_failure, so start by running any explicit\n                # examples from @example decorators.\n                if errors := list(\n                    execute_explicit_examples(\n                        state, wrapped_test, arguments, kwargs, original_sig\n                    )\n                ):\n                    # If we're not going to report multiple bugs, we would have\n                    # stopped running explicit examples at the first failure.\n                    assert len(errors) == 1 or state.settings.report_multiple_bugs\n\n                    # If an explicit example raised a 'skip' exception, ensure it's never\n                    # wrapped up in an exception group.  Because we break out of the loop\n                    # immediately on finding a skip, if present it's always the last error.\n                    if isinstance(errors[-1].exception, skip_exceptions_to_reraise()):\n                        # Covered by `test_issue_3453_regression`, just in a subprocess.\n                        del errors[:-1]  # pragma: no cover\n\n                    if state.settings.verbosity < Verbosity.verbose:\n                        # keep only one error per interesting origin, unless\n                        # verbosity is high\n                        errors = _simplify_explicit_errors(errors)\n\n                    _raise_to_user(errors, state.settings, [], \" in explicit examples\")\n\n                # If there were any explicit examples, they all ran successfully.\n                # The next step is to use the Conjecture engine to run the test on\n                # many different inputs.\n                ran_explicit_examples = (\n                    Phase.explicit in state.settings.phases\n                    and getattr(wrapped_test, \"hypothesis_explicit_examples\", ())\n                )\n                SKIP_BECAUSE_NO_EXAMPLES = unittest.SkipTest(\n                    \"Hypothesis has been told to run no examples for this test.\"\n                )\n                if not (\n                    Phase.reuse in settings.phases or Phase.generate in settings.phases\n                ):\n                    if not ran_explicit_examples:\n                        raise SKIP_BECAUSE_NO_EXAMPLES\n                    return\n\n                try:\n                    if isinstance(runner, TestCase) and hasattr(runner, \"subTest\"):\n                        subTest = runner.subTest\n                        try:\n                            runner.subTest = types.MethodType(fake_subTest, runner)\n                            state.run_engine()\n                        finally:\n                            runner.subTest = subTest\n                    else:\n                        state.run_engine()\n                except BaseException as e:\n                    # The exception caught here should either be an actual test\n                    # failure (or BaseExceptionGroup), or some kind of fatal error\n                    # that caused the engine to stop.\n                    generated_seed = (\n                        wrapped_test._hypothesis_internal_use_generated_seed\n                    )\n                    with local_settings(settings):\n                        if not (state.failed_normally or generated_seed is None):\n                            if running_under_pytest:\n                                report(\n                                    f\"You can add @seed({generated_seed}) to this test or \"\n                                    f\"run pytest with --hypothesis-seed={generated_seed} \"\n                                    \"to reproduce this failure.\"\n                                )\n                            else:\n                                report(\n                                    f\"You can add @seed({generated_seed}) to this test to \"\n                                    \"reproduce this failure.\"\n                                )\n                        # The dance here is to avoid showing users long tracebacks\n                        # full of Hypothesis internals they don't care about.\n                        # We have to do this inline, to avoid adding another\n                        # internal stack frame just when we've removed the rest.\n                        #\n                        # Using a variable for our trimmed error ensures that the line\n                        # which will actually appear in tracebacks is as clear as\n                        # possible - \"raise the_error_hypothesis_found\".\n                        the_error_hypothesis_found = e.with_traceback(\n                            None\n                            if isinstance(e, BaseExceptionGroup)\n                            else get_trimmed_traceback()\n                        )\n                        raise the_error_hypothesis_found\n\n                if not (ran_explicit_examples or state.ever_executed):\n                    raise SKIP_BECAUSE_NO_EXAMPLES\n            finally:\n                with thread_overlap_lock:\n                    del thread_overlap[threadid]\n\n        def _get_fuzz_target() -> (\n            Callable[[bytes | bytearray | memoryview | BinaryIO], bytes | None]\n        ):\n            # Because fuzzing interfaces are very performance-sensitive, we use a\n            # somewhat more complicated structure here.  `_get_fuzz_target()` is\n            # called by the `HypothesisHandle.fuzz_one_input` property, allowing\n            # us to defer our collection of the settings, random instance, and\n            # reassignable `inner_test` (etc) until `fuzz_one_input` is accessed.\n            #\n            # We then share the performance cost of setting up `state` between\n            # many invocations of the target.  We explicitly force `deadline=None`\n            # for performance reasons, saving ~40% the runtime of an empty test.\n            test = wrapped_test.hypothesis.inner_test\n            settings = Settings(\n                parent=wrapped_test._hypothesis_internal_use_settings, deadline=None\n            )\n            random = get_random_for_wrapped_test(test, wrapped_test)\n            _args, _kwargs, stuff = process_arguments_to_given(\n                wrapped_test, (), {}, given_kwargs, new_signature.parameters\n            )\n            assert not _args\n            assert not _kwargs\n            state = StateForActualGivenExecution(\n                stuff,\n                test,\n                settings,\n                random,\n                wrapped_test,\n                thread_overlap=thread_overlap,\n            )\n            database_key = function_digest(test) + b\".secondary\"\n            # We track the minimal-so-far example for each distinct origin, so\n            # that we track log-n instead of n examples for long runs.  In particular\n            # it means that we saturate for common errors in long runs instead of\n            # storing huge volumes of low-value data.\n            minimal_failures: dict = {}\n\n            def fuzz_one_input(\n                buffer: bytes | bytearray | memoryview | BinaryIO,\n            ) -> bytes | None:\n                # This inner part is all that the fuzzer will actually run,\n                # so we keep it as small and as fast as possible.\n                if isinstance(buffer, io.IOBase):\n                    buffer = buffer.read(BUFFER_SIZE)\n                assert isinstance(buffer, (bytes, bytearray, memoryview))\n                data = ConjectureData(\n                    random=None,\n                    provider=BytestringProvider,\n                    provider_kw={\"bytestring\": buffer},\n                )\n                try:\n                    state.execute_once(data)\n                    status = Status.VALID\n                except StopTest:\n                    status = data.status\n                    return None\n                except UnsatisfiedAssumption:\n                    status = Status.INVALID\n                    return None\n                except BaseException:\n                    known = minimal_failures.get(data.interesting_origin)\n                    if settings.database is not None and (\n                        known is None or sort_key(data.nodes) <= sort_key(known)\n                    ):\n                        settings.database.save(\n                            database_key, choices_to_bytes(data.choices)\n                        )\n                        minimal_failures[data.interesting_origin] = data.nodes\n                    status = Status.INTERESTING\n                    raise\n                finally:\n                    if observability_enabled():\n                        data.freeze()\n                        tc = make_testcase(\n                            run_start=state._start_timestamp,\n                            property=state.test_identifier,\n                            data=data,\n                            how_generated=\"fuzz_one_input\",\n                            representation=state._string_repr,\n                            arguments=data._observability_args,\n                            timing=state._timing_features,\n                            coverage=None,\n                            status=status,\n                            backend_metadata=data.provider.observe_test_case(),\n                        )\n                        deliver_observation(tc)\n                        state._timing_features = {}\n\n                assert isinstance(data.provider, BytestringProvider)\n                return bytes(data.provider.drawn)\n\n            fuzz_one_input.__doc__ = HypothesisHandle.fuzz_one_input.__doc__\n            return fuzz_one_input\n\n        # After having created the decorated test function, we need to copy\n        # over some attributes to make the switch as seamless as possible.\n\n        for attrib in dir(test):\n            if not (attrib.startswith(\"_\") or hasattr(wrapped_test, attrib)):\n                setattr(wrapped_test, attrib, getattr(test, attrib))\n        wrapped_test.is_hypothesis_test = True\n        if hasattr(test, \"_hypothesis_internal_settings_applied\"):\n            # Used to check if @settings is applied twice.\n            wrapped_test._hypothesis_internal_settings_applied = True\n        wrapped_test._hypothesis_internal_use_seed = getattr(\n            test, \"_hypothesis_internal_use_seed\", None\n        )\n        wrapped_test._hypothesis_internal_use_settings = (\n            getattr(test, \"_hypothesis_internal_use_settings\", None) or Settings.default\n        )\n        wrapped_test._hypothesis_internal_use_reproduce_failure = getattr(\n            test, \"_hypothesis_internal_use_reproduce_failure\", None\n        )\n        wrapped_test.hypothesis = HypothesisHandle(test, _get_fuzz_target, given_kwargs)\n        return wrapped_test\n\n    return run_test_as_given\n\n\ndef find(\n    specifier: SearchStrategy[Ex],\n    condition: Callable[[Any], bool],\n    *,\n    settings: Settings | None = None,\n    random: Random | None = None,\n    database_key: bytes | None = None,\n) -> Ex:\n    \"\"\"Returns the minimal example from the given strategy ``specifier`` that\n    matches the predicate function ``condition``.\"\"\"\n    if settings is None:\n        settings = Settings(max_examples=2000)\n    settings = Settings(\n        settings, suppress_health_check=list(HealthCheck), report_multiple_bugs=False\n    )\n\n    if database_key is None and settings.database is not None:\n        # Note: The database key is not guaranteed to be unique. If not, replaying\n        # of database examples may fail to reproduce due to being replayed on the\n        # wrong condition.\n        database_key = function_digest(condition)\n\n    if not isinstance(specifier, SearchStrategy):\n        raise InvalidArgument(\n            f\"Expected SearchStrategy but got {specifier!r} of \"\n            f\"type {type(specifier).__name__}\"\n        )\n    specifier.validate()\n\n    last: list[Ex] = []\n\n    @settings\n    @given(specifier)\n    def test(v):\n        if condition(v):\n            last[:] = [v]\n            raise Found\n\n    if random is not None:\n        test = seed(random.getrandbits(64))(test)\n\n    test._hypothesis_internal_database_key = database_key  # type: ignore\n\n    try:\n        test()\n    except Found:\n        return last[0]\n\n    raise NoSuchExample(get_pretty_function_description(condition))\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/database.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport abc\nimport errno\nimport json\nimport os\nimport struct\nimport sys\nimport tempfile\nimport warnings\nimport weakref\nfrom collections.abc import Callable, Iterable\nfrom datetime import datetime, timedelta, timezone\nfrom functools import lru_cache\nfrom hashlib import sha384\nfrom os import PathLike, getenv\nfrom pathlib import Path, PurePath\nfrom queue import Queue\nfrom threading import Thread\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    ClassVar,\n    Literal,\n    TypeAlias,\n    cast,\n)\nfrom urllib.error import HTTPError, URLError\nfrom urllib.request import Request, urlopen\nfrom zipfile import BadZipFile, ZipFile\n\nfrom hypothesis.configuration import storage_directory\nfrom hypothesis.errors import HypothesisException, HypothesisWarning\nfrom hypothesis.internal.conjecture.choice import ChoiceT\nfrom hypothesis.utils.conventions import UniqueIdentifier, not_set\nfrom hypothesis.utils.deprecation import note_deprecation\n\n__all__ = [\n    \"DirectoryBasedExampleDatabase\",\n    \"ExampleDatabase\",\n    \"GitHubArtifactDatabase\",\n    \"InMemoryExampleDatabase\",\n    \"MultiplexedDatabase\",\n    \"ReadOnlyDatabase\",\n]\n\nif TYPE_CHECKING:\n    from watchdog.observers.api import BaseObserver\n\nStrPathT: TypeAlias = str | PathLike[str]\nSaveDataT: TypeAlias = tuple[bytes, bytes]  # key, value\nDeleteDataT: TypeAlias = tuple[bytes, bytes | None]  # key, value\nListenerEventT: TypeAlias = (\n    tuple[Literal[\"save\"], SaveDataT] | tuple[Literal[\"delete\"], DeleteDataT]\n)\nListenerT: TypeAlias = Callable[[ListenerEventT], Any]\n\n\ndef _usable_dir(path: StrPathT) -> bool:\n    \"\"\"\n    Returns True if the desired path can be used as database path because\n    either the directory exists and can be used, or its root directory can\n    be used and we can make the directory as needed.\n    \"\"\"\n    path = Path(path)\n    try:\n        while not path.exists():\n            # Loop terminates because the root dir ('/' on unix) always exists.\n            path = path.parent\n        return path.is_dir() and os.access(path, os.R_OK | os.W_OK | os.X_OK)\n    except PermissionError:  # pragma: no cover\n        # path.exists() returns False on 3.14+ instead of raising. See\n        # https://docs.python.org/3.14/library/pathlib.html#querying-file-type-and-status\n        return False\n\n\ndef _db_for_path(\n    path: StrPathT | UniqueIdentifier | Literal[\":memory:\"] | None = None,\n) -> \"ExampleDatabase\":\n    if path is not_set:\n        if os.getenv(\"HYPOTHESIS_DATABASE_FILE\") is not None:  # pragma: no cover\n            raise HypothesisException(\n                \"The $HYPOTHESIS_DATABASE_FILE environment variable no longer has any \"\n                \"effect.  Configure your database location via a settings profile instead.\\n\"\n                \"https://hypothesis.readthedocs.io/en/latest/settings.html#settings-profiles\"\n            )\n\n        path = storage_directory(\"examples\", intent_to_write=False)\n        if not _usable_dir(path):  # pragma: no cover\n            warnings.warn(\n                \"The database setting is not configured, and the default \"\n                \"location is unusable - falling back to an in-memory \"\n                f\"database for this session.  {path=}\",\n                HypothesisWarning,\n                stacklevel=3,\n            )\n            return InMemoryExampleDatabase()\n    if path in (None, \":memory:\"):\n        return InMemoryExampleDatabase()\n    path = cast(StrPathT, path)\n    return DirectoryBasedExampleDatabase(path)\n\n\nclass _EDMeta(abc.ABCMeta):\n    def __call__(self, *args: Any, **kwargs: Any) -> \"ExampleDatabase\":\n        if self is ExampleDatabase:\n            note_deprecation(\n                \"Creating a database using the abstract ExampleDatabase() class \"\n                \"is deprecated. Prefer using a concrete subclass, like \"\n                \"InMemoryExampleDatabase() or DirectoryBasedExampleDatabase(path). \"\n                'In particular, the special string ExampleDatabase(\":memory:\") '\n                \"should be replaced by InMemoryExampleDatabase().\",\n                since=\"2025-04-07\",\n                has_codemod=False,\n            )\n            return _db_for_path(*args, **kwargs)\n        return super().__call__(*args, **kwargs)\n\n\n# This __call__ method is picked up by Sphinx as the signature of all ExampleDatabase\n# subclasses, which is accurate, reasonable, and unhelpful.  Fortunately Sphinx\n# maintains a list of metaclass-call-methods to ignore, and while they would prefer\n# not to maintain it upstream (https://github.com/sphinx-doc/sphinx/pull/8262) we\n# can insert ourselves here.\n#\n# This code only runs if Sphinx has already been imported; and it would live in our\n# docs/conf.py except that we would also like it to work for anyone documenting\n# downstream ExampleDatabase subclasses too.\n#\n# We avoid type-checking this block due to this combination facts:\n# * our check-types-api CI job runs under 3.14\n# * tools.txt therefore pins to a newer version of sphinx which uses 3.12+ `type`\n#   syntax\n# * in test_mypy.py, mypy sees this block, sees sphinx is installed, tries parsing\n#   sphinx code, and errors\n#\n# Putting `and not TYPE_CHECKING` here is just a convenience for our testing setup\n# (because we don't split mypy tests by running CI version, eg), not for runtime\n#  behavior.\nif \"sphinx\" in sys.modules and not TYPE_CHECKING:  # pragma: no cover\n    try:\n        import sphinx.ext.autodoc\n\n        signature = \"hypothesis.database._EDMeta.__call__\"\n\n        # _METACLASS_CALL_BLACKLIST moved in newer sphinx versions\n        try:\n            import sphinx.ext.autodoc._dynamic._signatures as _module\n        except ImportError:\n            _module = sphinx.ext.autodoc\n\n        # _METACLASS_CALL_BLACKLIST is a frozenset in later sphinx versions\n        if isinstance(_module._METACLASS_CALL_BLACKLIST, frozenset):\n            _module._METACLASS_CALL_BLACKLIST = _module._METACLASS_CALL_BLACKLIST | {\n                signature\n            }\n        else:\n            _module._METACLASS_CALL_BLACKLIST.append(signature)\n    except Exception:\n        pass\n\n\nclass ExampleDatabase(metaclass=_EDMeta):\n    \"\"\"\n    A Hypothesis database, for use in |settings.database|.\n\n    Hypothesis automatically saves failures to the database set in\n    |settings.database|. The next time the test is run, Hypothesis will replay\n    any failures from the database in |settings.database| for that test (in\n    |Phase.reuse|).\n\n    The database is best thought of as a cache that you never need to invalidate.\n    Entries may be transparently dropped when upgrading your Hypothesis version\n    or changing your test. Do not rely on the database for correctness; to ensure\n    Hypothesis always tries an input, use |@example|.\n\n    A Hypothesis database is a simple mapping of bytes to sets of bytes. Hypothesis\n    provides several concrete database subclasses. To write your own database class,\n    see :doc:`/how-to/custom-database`.\n\n    Change listening\n    ----------------\n\n    An optional extension to |ExampleDatabase| is change listening. On databases\n    which support change listening, calling |ExampleDatabase.add_listener| adds\n    a function as a change listener, which will be called whenever a value is\n    added, deleted, or moved inside the database. See |ExampleDatabase.add_listener|\n    for details.\n\n    All databases in Hypothesis support change listening. Custom database classes\n    are not required to support change listening, though they will not be compatible\n    with features that require change listening until they do so.\n\n    .. note::\n\n        While no Hypothesis features currently require change listening, change\n        listening is required by `HypoFuzz <https://hypofuzz.com/>`_.\n\n    Database methods\n    ----------------\n\n    Required methods:\n\n    * |ExampleDatabase.save|\n    * |ExampleDatabase.fetch|\n    * |ExampleDatabase.delete|\n\n    Optional methods:\n\n    * |ExampleDatabase.move|\n\n    Change listening methods:\n\n    * |ExampleDatabase.add_listener|\n    * |ExampleDatabase.remove_listener|\n    * |ExampleDatabase.clear_listeners|\n    * |ExampleDatabase._start_listening|\n    * |ExampleDatabase._stop_listening|\n    * |ExampleDatabase._broadcast_change|\n    \"\"\"\n\n    def __init__(self) -> None:\n        self._listeners: list[ListenerT] = []\n\n    @abc.abstractmethod\n    def save(self, key: bytes, value: bytes) -> None:\n        \"\"\"Save ``value`` under ``key``.\n\n        If ``value`` is already present in ``key``, silently do nothing.\n        \"\"\"\n        raise NotImplementedError(f\"{type(self).__name__}.save\")\n\n    @abc.abstractmethod\n    def fetch(self, key: bytes) -> Iterable[bytes]:\n        \"\"\"Return an iterable over all values matching this key.\"\"\"\n        raise NotImplementedError(f\"{type(self).__name__}.fetch\")\n\n    @abc.abstractmethod\n    def delete(self, key: bytes, value: bytes) -> None:\n        \"\"\"Remove ``value`` from ``key``.\n\n        If ``value`` is not present in ``key``, silently do nothing.\n        \"\"\"\n        raise NotImplementedError(f\"{type(self).__name__}.delete\")\n\n    def move(self, src: bytes, dest: bytes, value: bytes) -> None:\n        \"\"\"\n        Move ``value`` from key ``src`` to key ``dest``.\n\n        Equivalent to ``delete(src, value)`` followed by ``save(src, value)``,\n        but may have a more efficient implementation.\n\n        Note that ``value`` will be inserted at ``dest`` regardless of whether\n        it is currently present at ``src``.\n        \"\"\"\n        if src == dest:\n            self.save(src, value)\n            return\n        self.delete(src, value)\n        self.save(dest, value)\n\n    def add_listener(self, f: ListenerT, /) -> None:\n        \"\"\"\n        Add a change listener. ``f`` will be called whenever a value is saved,\n        deleted, or moved in the database.\n\n        ``f`` can be called with two different event values:\n\n        * ``(\"save\", (key, value))``\n        * ``(\"delete\", (key, value))``\n\n        where ``key`` and ``value`` are both ``bytes``.\n\n        There is no ``move`` event. Instead, a move is broadcasted as a\n        ``delete`` event followed by a ``save`` event.\n\n        For the ``delete`` event, ``value`` may be ``None``. This might occur if\n        the database knows that a deletion has occurred in ``key``, but does not\n        know what value was deleted.\n        \"\"\"\n        had_listeners = bool(self._listeners)\n        self._listeners.append(f)\n        if not had_listeners:\n            self._start_listening()\n\n    def remove_listener(self, f: ListenerT, /) -> None:\n        \"\"\"\n        Removes ``f`` from the list of change listeners.\n\n        If ``f`` is not in the list of change listeners, silently do nothing.\n        \"\"\"\n        if f not in self._listeners:\n            return\n        self._listeners.remove(f)\n        if not self._listeners:\n            self._stop_listening()\n\n    def clear_listeners(self) -> None:\n        \"\"\"Remove all change listeners.\"\"\"\n        had_listeners = bool(self._listeners)\n        self._listeners.clear()\n        if had_listeners:\n            self._stop_listening()\n\n    def _broadcast_change(self, event: ListenerEventT) -> None:\n        \"\"\"\n        Called when a value has been either added to or deleted from a key in\n        the underlying database store. The possible values for ``event`` are:\n\n        * ``(\"save\", (key, value))``\n        * ``(\"delete\", (key, value))``\n\n        ``value`` may be ``None`` for the ``delete`` event, indicating we know\n        that some value was deleted under this key, but not its exact value.\n\n        Note that you should not assume your instance is the only reference to\n        the underlying database store. For example, if two instances of\n        |DirectoryBasedExampleDatabase| reference the same directory,\n        _broadcast_change should be called whenever a file is added or removed\n        from the directory, even if that database was not responsible for\n        changing the file.\n        \"\"\"\n        for listener in self._listeners:\n            listener(event)\n\n    def _start_listening(self) -> None:\n        \"\"\"\n        Called when the database adds a change listener, and did not previously\n        have any change listeners. Intended to allow databases to wait to start\n        expensive listening operations until necessary.\n\n        ``_start_listening`` and ``_stop_listening`` are guaranteed to alternate,\n        so you do not need to handle the case of multiple consecutive\n        ``_start_listening`` calls without an intermediate ``_stop_listening``\n        call.\n        \"\"\"\n        warnings.warn(\n            f\"{self.__class__} does not support listening for changes\",\n            HypothesisWarning,\n            stacklevel=4,\n        )\n\n    def _stop_listening(self) -> None:\n        \"\"\"\n        Called whenever no change listeners remain on the database.\n\n        ``_stop_listening`` and ``_start_listening`` are guaranteed to alternate,\n        so you do not need to handle the case of multiple consecutive\n        ``_stop_listening`` calls without an intermediate ``_start_listening``\n        call.\n        \"\"\"\n        warnings.warn(\n            f\"{self.__class__} does not support stopping listening for changes\",\n            HypothesisWarning,\n            stacklevel=4,\n        )\n\n\nclass InMemoryExampleDatabase(ExampleDatabase):\n    \"\"\"A non-persistent example database, implemented in terms of an in-memory\n    dictionary.\n\n    This can be useful if you call a test function several times in a single\n    session, or for testing other database implementations, but because it\n    does not persist between runs we do not recommend it for general use.\n    \"\"\"\n\n    def __init__(self) -> None:\n        super().__init__()\n        self.data: dict[bytes, set[bytes]] = {}\n\n    def __repr__(self) -> str:\n        return f\"InMemoryExampleDatabase({self.data!r})\"\n\n    def __eq__(self, other: object) -> bool:\n        return isinstance(other, InMemoryExampleDatabase) and self.data is other.data\n\n    def fetch(self, key: bytes) -> Iterable[bytes]:\n        yield from self.data.get(key, ())\n\n    def save(self, key: bytes, value: bytes) -> None:\n        value = bytes(value)\n        values = self.data.setdefault(key, set())\n        changed = value not in values\n        values.add(value)\n\n        if changed:\n            self._broadcast_change((\"save\", (key, value)))\n\n    def delete(self, key: bytes, value: bytes) -> None:\n        value = bytes(value)\n        values = self.data.get(key, set())\n        changed = value in values\n        values.discard(value)\n\n        if changed:\n            self._broadcast_change((\"delete\", (key, value)))\n\n    def _start_listening(self) -> None:\n        # declare compatibility with the listener api, but do the actual\n        # implementation in .delete and .save, since we know we are the only\n        # writer to .data.\n        pass\n\n    def _stop_listening(self) -> None:\n        pass\n\n\ndef _hash(key: bytes) -> str:\n    return sha384(key).hexdigest()[:16]\n\n\nclass DirectoryBasedExampleDatabase(ExampleDatabase):\n    \"\"\"Use a directory to store Hypothesis examples as files.\n\n    Each test corresponds to a directory, and each example to a file within that\n    directory.  While the contents are fairly opaque, a\n    |DirectoryBasedExampleDatabase| can be shared by checking the directory\n    into version control, for example with the following ``.gitignore``::\n\n        # Ignore files cached by Hypothesis...\n        .hypothesis/*\n        # except for the examples directory\n        !.hypothesis/examples/\n\n    Note however that this only makes sense if you also pin to an exact version of\n    Hypothesis, and we would usually recommend implementing a shared database with\n    a network datastore - see |ExampleDatabase|, and the |MultiplexedDatabase| helper.\n    \"\"\"\n\n    # we keep a database entry of the full values of all the database keys.\n    # currently only used for inverse mapping of hash -> key in change listening.\n    _metakeys_name: ClassVar[bytes] = b\".hypothesis-keys\"\n    _metakeys_hash: ClassVar[str] = _hash(_metakeys_name)\n\n    def __init__(self, path: StrPathT) -> None:\n        super().__init__()\n        self.path = Path(path)\n        self.keypaths: dict[bytes, Path] = {}\n        self._observer: BaseObserver | None = None\n\n    def __repr__(self) -> str:\n        return f\"DirectoryBasedExampleDatabase({self.path!r})\"\n\n    def __eq__(self, other: object) -> bool:\n        return (\n            isinstance(other, DirectoryBasedExampleDatabase) and self.path == other.path\n        )\n\n    def _key_path(self, key: bytes) -> Path:\n        try:\n            return self.keypaths[key]\n        except KeyError:\n            pass\n        self.keypaths[key] = self.path / _hash(key)\n        return self.keypaths[key]\n\n    def _value_path(self, key: bytes, value: bytes) -> Path:\n        return self._key_path(key) / _hash(value)\n\n    def fetch(self, key: bytes) -> Iterable[bytes]:\n        kp = self._key_path(key)\n        if not kp.is_dir():\n            return\n\n        try:\n            for path in os.listdir(kp):\n                try:\n                    yield (kp / path).read_bytes()\n                except OSError:\n                    pass\n        except OSError:  # pragma: no cover\n            # the `kp` directory might have been deleted in the meantime\n            pass\n\n    def save(self, key: bytes, value: bytes) -> None:\n        key_path = self._key_path(key)\n        if key_path.name != self._metakeys_hash:\n            # add this key to our meta entry of all keys - taking care to avoid\n            # infinite recursion.\n            self.save(self._metakeys_name, key)\n\n        # Note: we attempt to create the dir in question now. We\n        # already checked for permissions, but there can still be other issues,\n        # e.g. the disk is full, or permissions might have been changed.\n        try:\n            key_path.mkdir(exist_ok=True, parents=True)\n            path = self._value_path(key, value)\n            if not path.exists():\n                # to mimic an atomic write, create and write in a temporary\n                # directory, and only move to the final path after. This avoids\n                # any intermediate state where the file is created (and empty)\n                # but not yet written to.\n                fd, tmpname = tempfile.mkstemp()\n                tmppath = Path(tmpname)\n                os.write(fd, value)\n                os.close(fd)\n                try:\n                    tmppath.rename(path)\n                except OSError as err:  # pragma: no cover\n                    if err.errno == errno.EXDEV:\n                        # Can't rename across filesystem boundaries, see e.g.\n                        # https://github.com/HypothesisWorks/hypothesis/issues/4335\n                        try:\n                            path.write_bytes(tmppath.read_bytes())\n                        except OSError:\n                            pass\n                    tmppath.unlink()\n                assert not tmppath.exists()\n        except OSError:  # pragma: no cover\n            pass\n\n    def move(self, src: bytes, dest: bytes, value: bytes) -> None:\n        if src == dest:\n            self.save(src, value)\n            return\n\n        src_path = self._value_path(src, value)\n        dest_path = self._value_path(dest, value)\n        # if the dest key path does not exist, os.renames will create it for us,\n        # and we will never track its creation in the meta keys entry. Do so now.\n        if not self._key_path(dest).exists():\n            self.save(self._metakeys_name, dest)\n\n        try:\n            os.renames(src_path, dest_path)\n        except OSError:\n            self.delete(src, value)\n            self.save(dest, value)\n\n    def delete(self, key: bytes, value: bytes) -> None:\n        try:\n            self._value_path(key, value).unlink()\n        except OSError:\n            return\n\n        # try deleting the key dir, which will only succeed if the dir is empty\n        # (i.e. ``value`` was the last value in this key).\n        try:\n            self._key_path(key).rmdir()\n        except OSError:\n            pass\n        else:\n            # if the deletion succeeded, also delete this key entry from metakeys.\n            # (if this key happens to be the metakey itself, this deletion will\n            # fail; that's ok and faster than checking for this rare case.)\n            self.delete(self._metakeys_name, key)\n\n    def _start_listening(self) -> None:\n        try:\n            from watchdog.events import (\n                DirCreatedEvent,\n                DirDeletedEvent,\n                DirMovedEvent,\n                FileCreatedEvent,\n                FileDeletedEvent,\n                FileMovedEvent,\n                FileSystemEventHandler,\n            )\n            from watchdog.observers import Observer\n        except ImportError:\n            warnings.warn(\n                f\"listening for changes in a {self.__class__.__name__} \"\n                \"requires the watchdog library. To install, run \"\n                \"`pip install hypothesis[watchdog]`\",\n                HypothesisWarning,\n                stacklevel=4,\n            )\n            return\n\n        hash_to_key = {_hash(key): key for key in self.fetch(self._metakeys_name)}\n        _metakeys_hash = self._metakeys_hash\n        _broadcast_change = self._broadcast_change\n\n        class Handler(\n            FileSystemEventHandler\n        ):  # pragma: no cover # skipped in test_database.py for now\n            def on_created(_self, event: FileCreatedEvent | DirCreatedEvent) -> None:\n                # we only registered for the file creation event\n                assert not isinstance(event, DirCreatedEvent)\n                # watchdog events are only bytes if we passed a byte path to\n                # .schedule\n                assert isinstance(event.src_path, str)\n\n                value_path = Path(event.src_path)\n                # the parent dir represents the key, and its name is the key hash\n                key_hash = value_path.parent.name\n\n                if key_hash == _metakeys_hash:\n                    try:\n                        hash_to_key[value_path.name] = value_path.read_bytes()\n                    except OSError:  # pragma: no cover\n                        # this might occur if all the values in a key have been\n                        # deleted and DirectoryBasedExampleDatabase removes its\n                        # metakeys entry (which is `value_path` here`).\n                        pass\n                    return\n\n                key = hash_to_key.get(key_hash)\n                if key is None:  # pragma: no cover\n                    # we didn't recognize this key. This shouldn't ever happen,\n                    # but some race condition trickery might cause this.\n                    return\n\n                try:\n                    value = value_path.read_bytes()\n                except OSError:  # pragma: no cover\n                    return\n\n                _broadcast_change((\"save\", (key, value)))\n\n            def on_deleted(self, event: FileDeletedEvent | DirDeletedEvent) -> None:\n                assert not isinstance(event, DirDeletedEvent)\n                assert isinstance(event.src_path, str)\n\n                value_path = Path(event.src_path)\n                key = hash_to_key.get(value_path.parent.name)\n                if key is None:  # pragma: no cover\n                    return\n\n                _broadcast_change((\"delete\", (key, None)))\n\n            def on_moved(self, event: FileMovedEvent | DirMovedEvent) -> None:\n                assert not isinstance(event, DirMovedEvent)\n                assert isinstance(event.src_path, str)\n                assert isinstance(event.dest_path, str)\n\n                src_path = Path(event.src_path)\n                dest_path = Path(event.dest_path)\n                k1 = hash_to_key.get(src_path.parent.name)\n                k2 = hash_to_key.get(dest_path.parent.name)\n\n                if k1 is None or k2 is None:  # pragma: no cover\n                    return\n\n                try:\n                    value = dest_path.read_bytes()\n                except OSError:  # pragma: no cover\n                    return\n\n                _broadcast_change((\"delete\", (k1, value)))\n                _broadcast_change((\"save\", (k2, value)))\n\n        # If we add a listener to a DirectoryBasedExampleDatabase whose database\n        # directory doesn't yet exist, the watchdog observer will not fire any\n        # events, even after the directory gets created.\n        #\n        # Ensure the directory exists before starting the observer.\n        self.path.mkdir(exist_ok=True, parents=True)\n        self._observer = Observer()\n        self._observer.schedule(\n            Handler(),\n            # remove type: ignore when released\n            # https://github.com/gorakhargosh/watchdog/pull/1096\n            self.path,  # type: ignore\n            recursive=True,\n            event_filter=[FileCreatedEvent, FileDeletedEvent, FileMovedEvent],\n        )\n        self._observer.start()\n\n    def _stop_listening(self) -> None:\n        assert self._observer is not None\n        self._observer.stop()\n        self._observer.join()\n        self._observer = None\n\n\nclass ReadOnlyDatabase(ExampleDatabase):\n    \"\"\"A wrapper to make the given database read-only.\n\n    The implementation passes through ``fetch``, and turns ``save``, ``delete``, and\n    ``move`` into silent no-ops.\n\n    Note that this disables Hypothesis' automatic discarding of stale examples.\n    It is designed to allow local machines to access a shared database (e.g. from CI\n    servers), without propagating changes back from a local or in-development branch.\n    \"\"\"\n\n    def __init__(self, db: ExampleDatabase) -> None:\n        super().__init__()\n        assert isinstance(db, ExampleDatabase)\n        self._wrapped = db\n\n    def __repr__(self) -> str:\n        return f\"ReadOnlyDatabase({self._wrapped!r})\"\n\n    def __eq__(self, other: object) -> bool:\n        return isinstance(other, ReadOnlyDatabase) and self._wrapped == other._wrapped\n\n    def fetch(self, key: bytes) -> Iterable[bytes]:\n        yield from self._wrapped.fetch(key)\n\n    def save(self, key: bytes, value: bytes) -> None:\n        pass\n\n    def delete(self, key: bytes, value: bytes) -> None:\n        pass\n\n    def _start_listening(self) -> None:\n        # we're read only, so there are no changes to broadcast.\n        pass\n\n    def _stop_listening(self) -> None:\n        pass\n\n\nclass MultiplexedDatabase(ExampleDatabase):\n    \"\"\"A wrapper around multiple databases.\n\n    Each ``save``, ``fetch``, ``move``, or ``delete`` operation will be run against\n    all of the wrapped databases.  ``fetch`` does not yield duplicate values, even\n    if the same value is present in two or more of the wrapped databases.\n\n    This combines well with a :class:`ReadOnlyDatabase`, as follows:\n\n    .. code-block:: python\n\n        local = DirectoryBasedExampleDatabase(\"/tmp/hypothesis/examples/\")\n        shared = CustomNetworkDatabase()\n\n        settings.register_profile(\"ci\", database=shared)\n        settings.register_profile(\n            \"dev\", database=MultiplexedDatabase(local, ReadOnlyDatabase(shared))\n        )\n        settings.load_profile(\"ci\" if os.environ.get(\"CI\") else \"dev\")\n\n    So your CI system or fuzzing runs can populate a central shared database;\n    while local runs on development machines can reproduce any failures from CI\n    but will only cache their own failures locally and cannot remove examples\n    from the shared database.\n    \"\"\"\n\n    def __init__(self, *dbs: ExampleDatabase) -> None:\n        super().__init__()\n        assert all(isinstance(db, ExampleDatabase) for db in dbs)\n        self._wrapped = dbs\n\n    def __repr__(self) -> str:\n        return \"MultiplexedDatabase({})\".format(\", \".join(map(repr, self._wrapped)))\n\n    def __eq__(self, other: object) -> bool:\n        return (\n            isinstance(other, MultiplexedDatabase) and self._wrapped == other._wrapped\n        )\n\n    def fetch(self, key: bytes) -> Iterable[bytes]:\n        seen = set()\n        for db in self._wrapped:\n            for value in db.fetch(key):\n                if value not in seen:\n                    yield value\n                    seen.add(value)\n\n    def save(self, key: bytes, value: bytes) -> None:\n        for db in self._wrapped:\n            db.save(key, value)\n\n    def delete(self, key: bytes, value: bytes) -> None:\n        for db in self._wrapped:\n            db.delete(key, value)\n\n    def move(self, src: bytes, dest: bytes, value: bytes) -> None:\n        for db in self._wrapped:\n            db.move(src, dest, value)\n\n    def _start_listening(self) -> None:\n        for db in self._wrapped:\n            db.add_listener(self._broadcast_change)\n\n    def _stop_listening(self) -> None:\n        for db in self._wrapped:\n            db.remove_listener(self._broadcast_change)\n\n\nclass GitHubArtifactDatabase(ExampleDatabase):\n    \"\"\"\n    A file-based database loaded from a `GitHub Actions <https://docs.github.com/en/actions>`_ artifact.\n\n    You can use this for sharing example databases between CI runs and developers, allowing\n    the latter to get read-only access to the former. This is particularly useful for\n    continuous fuzzing (i.e. with `HypoFuzz <https://hypofuzz.com/>`_),\n    where the CI system can help find new failing examples through fuzzing,\n    and developers can reproduce them locally without any manual effort.\n\n    .. note::\n        You must provide ``GITHUB_TOKEN`` as an environment variable. In CI, Github Actions provides\n        this automatically, but it needs to be set manually for local usage. In a developer machine,\n        this would usually be a `Personal Access Token <https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens>`_.\n        If the repository is private, it's necessary for the token to have ``repo`` scope\n        in the case of a classic token, or ``actions:read`` in the case of a fine-grained token.\n\n\n    In most cases, this will be used\n    through the :class:`~hypothesis.database.MultiplexedDatabase`,\n    by combining a local directory-based database with this one. For example:\n\n    .. code-block:: python\n\n        local = DirectoryBasedExampleDatabase(\".hypothesis/examples\")\n        shared = ReadOnlyDatabase(GitHubArtifactDatabase(\"user\", \"repo\"))\n\n        settings.register_profile(\"ci\", database=local)\n        settings.register_profile(\"dev\", database=MultiplexedDatabase(local, shared))\n        # We don't want to use the shared database in CI, only to populate its local one.\n        # which the workflow should then upload as an artifact.\n        settings.load_profile(\"ci\" if os.environ.get(\"CI\") else \"dev\")\n\n    .. note::\n        Because this database is read-only, you always need to wrap it with the\n        :class:`ReadOnlyDatabase`.\n\n    A setup like this can be paired with a GitHub Actions workflow including\n    something like the following:\n\n    .. code-block:: yaml\n\n        - name: Download example database\n          uses: dawidd6/action-download-artifact@v9\n          with:\n            name: hypothesis-example-db\n            path: .hypothesis/examples\n            if_no_artifact_found: warn\n            workflow_conclusion: completed\n\n        - name: Run tests\n          run: pytest\n\n        - name: Upload example database\n          uses: actions/upload-artifact@v3\n          if: always()\n          with:\n            name: hypothesis-example-db\n            path: .hypothesis/examples\n\n    In this workflow, we use `dawidd6/action-download-artifact <https://github.com/dawidd6/action-download-artifact>`_\n    to download the latest artifact given that the official `actions/download-artifact <https://github.com/actions/download-artifact>`_\n    does not support downloading artifacts from previous workflow runs.\n\n    The database automatically implements a simple file-based cache with a default expiration period\n    of 1 day. You can adjust this through the ``cache_timeout`` property.\n\n    For mono-repo support, you can provide a unique ``artifact_name`` (e.g. ``hypofuzz-example-db-frontend``).\n    \"\"\"\n\n    def __init__(\n        self,\n        owner: str,\n        repo: str,\n        artifact_name: str = \"hypothesis-example-db\",\n        cache_timeout: timedelta = timedelta(days=1),\n        path: StrPathT | None = None,\n    ):\n        super().__init__()\n        self.owner = owner\n        self.repo = repo\n        self.artifact_name = artifact_name\n        self.cache_timeout = cache_timeout\n\n        # Get the GitHub token from the environment\n        # It's unnecessary to use a token if the repo is public\n        self.token: str | None = getenv(\"GITHUB_TOKEN\")\n\n        if path is None:\n            self.path: Path = Path(\n                storage_directory(f\"github-artifacts/{self.artifact_name}/\")\n            )\n        else:\n            self.path = Path(path)\n\n        # We don't want to initialize the cache until we need to\n        self._initialized: bool = False\n        self._disabled: bool = False\n\n        # This is the path to the artifact in usage\n        # .hypothesis/github-artifacts/<artifact-name>/<modified_isoformat>.zip\n        self._artifact: Path | None = None\n        # This caches the artifact structure\n        self._access_cache: dict[PurePath, set[PurePath]] | None = None\n\n        # Message to display if user doesn't wrap around ReadOnlyDatabase\n        self._read_only_message = (\n            \"This database is read-only. \"\n            \"Please wrap this class with ReadOnlyDatabase\"\n            \"i.e. ReadOnlyDatabase(GitHubArtifactDatabase(...)).\"\n        )\n\n    def __repr__(self) -> str:\n        return (\n            f\"GitHubArtifactDatabase(owner={self.owner!r}, \"\n            f\"repo={self.repo!r}, artifact_name={self.artifact_name!r})\"\n        )\n\n    def __eq__(self, other: object) -> bool:\n        return (\n            isinstance(other, GitHubArtifactDatabase)\n            and self.owner == other.owner\n            and self.repo == other.repo\n            and self.artifact_name == other.artifact_name\n            and self.path == other.path\n        )\n\n    def _prepare_for_io(self) -> None:\n        assert self._artifact is not None, \"Artifact not loaded.\"\n\n        if self._initialized:  # pragma: no cover\n            return\n\n        # Test that the artifact is valid\n        try:\n            with ZipFile(self._artifact) as f:\n                if f.testzip():  # pragma: no cover\n                    raise BadZipFile\n\n            # Turns out that testzip() doesn't work quite well\n            # doing the cache initialization here instead\n            # will give us more coverage of the artifact.\n\n            # Cache the files inside each keypath\n            self._access_cache = {}\n            with ZipFile(self._artifact) as zf:\n                namelist = zf.namelist()\n                # Iterate over files in the artifact\n                for filename in namelist:\n                    fileinfo = zf.getinfo(filename)\n                    if fileinfo.is_dir():\n                        self._access_cache[PurePath(filename)] = set()\n                    else:\n                        # Get the keypath from the filename\n                        keypath = PurePath(filename).parent\n                        # Add the file to the keypath\n                        self._access_cache[keypath].add(PurePath(filename))\n        except BadZipFile:\n            warnings.warn(\n                \"The downloaded artifact from GitHub is invalid. \"\n                \"This could be because the artifact was corrupted, \"\n                \"or because the artifact was not created by Hypothesis. \",\n                HypothesisWarning,\n                stacklevel=3,\n            )\n            self._disabled = True\n\n        self._initialized = True\n\n    def _initialize_db(self) -> None:\n        # Trigger warning that we suppressed earlier by intent_to_write=False\n        storage_directory(self.path.name)\n        # Create the cache directory if it doesn't exist\n        self.path.mkdir(exist_ok=True, parents=True)\n\n        # Get all artifacts\n        cached_artifacts = sorted(\n            self.path.glob(\"*.zip\"),\n            key=lambda a: datetime.fromisoformat(a.stem.replace(\"_\", \":\")),\n        )\n\n        # Remove all but the latest artifact\n        for artifact in cached_artifacts[:-1]:\n            artifact.unlink()\n\n        try:\n            found_artifact = cached_artifacts[-1]\n        except IndexError:\n            found_artifact = None\n\n        # Check if the latest artifact is a cache hit\n        if found_artifact is not None and (\n            datetime.now(timezone.utc)\n            - datetime.fromisoformat(found_artifact.stem.replace(\"_\", \":\"))\n            < self.cache_timeout\n        ):\n            self._artifact = found_artifact\n        else:\n            # Download the latest artifact from GitHub\n            new_artifact = self._fetch_artifact()\n\n            if new_artifact:\n                if found_artifact is not None:\n                    found_artifact.unlink()\n                self._artifact = new_artifact\n            elif found_artifact is not None:\n                warnings.warn(\n                    \"Using an expired artifact as a fallback for the database: \"\n                    f\"{found_artifact}\",\n                    HypothesisWarning,\n                    stacklevel=2,\n                )\n                self._artifact = found_artifact\n            else:\n                warnings.warn(\n                    \"Couldn't acquire a new or existing artifact. Disabling database.\",\n                    HypothesisWarning,\n                    stacklevel=2,\n                )\n                self._disabled = True\n                return\n\n        self._prepare_for_io()\n\n    def _get_bytes(self, url: str) -> bytes | None:  # pragma: no cover\n        request = Request(\n            url,\n            headers={\n                \"Accept\": \"application/vnd.github+json\",\n                \"X-GitHub-Api-Version\": \"2022-11-28 \",\n                \"Authorization\": f\"Bearer {self.token}\",\n            },\n        )\n        warning_message = None\n        response_bytes: bytes | None = None\n        try:\n            with urlopen(request) as response:\n                response_bytes = response.read()\n        except HTTPError as e:\n            if e.code == 401:\n                warning_message = (\n                    \"Authorization failed when trying to download artifact from GitHub. \"\n                    \"Check that you have a valid GITHUB_TOKEN set in your environment.\"\n                )\n            else:\n                warning_message = (\n                    \"Could not get the latest artifact from GitHub. \"\n                    \"This could be because the repository \"\n                    \"or artifact does not exist. \"\n                )\n            # see https://github.com/python/cpython/issues/128734\n            e.close()\n        except URLError:\n            warning_message = \"Could not connect to GitHub to get the latest artifact. \"\n        except TimeoutError:\n            warning_message = (\n                \"Could not connect to GitHub to get the latest artifact \"\n                \"(connection timed out).\"\n            )\n\n        if warning_message is not None:\n            warnings.warn(warning_message, HypothesisWarning, stacklevel=4)\n            return None\n\n        return response_bytes\n\n    def _fetch_artifact(self) -> Path | None:  # pragma: no cover\n        # Get the list of artifacts from GitHub\n        url = f\"https://api.github.com/repos/{self.owner}/{self.repo}/actions/artifacts\"\n        response_bytes = self._get_bytes(url)\n        if response_bytes is None:\n            return None\n\n        artifacts = json.loads(response_bytes)[\"artifacts\"]\n        artifacts = [a for a in artifacts if a[\"name\"] == self.artifact_name]\n\n        if not artifacts:\n            return None\n\n        # Get the latest artifact from the list\n        artifact = max(artifacts, key=lambda a: a[\"created_at\"])\n        url = artifact[\"archive_download_url\"]\n\n        # Download the artifact\n        artifact_bytes = self._get_bytes(url)\n        if artifact_bytes is None:\n            return None\n\n        # Save the artifact to the cache\n        # We replace \":\" with \"_\" to ensure the filenames are compatible\n        # with Windows filesystems\n        timestamp = datetime.now(timezone.utc).isoformat().replace(\":\", \"_\")\n        artifact_path = self.path / f\"{timestamp}.zip\"\n        try:\n            artifact_path.write_bytes(artifact_bytes)\n        except OSError:\n            warnings.warn(\n                \"Could not save the latest artifact from GitHub. \",\n                HypothesisWarning,\n                stacklevel=3,\n            )\n            return None\n\n        return artifact_path\n\n    @staticmethod\n    @lru_cache\n    def _key_path(key: bytes) -> PurePath:\n        return PurePath(_hash(key) + \"/\")\n\n    def fetch(self, key: bytes) -> Iterable[bytes]:\n        if self._disabled:\n            return\n\n        if not self._initialized:\n            self._initialize_db()\n            if self._disabled:\n                return\n\n        assert self._artifact is not None\n        assert self._access_cache is not None\n\n        kp = self._key_path(key)\n\n        with ZipFile(self._artifact) as zf:\n            # Get all the files in the kp from the cache\n            filenames = self._access_cache.get(kp, ())\n            for filename in filenames:\n                with zf.open(filename.as_posix()) as f:\n                    yield f.read()\n\n    # Read-only interface\n    def save(self, key: bytes, value: bytes) -> None:\n        raise RuntimeError(self._read_only_message)\n\n    def move(self, src: bytes, dest: bytes, value: bytes) -> None:\n        raise RuntimeError(self._read_only_message)\n\n    def delete(self, key: bytes, value: bytes) -> None:\n        raise RuntimeError(self._read_only_message)\n\n\nclass BackgroundWriteDatabase(ExampleDatabase):\n    \"\"\"A wrapper which defers writes on the given database to a background thread.\n\n    Calls to :meth:`~hypothesis.database.ExampleDatabase.fetch` wait for any\n    enqueued writes to finish before fetching from the database.\n    \"\"\"\n\n    def __init__(self, db: ExampleDatabase) -> None:\n        super().__init__()\n        self._db = db\n        self._queue: Queue[tuple[str, tuple[bytes, ...]]] = Queue()\n        self._thread: Thread | None = None\n\n    def _ensure_thread(self):\n        if self._thread is None:\n            self._thread = Thread(target=self._worker, daemon=True)\n            self._thread.start()\n            # avoid an unbounded timeout during gc. 0.1 should be plenty for most\n            # use cases.\n            weakref.finalize(self, self._join, 0.1)\n\n    def __repr__(self) -> str:\n        return f\"BackgroundWriteDatabase({self._db!r})\"\n\n    def __eq__(self, other: object) -> bool:\n        return isinstance(other, BackgroundWriteDatabase) and self._db == other._db\n\n    def _worker(self) -> None:\n        while True:\n            method, args = self._queue.get()\n            getattr(self._db, method)(*args)\n            self._queue.task_done()\n\n    def _join(self, timeout: float | None = None) -> None:\n        # copy of Queue.join with a timeout. https://bugs.python.org/issue9634\n        with self._queue.all_tasks_done:\n            while self._queue.unfinished_tasks:\n                self._queue.all_tasks_done.wait(timeout)\n\n    def fetch(self, key: bytes) -> Iterable[bytes]:\n        self._join()\n        return self._db.fetch(key)\n\n    def save(self, key: bytes, value: bytes) -> None:\n        self._ensure_thread()\n        self._queue.put((\"save\", (key, value)))\n\n    def delete(self, key: bytes, value: bytes) -> None:\n        self._ensure_thread()\n        self._queue.put((\"delete\", (key, value)))\n\n    def move(self, src: bytes, dest: bytes, value: bytes) -> None:\n        self._ensure_thread()\n        self._queue.put((\"move\", (src, dest, value)))\n\n    def _start_listening(self) -> None:\n        self._db.add_listener(self._broadcast_change)\n\n    def _stop_listening(self) -> None:\n        self._db.remove_listener(self._broadcast_change)\n\n\ndef _pack_uleb128(value: int) -> bytes:\n    \"\"\"\n    Serialize an integer into variable-length bytes. For each byte, the first 7\n    bits represent (part of) the integer, while the last bit indicates whether the\n    integer continues into the next byte.\n\n    https://en.wikipedia.org/wiki/LEB128\n    \"\"\"\n    parts = bytearray()\n    assert value >= 0\n    while True:\n        # chop off 7 bits\n        byte = value & ((1 << 7) - 1)\n        value >>= 7\n        # set the continuation bit if we have more left\n        if value:\n            byte |= 1 << 7\n\n        parts.append(byte)\n        if not value:\n            break\n    return bytes(parts)\n\n\ndef _unpack_uleb128(buffer: bytes) -> tuple[int, int]:\n    \"\"\"\n    Inverts _pack_uleb128, and also returns the index at which at which we stopped\n    reading.\n    \"\"\"\n    value = 0\n    for i, byte in enumerate(buffer):\n        n = byte & ((1 << 7) - 1)\n        value |= n << (i * 7)\n\n        if not byte >> 7:\n            break\n    return (i + 1, value)\n\n\ndef choices_to_bytes(choices: Iterable[ChoiceT], /) -> bytes:\n    \"\"\"Serialize a list of choices to a bytestring.  Inverts choices_from_bytes.\"\"\"\n    # We use a custom serialization format for this, which might seem crazy - but our\n    # data is a flat sequence of elements, and standard tools like protobuf or msgpack\n    # don't deal well with e.g. nonstandard bit-pattern-NaNs, or invalid-utf8 unicode.\n    #\n    # We simply encode each element with a metadata byte, if needed a uint16 size, and\n    # then the payload bytes.  For booleans, the payload is inlined into the metadata.\n    parts = []\n    for choice in choices:\n        if isinstance(choice, bool):\n            # `000_0000v` - tag zero, low bit payload.\n            parts.append(b\"\\1\" if choice else b\"\\0\")\n            continue\n\n        # `tag_ssss [uint16 size?] [payload]`\n        if isinstance(choice, float):\n            tag = 1 << 5\n            choice = struct.pack(\"!d\", choice)\n        elif isinstance(choice, int):\n            tag = 2 << 5\n            choice = choice.to_bytes(1 + choice.bit_length() // 8, \"big\", signed=True)\n        elif isinstance(choice, bytes):\n            tag = 3 << 5\n        else:\n            assert isinstance(choice, str)\n            tag = 4 << 5\n            choice = choice.encode(errors=\"surrogatepass\")\n\n        size = len(choice)\n        if size < 0b11111:\n            parts.append((tag | size).to_bytes(1, \"big\"))\n        else:\n            parts.append((tag | 0b11111).to_bytes(1, \"big\"))\n            parts.append(_pack_uleb128(size))\n        parts.append(choice)\n\n    return b\"\".join(parts)\n\n\ndef _choices_from_bytes(buffer: bytes, /) -> tuple[ChoiceT, ...]:\n    # See above for an explanation of the format.\n    parts: list[ChoiceT] = []\n    idx = 0\n    while idx < len(buffer):\n        tag = buffer[idx] >> 5\n        size = buffer[idx] & 0b11111\n        idx += 1\n\n        if tag == 0:\n            parts.append(bool(size))\n            continue\n        if size == 0b11111:\n            offset, size = _unpack_uleb128(buffer[idx:])\n            idx += offset\n        chunk = buffer[idx : idx + size]\n        idx += size\n\n        if tag == 1:\n            assert size == 8, \"expected float64\"\n            parts.extend(struct.unpack(\"!d\", chunk))\n        elif tag == 2:\n            parts.append(int.from_bytes(chunk, \"big\", signed=True))\n        elif tag == 3:\n            parts.append(chunk)\n        else:\n            assert tag == 4\n            parts.append(chunk.decode(errors=\"surrogatepass\"))\n    return tuple(parts)\n\n\ndef choices_from_bytes(buffer: bytes, /) -> tuple[ChoiceT, ...] | None:\n    \"\"\"\n    Deserialize a bytestring to a tuple of choices. Inverts choices_to_bytes.\n\n    Returns None if the given bytestring is not a valid serialization of choice\n    sequences.\n    \"\"\"\n    try:\n        return _choices_from_bytes(buffer)\n    except Exception:\n        # deserialization error, eg because our format changed or someone put junk\n        # data in the db.\n        return None\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/entry_points.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"Run all functions registered for the \"hypothesis\" entry point.\n\nThis can be used with `st.register_type_strategy` to register strategies for your\ncustom types, running the relevant code when *hypothesis* is imported instead of\nyour package.\n\"\"\"\n\nimport importlib.metadata\nimport os\n\n\ndef run() -> None:\n    if os.environ.get(\"HYPOTHESIS_NO_PLUGINS\"):\n        return\n\n    for entry in importlib.metadata.entry_points(\n        group=\"hypothesis\"\n    ):  # pragma: no cover\n        hook = entry.load()\n        if callable(hook):\n            hook()\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/errors.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom datetime import timedelta\nfrom typing import Any, Literal\n\nfrom hypothesis.internal.compat import ExceptionGroup\n\n\nclass HypothesisException(Exception):\n    \"\"\"Generic parent class for exceptions thrown by Hypothesis.\"\"\"\n\n\nclass _Trimmable(HypothesisException):\n    \"\"\"Hypothesis can trim these tracebacks even if they're raised internally.\"\"\"\n\n\nclass UnsatisfiedAssumption(HypothesisException):\n    \"\"\"An internal error raised by assume.\n\n    If you're seeing this error something has gone wrong.\n    \"\"\"\n\n    def __init__(self, reason: str | None = None) -> None:\n        self.reason = reason\n\n\nclass NoSuchExample(HypothesisException):\n    \"\"\"The condition we have been asked to satisfy appears to be always false.\n\n    This does not guarantee that no example exists, only that we were\n    unable to find one.\n    \"\"\"\n\n    def __init__(self, condition_string: str, extra: str = \"\") -> None:\n        super().__init__(f\"No examples found of condition {condition_string}{extra}\")\n\n\nclass Unsatisfiable(_Trimmable):\n    \"\"\"We ran out of time or examples before we could find enough examples\n    which satisfy the assumptions of this hypothesis.\n\n    This could be because the function is too slow. If so, try upping\n    the timeout. It could also be because the function is using assume\n    in a way that is too hard to satisfy. If so, try writing a custom\n    strategy or using a better starting point (e.g if you are requiring\n    a list has unique values you could instead filter out all duplicate\n    values from the list)\n    \"\"\"\n\n\nclass ChoiceTooLarge(HypothesisException):\n    \"\"\"An internal error raised by choice_from_index.\"\"\"\n\n\nclass Flaky(_Trimmable):\n    \"\"\"\n    Base class for indeterministic failures. Usually one of the more\n    specific subclasses (|FlakyFailure| or |FlakyStrategyDefinition|) is raised.\n\n    .. seealso::\n\n        See also the :doc:`flaky failures tutorial </tutorial/flaky>`.\n    \"\"\"\n\n\nclass FlakyReplay(Flaky):\n    \"\"\"Internal error raised by the conjecture engine if flaky failures are\n    detected during replay.\n\n    Carries information allowing the runner to reconstruct the flakiness as\n    a FlakyFailure exception group for final presentation.\n    \"\"\"\n\n    def __init__(self, reason, interesting_origins=None):\n        super().__init__(reason)\n        self.reason = reason\n        self._interesting_origins = interesting_origins\n\n\nclass FlakyStrategyDefinition(Flaky):\n    \"\"\"\n    This function appears to cause inconsistent data generation.\n\n    Common causes for this problem are:\n        1. The strategy depends on external state. e.g. it uses an external\n           random number generator. Try to make a version that passes all the\n           relevant state in from Hypothesis.\n\n    .. seealso::\n\n        See also the :doc:`flaky failures tutorial </tutorial/flaky>`.\n    \"\"\"\n\n\nclass _WrappedBaseException(Exception):\n    \"\"\"Used internally for wrapping BaseExceptions as components of FlakyFailure.\"\"\"\n\n\nclass FlakyFailure(ExceptionGroup, Flaky):\n    \"\"\"\n    This function appears to fail non-deterministically: We have seen it\n    fail when passed this example at least once, but a subsequent invocation\n    did not fail, or caused a distinct error.\n\n    Common causes for this problem are:\n        1. The function depends on external state. e.g. it uses an external\n           random number generator. Try to make a version that passes all the\n           relevant state in from Hypothesis.\n        2. The function is suffering from too much recursion and its failure\n           depends sensitively on where it's been called from.\n        3. The function is timing sensitive and can fail or pass depending on\n           how long it takes. Try breaking it up into smaller functions which\n           don't do that and testing those instead.\n\n    .. seealso::\n\n        See also the :doc:`flaky failures tutorial </tutorial/flaky>`.\n    \"\"\"\n\n    def __new__(cls, msg, group):\n        # The Exception mixin forces this an ExceptionGroup (only accepting\n        # Exceptions, not BaseException). Usually BaseException is raised\n        # directly and will hence not be part of a FlakyFailure, but I'm not\n        # sure this assumption holds everywhere. So wrap any BaseExceptions.\n        group = list(group)\n        for i, exc in enumerate(group):\n            if not isinstance(exc, Exception):\n                err = _WrappedBaseException()\n                err.__cause__ = err.__context__ = exc\n                group[i] = err\n        return ExceptionGroup.__new__(cls, msg, group)\n\n    # defining `derive` is required for `split` to return an instance of FlakyFailure\n    # instead of ExceptionGroup. See https://github.com/python/cpython/issues/119287\n    # and https://docs.python.org/3/library/exceptions.html#BaseExceptionGroup.derive\n    def derive(self, excs):\n        return type(self)(self.message, excs)\n\n\nclass FlakyBackendFailure(FlakyFailure):\n    \"\"\"\n    A failure was reported by an |alternative backend|,\n    but this failure did not reproduce when replayed under the Hypothesis backend.\n\n    When an alternative backend reports a failure, Hypothesis first replays it\n    under the standard Hypothesis backend to check for flakiness. If the failure\n    does not reproduce, Hypothesis raises this exception.\n    \"\"\"\n\n\nclass InvalidArgument(_Trimmable, TypeError):\n    \"\"\"Used to indicate that the arguments to a Hypothesis function were in\n    some manner incorrect.\"\"\"\n\n\nclass ResolutionFailed(InvalidArgument):\n    \"\"\"Hypothesis had to resolve a type to a strategy, but this failed.\n\n    Type inference is best-effort, so this only happens when an\n    annotation exists but could not be resolved for a required argument\n    to the target of ``builds()``, or where the user passed ``...``.\n    \"\"\"\n\n\nclass InvalidState(HypothesisException):\n    \"\"\"The system is not in a state where you were allowed to do that.\"\"\"\n\n\nclass InvalidDefinition(_Trimmable, TypeError):\n    \"\"\"Used to indicate that a class definition was not well put together and\n    has something wrong with it.\"\"\"\n\n\nclass HypothesisWarning(HypothesisException, Warning):\n    \"\"\"A generic warning issued by Hypothesis.\"\"\"\n\n\nclass FailedHealthCheck(_Trimmable):\n    \"\"\"Raised when a test fails a health check. See |HealthCheck|.\"\"\"\n\n\nclass NonInteractiveExampleWarning(HypothesisWarning):\n    \"\"\"\n    Emitted when |.example| is used outside of interactive use.\n\n    |.example| is intended for exploratory and interactive work, not to be run as\n    part of a test suite.\n    \"\"\"\n\n\nclass HypothesisDeprecationWarning(HypothesisWarning, FutureWarning):\n    \"\"\"A deprecation warning issued by Hypothesis.\n\n    Actually inherits from FutureWarning, because DeprecationWarning is\n    hidden by the default warnings filter.\n\n    You can configure the :mod:`python:warnings` module to handle these\n    warnings differently to others, either turning them into errors or\n    suppressing them entirely.  Obviously we would prefer the former!\n    \"\"\"\n\n\nclass HypothesisSideeffectWarning(HypothesisWarning):\n    \"\"\"A warning issued by Hypothesis when it sees actions that are\n    discouraged at import or initialization time because they are\n    slow or have user-visible side effects.\n    \"\"\"\n\n\nclass Frozen(HypothesisException):\n    \"\"\"Raised when a mutation method has been called on a ConjectureData object\n    after freeze() has been called.\"\"\"\n\n\ndef __getattr__(name: str) -> Any:\n    if name == \"MultipleFailures\":\n        from hypothesis.internal.compat import BaseExceptionGroup\n        from hypothesis.utils.deprecation import note_deprecation\n\n        note_deprecation(\n            \"MultipleFailures is deprecated; use the builtin `BaseExceptionGroup` type \"\n            \"instead, or `exceptiongroup.BaseExceptionGroup` before Python 3.11\",\n            since=\"2022-08-02\",\n            has_codemod=False,  # This would be a great PR though!\n            stacklevel=1,\n        )\n        return BaseExceptionGroup\n\n    raise AttributeError(f\"Module 'hypothesis.errors' has no attribute {name}\")\n\n\nclass DeadlineExceeded(_Trimmable):\n    \"\"\"\n    Raised when an input takes too long to run, relative to the |settings.deadline|\n    setting.\n    \"\"\"\n\n    def __init__(self, runtime: timedelta, deadline: timedelta) -> None:\n        super().__init__(\n            f\"Test took {runtime.total_seconds() * 1000:.2f}ms, which exceeds \"\n            f\"the deadline of {deadline.total_seconds() * 1000:.2f}ms. If you \"\n            \"expect test cases to take this long, you can use @settings(deadline=...) \"\n            \"to either set a higher deadline, or to disable it with deadline=None.\"\n        )\n        self.runtime = runtime\n        self.deadline = deadline\n\n    def __reduce__(\n        self,\n    ) -> tuple[type[\"DeadlineExceeded\"], tuple[timedelta, timedelta]]:\n        return (type(self), (self.runtime, self.deadline))\n\n\nclass StopTest(BaseException):\n    \"\"\"Raised when a test should stop running and return control to\n    the Hypothesis engine, which should then continue normally.\n    \"\"\"\n\n    def __init__(self, testcounter: int) -> None:\n        super().__init__(repr(testcounter))\n        self.testcounter = testcounter\n\n\nclass DidNotReproduce(HypothesisException):\n    pass\n\n\nclass Found(HypothesisException):\n    \"\"\"Signal that the example matches condition. Internal use only.\"\"\"\n\n\nclass RewindRecursive(Exception):\n    \"\"\"Signal that the type inference should be rewound due to recursive types. Internal use only.\"\"\"\n\n    def __init__(self, target: object) -> None:\n        self.target = target\n\n\nclass SmallSearchSpaceWarning(HypothesisWarning):\n    \"\"\"Indicates that an inferred strategy does not span the search space\n    in a meaningful way, for example by only creating default instances.\"\"\"\n\n\nCannotProceedScopeT = Literal[\"verified\", \"exhausted\", \"discard_test_case\", \"other\"]\n_valid_cannot_proceed_scopes = CannotProceedScopeT.__args__  # type: ignore\n\n\nclass BackendCannotProceed(HypothesisException):\n    \"\"\"\n    Raised by alternative backends when a |PrimitiveProvider| cannot proceed.\n    This is expected to occur inside one of the ``.draw_*()`` methods, or for\n    symbolic execution perhaps in |PrimitiveProvider.realize|.\n\n    The optional ``scope`` argument can enable smarter integration:\n\n        verified:\n            Do not request further test cases from this backend.  We *may*\n            generate more test cases with other backends; if one fails then\n            Hypothesis will report unsound verification in the backend too.\n\n        exhausted:\n            Do not request further test cases from this backend; finish testing\n            with test cases generated with the default backend.  Common if e.g.\n            native code blocks symbolic reasoning very early.\n\n        discard_test_case:\n            This particular test case could not be converted to concrete values;\n            skip any further processing and continue with another test case from\n            this backend.\n    \"\"\"\n\n    def __init__(self, scope: CannotProceedScopeT = \"other\", /) -> None:\n        if scope not in _valid_cannot_proceed_scopes:\n            raise InvalidArgument(\n                f\"Got scope={scope}, but expected one of \"\n                f\"{_valid_cannot_proceed_scopes!r}\"\n            )\n        self.scope = scope\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/_array_helpers.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\nfrom types import EllipsisType\nfrom typing import NamedTuple\n\nfrom hypothesis import assume, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.conjecture.utils import _calc_p_continue\nfrom hypothesis.internal.coverage import check_function\nfrom hypothesis.internal.validation import check_type, check_valid_interval\nfrom hypothesis.strategies._internal.utils import defines_strategy\nfrom hypothesis.utils.conventions import UniqueIdentifier, not_set\n\n__all__ = [\n    \"NDIM_MAX\",\n    \"_BIE\",\n    \"BasicIndex\",\n    \"BasicIndexStrategy\",\n    \"BroadcastableShapes\",\n    \"MutuallyBroadcastableShapesStrategy\",\n    \"Shape\",\n    \"_BIENoEllipsis\",\n    \"_BIENoEllipsisNoNewaxis\",\n    \"_BIENoNewaxis\",\n    \"array_shapes\",\n    \"broadcastable_shapes\",\n    \"check_argument\",\n    \"check_valid_dims\",\n    \"mutually_broadcastable_shapes\",\n    \"order_check\",\n    \"valid_tuple_axes\",\n]\n\n\nShape = tuple[int, ...]\n\n# Type aliases for basic array index elements. Variants exist to accurately\n# type the return value of basic_indices() based on allow_ellipsis/allow_newaxis.\n_BIE = int | slice | None | EllipsisType\n_BIENoEllipsis = int | slice | None\n_BIENoNewaxis = int | slice | EllipsisType\n_BIENoEllipsisNoNewaxis = int | slice\n\nBasicIndex = _BIE | tuple[_BIE, ...]\n\n\nclass BroadcastableShapes(NamedTuple):\n    input_shapes: tuple[Shape, ...]\n    result_shape: Shape\n\n\n@check_function\ndef check_argument(condition, fail_message, *f_args, **f_kwargs):\n    if not condition:\n        raise InvalidArgument(fail_message.format(*f_args, **f_kwargs))\n\n\n@check_function\ndef order_check(name, floor, min_, max_):\n    if floor > min_:\n        raise InvalidArgument(f\"min_{name} must be at least {floor} but was {min_}\")\n    if min_ > max_:\n        raise InvalidArgument(f\"min_{name}={min_} is larger than max_{name}={max_}\")\n\n\n# 32 is a dimension limit specific to NumPy, and does not necessarily apply to\n# other array/tensor libraries. Historically these strategies were built for the\n# NumPy extra, so it's nice to keep these limits, and it's seemingly unlikely\n# someone would want to generate >32 dim arrays anyway.\n# See https://github.com/HypothesisWorks/hypothesis/pull/3067.\nNDIM_MAX = 32\n\n\n@check_function\ndef check_valid_dims(dims, name):\n    if dims > NDIM_MAX:\n        raise InvalidArgument(\n            f\"{name}={dims}, but Hypothesis does not support arrays with \"\n            f\"more than {NDIM_MAX} dimensions\"\n        )\n\n\n@defines_strategy()\ndef array_shapes(\n    *,\n    min_dims: int = 1,\n    max_dims: int | None = None,\n    min_side: int = 1,\n    max_side: int | None = None,\n) -> st.SearchStrategy[Shape]:\n    \"\"\"Return a strategy for array shapes (tuples of int >= 1).\n\n    * ``min_dims`` is the smallest length that the generated shape can possess.\n    * ``max_dims`` is the largest length that the generated shape can possess,\n      defaulting to ``min_dims + 2``.\n    * ``min_side`` is the smallest size that a dimension can possess.\n    * ``max_side`` is the largest size that a dimension can possess,\n      defaulting to ``min_side + 5``.\n    \"\"\"\n    check_type(int, min_dims, \"min_dims\")\n    check_type(int, min_side, \"min_side\")\n    check_valid_dims(min_dims, \"min_dims\")\n\n    if max_dims is None:\n        max_dims = min(min_dims + 2, NDIM_MAX)\n    check_type(int, max_dims, \"max_dims\")\n    check_valid_dims(max_dims, \"max_dims\")\n\n    if max_side is None:\n        max_side = min_side + 5\n    check_type(int, max_side, \"max_side\")\n\n    order_check(\"dims\", 0, min_dims, max_dims)\n    order_check(\"side\", 0, min_side, max_side)\n\n    return st.lists(\n        st.integers(min_side, max_side), min_size=min_dims, max_size=max_dims\n    ).map(tuple)\n\n\n@defines_strategy()\ndef valid_tuple_axes(\n    ndim: int,\n    *,\n    min_size: int = 0,\n    max_size: int | None = None,\n) -> st.SearchStrategy[tuple[int, ...]]:\n    \"\"\"\n    All tuples will have a length >= ``min_size`` and <= ``max_size``. The default\n    value for ``max_size`` is ``ndim``.\n\n    Examples from this strategy shrink towards an empty tuple, which render most\n    sequential functions as no-ops.\n\n    The following are some examples drawn from this strategy.\n\n    .. code-block:: pycon\n\n      >>> [valid_tuple_axes(3).example() for i in range(4)]\n      [(-3, 1), (0, 1, -1), (0, 2), (0, -2, 2)]\n\n    ``valid_tuple_axes`` can be joined with other strategies to generate\n    any type of valid axis object, i.e. integers, tuples, and ``None``:\n\n    .. code-block:: python\n\n      any_axis_strategy = none() | integers(-ndim, ndim - 1) | valid_tuple_axes(ndim)\n    \"\"\"\n    check_type(int, ndim, \"ndim\")\n    check_type(int, min_size, \"min_size\")\n    if max_size is None:\n        max_size = ndim\n    check_type(int, max_size, \"max_size\")\n    order_check(\"size\", 0, min_size, max_size)\n    check_valid_interval(max_size, ndim, \"max_size\", \"ndim\")\n\n    axes = st.integers(0, max(0, 2 * ndim - 1)).map(\n        lambda x: x if x < ndim else x - 2 * ndim\n    )\n\n    return st.lists(\n        axes, min_size=min_size, max_size=max_size, unique_by=lambda x: x % ndim\n    ).map(tuple)\n\n\n@defines_strategy()\ndef broadcastable_shapes(\n    shape: Shape,\n    *,\n    min_dims: int = 0,\n    max_dims: int | None = None,\n    min_side: int = 1,\n    max_side: int | None = None,\n) -> st.SearchStrategy[Shape]:\n    \"\"\"Return a strategy for shapes that are broadcast-compatible with the\n    provided shape.\n\n    Examples from this strategy shrink towards a shape with length ``min_dims``.\n    The size of an aligned dimension shrinks towards size ``1``. The size of an\n    unaligned dimension shrink towards ``min_side``.\n\n    * ``shape`` is a tuple of integers.\n    * ``min_dims`` is the smallest length that the generated shape can possess.\n    * ``max_dims`` is the largest length that the generated shape can possess,\n      defaulting to ``max(len(shape), min_dims) + 2``.\n    * ``min_side`` is the smallest size that an unaligned dimension can possess.\n    * ``max_side`` is the largest size that an unaligned dimension can possess,\n      defaulting to 2 plus the size of the largest aligned dimension.\n\n    The following are some examples drawn from this strategy.\n\n    .. code-block:: pycon\n\n        >>> [broadcastable_shapes(shape=(2, 3)).example() for i in range(5)]\n        [(1, 3), (), (2, 3), (2, 1), (4, 1, 3), (3, )]\n\n    \"\"\"\n    check_type(tuple, shape, \"shape\")\n    check_type(int, min_side, \"min_side\")\n    check_type(int, min_dims, \"min_dims\")\n    check_valid_dims(min_dims, \"min_dims\")\n\n    strict_check = max_side is None or max_dims is None\n\n    if max_dims is None:\n        max_dims = min(max(len(shape), min_dims) + 2, NDIM_MAX)\n    check_type(int, max_dims, \"max_dims\")\n    check_valid_dims(max_dims, \"max_dims\")\n\n    if max_side is None:\n        max_side = max(shape[-max_dims:] + (min_side,)) + 2\n    check_type(int, max_side, \"max_side\")\n\n    order_check(\"dims\", 0, min_dims, max_dims)\n    order_check(\"side\", 0, min_side, max_side)\n\n    if strict_check:\n        dims = max_dims\n        bound_name = \"max_dims\"\n    else:\n        dims = min_dims\n        bound_name = \"min_dims\"\n\n    # check for unsatisfiable min_side\n    if not all(min_side <= s for s in shape[::-1][:dims] if s != 1):\n        raise InvalidArgument(\n            f\"Given shape={shape}, there are no broadcast-compatible \"\n            f\"shapes that satisfy: {bound_name}={dims} and min_side={min_side}\"\n        )\n\n    # check for unsatisfiable [min_side, max_side]\n    if not (\n        min_side <= 1 <= max_side or all(s <= max_side for s in shape[::-1][:dims])\n    ):\n        raise InvalidArgument(\n            f\"Given base_shape={shape}, there are no broadcast-compatible \"\n            f\"shapes that satisfy all of {bound_name}={dims}, \"\n            f\"min_side={min_side}, and max_side={max_side}\"\n        )\n\n    if not strict_check:\n        # reduce max_dims to exclude unsatisfiable dimensions\n        for n, s in zip(range(max_dims), shape[::-1], strict=False):\n            if s < min_side and s != 1:\n                max_dims = n\n                break\n            if not (min_side <= 1 <= max_side or s <= max_side):\n                max_dims = n\n                break\n\n    return MutuallyBroadcastableShapesStrategy(\n        num_shapes=1,\n        base_shape=shape,\n        min_dims=min_dims,\n        max_dims=max_dims,\n        min_side=min_side,\n        max_side=max_side,\n    ).map(lambda x: x.input_shapes[0])\n\n\n# See https://numpy.org/doc/stable/reference/c-api/generalized-ufuncs.html\n# Implementation based on numpy.lib.function_base._parse_gufunc_signature\n# with minor upgrades to handle numeric and optional dimensions.  Examples:\n#\n#     add       (),()->()                   binary ufunc\n#     sum1d     (i)->()                     reduction\n#     inner1d   (i),(i)->()                 vector-vector multiplication\n#     matmat    (m,n),(n,p)->(m,p)          matrix multiplication\n#     vecmat    (n),(n,p)->(p)              vector-matrix multiplication\n#     matvec    (m,n),(n)->(m)              matrix-vector multiplication\n#     matmul    (m?,n),(n,p?)->(m?,p?)      combination of the four above\n#     cross1d   (3),(3)->(3)                cross product with frozen dimensions\n#\n# Note that while no examples of such usage are given, Numpy does allow\n# generalised ufuncs that have *multiple output arrays*.  This is not\n# currently supported by Hypothesis - please contact us if you would use it!\n#\n# We are unsure if gufuncs allow frozen dimensions to be optional, but it's\n# easy enough to support here - and so we will unless we learn otherwise.\n_DIMENSION = r\"\\w+\\??\"  # Note that \\w permits digits too!\n_SHAPE = rf\"\\((?:{_DIMENSION}(?:,{_DIMENSION}){{0,31}})?\\)\"\n_ARGUMENT_LIST = f\"{_SHAPE}(?:,{_SHAPE})*\"\n_SIGNATURE = rf\"^{_ARGUMENT_LIST}->{_SHAPE}$\"\n_SIGNATURE_MULTIPLE_OUTPUT = rf\"^{_ARGUMENT_LIST}->{_ARGUMENT_LIST}$\"\n\n\nclass _GUfuncSig(NamedTuple):\n    input_shapes: tuple[Shape, ...]\n    result_shape: Shape\n\n\ndef _hypothesis_parse_gufunc_signature(signature):\n    # Disable all_checks to better match the Numpy version, for testing\n    if not re.match(_SIGNATURE, signature):\n        if re.match(_SIGNATURE_MULTIPLE_OUTPUT, signature):\n            raise InvalidArgument(\n                \"Hypothesis does not yet support generalised ufunc signatures \"\n                \"with multiple output arrays - mostly because we don't know of \"\n                \"anyone who uses them!  Please get in touch with us to fix that.\"\n                f\"\\n ({signature=})\"\n            )\n        if re.match(\n            (\n                # Taken from np.lib.function_base._SIGNATURE\n                r\"^\\((?:\\w+(?:,\\w+)*)?\\)(?:,\\((?:\\w+(?:,\\w+)*)?\\))*->\"\n                r\"\\((?:\\w+(?:,\\w+)*)?\\)(?:,\\((?:\\w+(?:,\\w+)*)?\\))*$\"\n            ),\n            signature,\n        ):\n            raise InvalidArgument(\n                f\"{signature=} matches Numpy's regex for gufunc signatures, \"\n                f\"but contains shapes with more than {NDIM_MAX} dimensions and is thus invalid.\"\n            )\n        raise InvalidArgument(f\"{signature!r} is not a valid gufunc signature\")\n    input_shapes, output_shapes = (\n        tuple(tuple(re.findall(_DIMENSION, a)) for a in re.findall(_SHAPE, arg_list))\n        for arg_list in signature.split(\"->\")\n    )\n    assert len(output_shapes) == 1\n    result_shape = output_shapes[0]\n    # Check that there are no names in output shape that do not appear in inputs.\n    # (kept out of parser function for easier generation of test values)\n    # We also disallow frozen optional dimensions - this is ambiguous as there is\n    # no way to share an un-named dimension between shapes.  Maybe just padding?\n    # Anyway, we disallow it pending clarification from upstream.\n    for shape in (*input_shapes, result_shape):\n        for name in shape:\n            try:\n                int(name.strip(\"?\"))\n                if \"?\" in name:\n                    raise InvalidArgument(\n                        f\"Got dimension {name!r}, but handling of frozen optional dimensions \"\n                        \"is ambiguous.  If you known how this should work, please \"\n                        f\"contact us to get this fixed and documented ({signature=}).\"\n                    )\n            except ValueError:\n                names_in = {n.strip(\"?\") for shp in input_shapes for n in shp}\n                names_out = {n.strip(\"?\") for n in result_shape}\n                if name.strip(\"?\") in (names_out - names_in):\n                    raise InvalidArgument(\n                        f\"The {name!r} dimension only appears in the output shape, and is \"\n                        f\"not frozen, so the size is not determined ({signature=}).\"\n                    ) from None\n    return _GUfuncSig(input_shapes=input_shapes, result_shape=result_shape)\n\n\n@defines_strategy()\ndef mutually_broadcastable_shapes(\n    *,\n    num_shapes: UniqueIdentifier | int = not_set,\n    signature: UniqueIdentifier | str = not_set,\n    base_shape: Shape = (),\n    min_dims: int = 0,\n    max_dims: int | None = None,\n    min_side: int = 1,\n    max_side: int | None = None,\n) -> st.SearchStrategy[BroadcastableShapes]:\n    \"\"\"\n    Return a strategy for a specified number of shapes N that are\n    mutually-broadcastable with one another and with the provided base shape.\n\n    * ``num_shapes`` is the number of mutually broadcast-compatible shapes to generate.\n    * ``base_shape`` is the shape against which all generated shapes can broadcast.\n      The default shape is empty, which corresponds to a scalar and thus does\n      not constrain broadcasting at all.\n    * ``min_dims`` is the smallest length that the generated shape can possess.\n    * ``max_dims`` is the largest length that the generated shape can possess,\n      defaulting to ``max(len(shape), min_dims) + 2``.\n    * ``min_side`` is the smallest size that an unaligned dimension can possess.\n    * ``max_side`` is the largest size that an unaligned dimension can possess,\n      defaulting to 2 plus the size of the largest aligned dimension.\n\n    The strategy will generate a :obj:`python:typing.NamedTuple` containing:\n\n    * ``input_shapes`` as a tuple of the N generated shapes.\n    * ``result_shape`` as the resulting shape produced by broadcasting the N shapes\n      with the base shape.\n\n    The following are some examples drawn from this strategy.\n\n    .. code-block:: pycon\n\n        >>> # Draw three shapes where each shape is broadcast-compatible with (2, 3)\n        ... strat = mutually_broadcastable_shapes(num_shapes=3, base_shape=(2, 3))\n        >>> for _ in range(5):\n        ...     print(strat.example())\n        BroadcastableShapes(input_shapes=((4, 1, 3), (4, 2, 3), ()), result_shape=(4, 2, 3))\n        BroadcastableShapes(input_shapes=((3,), (1, 3), (2, 3)), result_shape=(2, 3))\n        BroadcastableShapes(input_shapes=((), (), ()), result_shape=())\n        BroadcastableShapes(input_shapes=((3,), (), (3,)), result_shape=(3,))\n        BroadcastableShapes(input_shapes=((1, 2, 3), (3,), ()), result_shape=(1, 2, 3))\n    \"\"\"\n    arg_msg = \"Pass either the `num_shapes` or the `signature` argument, but not both.\"\n    if num_shapes is not not_set:\n        check_argument(signature is not_set, arg_msg)\n        check_type(int, num_shapes, \"num_shapes\")\n        assert isinstance(num_shapes, int)  # for mypy\n        parsed_signature = None\n        sig_dims = 0\n    else:\n        check_argument(signature is not not_set, arg_msg)\n        if signature is None:\n            raise InvalidArgument(\n                \"Expected a string, but got invalid signature=None.  \"\n                \"(maybe .signature attribute of an element-wise ufunc?)\"\n            )\n        check_type(str, signature, \"signature\")\n        parsed_signature = _hypothesis_parse_gufunc_signature(signature)\n        all_shapes = (*parsed_signature.input_shapes, parsed_signature.result_shape)\n        sig_dims = min(len(s) for s in all_shapes)\n        num_shapes = len(parsed_signature.input_shapes)\n\n    if num_shapes < 1:\n        raise InvalidArgument(f\"num_shapes={num_shapes} must be at least 1\")\n\n    check_type(tuple, base_shape, \"base_shape\")\n    check_type(int, min_side, \"min_side\")\n    check_type(int, min_dims, \"min_dims\")\n    check_valid_dims(min_dims, \"min_dims\")\n\n    strict_check = max_dims is not None\n\n    if max_dims is None:\n        max_dims = min(max(len(base_shape), min_dims) + 2, NDIM_MAX - sig_dims)\n    check_type(int, max_dims, \"max_dims\")\n    check_valid_dims(max_dims, \"max_dims\")\n\n    if max_side is None:\n        max_side = max(base_shape[-max_dims:] + (min_side,)) + 2\n    check_type(int, max_side, \"max_side\")\n\n    order_check(\"dims\", 0, min_dims, max_dims)\n    order_check(\"side\", 0, min_side, max_side)\n\n    if signature is not None and max_dims > NDIM_MAX - sig_dims:\n        raise InvalidArgument(\n            f\"max_dims={signature!r} would exceed the {NDIM_MAX}-dimension\"\n            \"limit Hypothesis imposes on array shapes, \"\n            f\"given signature={parsed_signature!r}\"\n        )\n\n    if strict_check:\n        dims = max_dims\n        bound_name = \"max_dims\"\n    else:\n        dims = min_dims\n        bound_name = \"min_dims\"\n\n    # check for unsatisfiable min_side\n    if not all(min_side <= s for s in base_shape[::-1][:dims] if s != 1):\n        raise InvalidArgument(\n            f\"Given base_shape={base_shape}, there are no broadcast-compatible \"\n            f\"shapes that satisfy: {bound_name}={dims} and min_side={min_side}\"\n        )\n\n    # check for unsatisfiable [min_side, max_side]\n    if not (\n        min_side <= 1 <= max_side or all(s <= max_side for s in base_shape[::-1][:dims])\n    ):\n        raise InvalidArgument(\n            f\"Given base_shape={base_shape}, there are no broadcast-compatible \"\n            f\"shapes that satisfy all of {bound_name}={dims}, \"\n            f\"min_side={min_side}, and max_side={max_side}\"\n        )\n\n    if not strict_check:\n        # reduce max_dims to exclude unsatisfiable dimensions\n        for n, s in zip(range(max_dims), base_shape[::-1], strict=False):\n            if s < min_side and s != 1:\n                max_dims = n\n                break\n            if not (min_side <= 1 <= max_side or s <= max_side):\n                max_dims = n\n                break\n\n    return MutuallyBroadcastableShapesStrategy(\n        num_shapes=num_shapes,\n        signature=parsed_signature,\n        base_shape=base_shape,\n        min_dims=min_dims,\n        max_dims=max_dims,\n        min_side=min_side,\n        max_side=max_side,\n    )\n\n\nclass MutuallyBroadcastableShapesStrategy(st.SearchStrategy):\n    def __init__(\n        self,\n        num_shapes,\n        signature=None,\n        base_shape=(),\n        min_dims=0,\n        max_dims=None,\n        min_side=1,\n        max_side=None,\n    ):\n        super().__init__()\n        self.base_shape = base_shape\n        self.side_strat = st.integers(min_side, max_side)\n        self.num_shapes = num_shapes\n        self.signature = signature\n        self.min_dims = min_dims\n        self.max_dims = max_dims\n        self.min_side = min_side\n        self.max_side = max_side\n\n        self.size_one_allowed = self.min_side <= 1 <= self.max_side\n\n    def do_draw(self, data):\n        # We don't usually have a gufunc signature; do the common case first & fast.\n        if self.signature is None:\n            return self._draw_loop_dimensions(data)\n\n        # When we *do*, draw the core dims, then draw loop dims, and finally combine.\n        core_in, core_res = self._draw_core_dimensions(data)\n\n        # If some core shape has omitted optional dimensions, it's an error to add\n        # loop dimensions to it.  We never omit core dims if min_dims >= 1.\n        # This ensures that we respect Numpy's gufunc broadcasting semantics and user\n        # constraints without needing to check whether the loop dims will be\n        # interpreted as an invalid substitute for the omitted core dims.\n        # We may implement this check later!\n        use = [None not in shp for shp in core_in]\n        loop_in, loop_res = self._draw_loop_dimensions(data, use=use)\n\n        def add_shape(loop, core):\n            return tuple(x for x in (loop + core)[-NDIM_MAX:] if x is not None)\n\n        return BroadcastableShapes(\n            input_shapes=tuple(\n                add_shape(l_in, c) for l_in, c in zip(loop_in, core_in, strict=True)\n            ),\n            result_shape=add_shape(loop_res, core_res),\n        )\n\n    def _draw_core_dimensions(self, data):\n        # Draw gufunc core dimensions, with None standing for optional dimensions\n        # that will not be present in the final shape.  We track omitted dims so\n        # that we can do an accurate per-shape length cap.\n        dims = {}\n        shapes = []\n        for shape in (*self.signature.input_shapes, self.signature.result_shape):\n            shapes.append([])\n            for name in shape:\n                if name.isdigit():\n                    shapes[-1].append(int(name))\n                    continue\n                if name not in dims:\n                    dim = name.strip(\"?\")\n                    dims[dim] = data.draw(self.side_strat)\n                    if self.min_dims == 0 and not data.draw_boolean(7 / 8):\n                        dims[dim + \"?\"] = None\n                    else:\n                        dims[dim + \"?\"] = dims[dim]\n                shapes[-1].append(dims[name])\n        return tuple(tuple(s) for s in shapes[:-1]), tuple(shapes[-1])\n\n    def _draw_loop_dimensions(self, data, use=None):\n        # All shapes are handled in column-major order; i.e. they are reversed\n        base_shape = self.base_shape[::-1]\n        result_shape = list(base_shape)\n        shapes = [[] for _ in range(self.num_shapes)]\n        if use is None:\n            use = [True for _ in range(self.num_shapes)]\n        else:\n            assert len(use) == self.num_shapes\n            assert all(isinstance(x, bool) for x in use)\n\n        _gap = self.max_dims - self.min_dims\n        p_keep_extending_shape = _calc_p_continue(desired_avg=_gap / 2, max_size=_gap)\n\n        for dim_count in range(1, self.max_dims + 1):\n            dim = dim_count - 1\n\n            # We begin by drawing a valid dimension-size for the given\n            # dimension. This restricts the variability across the shapes\n            # at this dimension such that they can only choose between\n            # this size and a singleton dimension.\n            if len(base_shape) < dim_count or base_shape[dim] == 1:\n                # dim is unrestricted by the base-shape: shrink to min_side\n                dim_side = data.draw(self.side_strat)\n            elif base_shape[dim] <= self.max_side:\n                # dim is aligned with non-singleton base-dim\n                dim_side = base_shape[dim]\n            else:\n                # only a singleton is valid in alignment with the base-dim\n                dim_side = 1\n\n            allowed_sides = sorted([1, dim_side])  # shrink to 0 when available\n            for shape_id, shape in enumerate(shapes):\n                # Populating this dimension-size for each shape, either\n                # the drawn size is used or, if permitted, a singleton\n                # dimension.\n                if dim <= len(result_shape) and self.size_one_allowed:\n                    # aligned: shrink towards size 1\n                    side = data.draw(st.sampled_from(allowed_sides))\n                else:\n                    side = dim_side\n\n                # Use a trick where a biased coin is queried to see\n                # if the given shape-tuple will continue to be grown. All\n                # of the relevant draws will still be made for the given\n                # shape-tuple even if it is no longer being added to.\n                # This helps to ensure more stable shrinking behavior.\n                if self.min_dims < dim_count:\n                    use[shape_id] &= data.draw_boolean(p_keep_extending_shape)\n\n                if use[shape_id]:\n                    shape.append(side)\n                    if len(result_shape) < len(shape):\n                        result_shape.append(shape[-1])\n                    elif shape[-1] != 1 and result_shape[dim] == 1:\n                        result_shape[dim] = shape[-1]\n            if not any(use):\n                break\n\n        result_shape = result_shape[: max(map(len, [self.base_shape, *shapes]))]\n\n        assert len(shapes) == self.num_shapes\n        assert all(self.min_dims <= len(s) <= self.max_dims for s in shapes)\n        assert all(self.min_side <= s <= self.max_side for side in shapes for s in side)\n\n        return BroadcastableShapes(\n            input_shapes=tuple(tuple(reversed(shape)) for shape in shapes),\n            result_shape=tuple(reversed(result_shape)),\n        )\n\n\nclass BasicIndexStrategy(st.SearchStrategy):\n    def __init__(\n        self,\n        shape,\n        min_dims,\n        max_dims,\n        allow_ellipsis,\n        allow_newaxis,\n        allow_fewer_indices_than_dims,\n    ):\n        super().__init__()\n        self.shape = shape\n        self.min_dims = min_dims\n        self.max_dims = max_dims\n        self.allow_ellipsis = allow_ellipsis\n        self.allow_newaxis = allow_newaxis\n        # allow_fewer_indices_than_dims=False will disable generating indices\n        # that don't cover all axes, i.e. indices that will flat index arrays.\n        # This is necessary for the Array API as such indices are not supported.\n        self.allow_fewer_indices_than_dims = allow_fewer_indices_than_dims\n\n    def do_draw(self, data):\n        # General plan: determine the actual selection up front with a straightforward\n        # approach that shrinks well, then complicate it by inserting other things.\n        result = []\n        for dim_size in self.shape:\n            if dim_size == 0:\n                result.append(slice(None))\n                continue\n            strategy = st.integers(-dim_size, dim_size - 1) | st.slices(dim_size)\n            result.append(data.draw(strategy))\n        # Insert some number of new size-one dimensions if allowed\n        result_dims = sum(isinstance(idx, slice) for idx in result)\n        while (\n            self.allow_newaxis\n            and result_dims < self.max_dims\n            and (result_dims < self.min_dims or data.draw(st.booleans()))\n        ):\n            i = data.draw(st.integers(0, len(result)))\n            result.insert(i, None)  # Note that `np.newaxis is None`\n            result_dims += 1\n        # Check that we'll have the right number of dimensions; reject if not.\n        # It's easy to do this by construction if you don't care about shrinking,\n        # which is really important for array shapes.  So we filter instead.\n        assume(self.min_dims <= result_dims <= self.max_dims)\n        # This is a quick-and-dirty way to insert ..., xor shorten the indexer,\n        # but it means we don't have to do any structural analysis.\n        if self.allow_ellipsis and data.draw(st.booleans()):\n            # Choose an index; then replace all adjacent whole-dimension slices.\n            i = j = data.draw(st.integers(0, len(result)))\n            while i > 0 and result[i - 1] == slice(None):\n                i -= 1\n            while j < len(result) and result[j] == slice(None):\n                j += 1\n            result[i:j] = [Ellipsis]\n        elif self.allow_fewer_indices_than_dims:  # pragma: no cover\n            while result[-1:] == [slice(None, None)] and data.draw(st.integers(0, 7)):\n                result.pop()\n        if len(result) == 1 and data.draw(st.booleans()):\n            # Sometimes generate bare element equivalent to a length-one tuple\n            return result[0]\n        return tuple(result)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/_patching.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\nWrite patches which add @example() decorators for discovered test cases.\n\nRequires `hypothesis[codemods,ghostwriter]` installed, i.e. black and libcst.\n\nThis module is used by Hypothesis' builtin pytest plugin for failing examples\ndiscovered during testing, and by HypoFuzz for _covering_ examples discovered\nduring fuzzing.\n\"\"\"\n\nimport ast\nimport difflib\nimport hashlib\nimport inspect\nimport re\nimport sys\nimport types\nfrom ast import literal_eval\nfrom collections.abc import Sequence\nfrom contextlib import suppress\nfrom datetime import date, datetime, timedelta, timezone\nfrom pathlib import Path\nfrom typing import Any\n\nimport libcst as cst\nfrom libcst import matchers as m\nfrom libcst.codemod import CodemodContext, VisitorBasedCodemodCommand\nfrom libcst.metadata import ExpressionContext, ExpressionContextProvider\n\nfrom hypothesis.configuration import storage_directory\nfrom hypothesis.version import __version__\n\ntry:\n    import black\nexcept ImportError:\n    black = None  # type: ignore\n\nHEADER = \"\"\"\\\nFrom HEAD Mon Sep 17 00:00:00 2001\nFrom: {author}\nDate: {when:%a, %d %b %Y %H:%M:%S}\nSubject: [PATCH] {msg}\n\n---\n\"\"\"\nFAIL_MSG = \"discovered failure\"\n_space_only_re = re.compile(\"^ +$\", re.MULTILINE)\n_leading_space_re = re.compile(\"(^[ ]*)(?:[^ \\n])\", re.MULTILINE)\n\n\ndef dedent(text: str) -> tuple[str, str]:\n    # Simplified textwrap.dedent, for valid Python source code only\n    text = _space_only_re.sub(\"\", text)\n    prefix = min(_leading_space_re.findall(text), key=len)\n    return re.sub(r\"(?m)^\" + prefix, \"\", text), prefix\n\n\ndef indent(text: str, prefix: str) -> str:\n    return \"\".join(prefix + line for line in text.splitlines(keepends=True))\n\n\nclass AddExamplesCodemod(VisitorBasedCodemodCommand):\n    DESCRIPTION = \"Add explicit examples to failing tests.\"\n\n    def __init__(\n        self,\n        context: CodemodContext,\n        fn_examples: dict[str, list[tuple[cst.Call, str]]],\n        strip_via: tuple[str, ...] = (),\n        decorator: str = \"example\",\n        width: int = 88,\n    ):\n        \"\"\"Add @example() decorator(s) for failing test(s).\n\n        `code` is the source code of the module where the test functions are defined.\n        `fn_examples` is a dict of function name to list-of-failing-examples.\n        \"\"\"\n        assert fn_examples, \"This codemod does nothing without fn_examples.\"\n        super().__init__(context)\n\n        self.decorator_func = cst.parse_expression(decorator)\n        self.line_length = width\n        value_in_strip_via: Any = m.MatchIfTrue(\n            lambda x: literal_eval(x.value) in strip_via\n        )\n        self.strip_matching = m.Call(\n            m.Attribute(m.Call(), m.Name(\"via\")),\n            [m.Arg(m.SimpleString() & value_in_strip_via)],\n        )\n\n        # Codemod the failing examples to Call nodes usable as decorators\n        self.fn_examples = {\n            k: tuple(\n                d\n                for (node, via) in nodes\n                if (d := self.__call_node_to_example_dec(node, via))\n            )\n            for k, nodes in fn_examples.items()\n        }\n\n    def __call_node_to_example_dec(\n        self, node: cst.Call, via: str\n    ) -> cst.Decorator | None:\n        # If we have black installed, remove trailing comma, _unless_ there's a comment\n        node = node.with_changes(\n            func=self.decorator_func,\n            args=(\n                [\n                    a.with_changes(\n                        comma=(\n                            a.comma\n                            if m.findall(a.comma, m.Comment())\n                            else cst.MaybeSentinel.DEFAULT\n                        )\n                    )\n                    for a in node.args\n                ]\n                if black\n                else node.args\n            ),\n        )\n        via: cst.BaseExpression = cst.Call(\n            func=cst.Attribute(node, cst.Name(\"via\")),\n            args=[cst.Arg(cst.SimpleString(repr(via)))],\n        )\n        if black:  # pragma: no branch\n            try:\n                pretty = black.format_str(\n                    cst.Module([]).code_for_node(via),\n                    mode=black.Mode(line_length=self.line_length),\n                )\n            except (ImportError, AttributeError):  # pragma: no cover\n                return None  # See https://github.com/psf/black/pull/4224\n            via = cst.parse_expression(pretty.strip())\n        return cst.Decorator(via)\n\n    def leave_FunctionDef(\n        self, _original_node: cst.FunctionDef, updated_node: cst.FunctionDef\n    ) -> cst.FunctionDef:\n        return updated_node.with_changes(\n            # TODO: improve logic for where in the list to insert this decorator\n            decorators=tuple(\n                d\n                for d in updated_node.decorators\n                # `findall()` to see through the identity function workaround on py38\n                if not m.findall(d, self.strip_matching)\n            )\n            + self.fn_examples.get(updated_node.name.value, ())\n        )\n\n\ndef get_patch_for(\n    func: Any,\n    examples: Sequence[tuple[str, str]],\n    *,\n    strip_via: tuple[str, ...] = (),\n) -> tuple[str, str, str] | None:\n    # Skip this if we're unable to find the location of this function.\n    try:\n        module = sys.modules[func.__module__]\n        file_path = Path(module.__file__)  # type: ignore\n    except Exception:\n        return None\n\n    fname = (\n        file_path.relative_to(Path.cwd())\n        if file_path.is_relative_to(Path.cwd())\n        else file_path\n    )\n    patch = _get_patch_for(\n        func, examples, strip_via=strip_via, namespace=module.__dict__\n    )\n    if patch is None:\n        return None\n\n    (before, after) = patch\n    return (str(fname), before, after)\n\n\n# split out for easier testing of patches in hypofuzz, where the function to\n# apply the patch to may not be loaded in sys.modules.\ndef _get_patch_for(\n    func: Any,\n    examples: Sequence[tuple[str, str]],\n    *,\n    strip_via: tuple[str, ...] = (),\n    namespace: dict[str, Any],\n) -> tuple[str, str] | None:\n    try:\n        before = inspect.getsource(func)\n    except Exception:  # pragma: no cover\n        return None\n\n    modules_in_test_scope = sorted(\n        ((k, v) for (k, v) in namespace.items() if isinstance(v, types.ModuleType)),\n        key=lambda kv: len(kv[1].__name__),\n    )\n\n    # The printed examples might include object reprs which are invalid syntax,\n    # so we parse here and skip over those.  If _none_ are valid, there's no patch.\n    call_nodes: list[tuple[cst.Call, str]] = []\n\n    # we want to preserve order, but remove duplicates.\n    seen_examples = set()\n    for ex, via in examples:\n        if (ex, via) in seen_examples:\n            continue\n        seen_examples.add((ex, via))\n\n        with suppress(Exception):\n            node: Any = cst.parse_module(ex)\n            the_call = node.body[0].body[0].value\n            assert isinstance(the_call, cst.Call), the_call\n            # Check for st.data(), which doesn't support explicit examples\n            data = m.Arg(m.Call(m.Name(\"data\"), args=[m.Arg(m.Ellipsis())]))\n            if m.matches(the_call, m.Call(args=[m.ZeroOrMore(), data, m.ZeroOrMore()])):\n                return None\n\n            # Many reprs use the unqualified name of the type, e.g. np.array()\n            # -> array([...]), so here we find undefined names and look them up\n            # on each module which was in the test's global scope.\n            names = {}\n            for anode in ast.walk(ast.parse(ex, \"eval\")):\n                if (\n                    isinstance(anode, ast.Name)\n                    and isinstance(anode.ctx, ast.Load)\n                    and anode.id not in names\n                    and anode.id not in namespace\n                ):\n                    for k, v in modules_in_test_scope:\n                        if anode.id in v.__dict__:\n                            names[anode.id] = cst.parse_expression(f\"{k}.{anode.id}\")\n                            break\n\n            # LibCST doesn't track Load()/Store() state of names by default, so we have\n            # to do a bit of a dance here, *and* explicitly handle keyword arguments\n            # which are treated as Load() context - but even if that's fixed later\n            # we'll still want to support older versions.\n            with suppress(Exception):\n                wrapper = cst.metadata.MetadataWrapper(node)\n                kwarg_names = {\n                    node.keyword  # type: ignore\n                    for node in m.findall(wrapper, m.Arg(keyword=m.Name()))\n                }\n                node = m.replace(\n                    wrapper,\n                    m.Name(value=m.MatchIfTrue(names.__contains__))\n                    & m.MatchMetadata(ExpressionContextProvider, ExpressionContext.LOAD)\n                    & m.MatchIfTrue(lambda n, k=kwarg_names: n not in k),  # type: ignore\n                    replacement=lambda node, _, ns=names: ns[node.value],  # type: ignore\n                )\n            node = node.body[0].body[0].value\n            assert isinstance(node, cst.Call), node\n            call_nodes.append((node, via))\n\n    if not call_nodes:\n        return None\n\n    if (\n        namespace.get(\"hypothesis\") is sys.modules[\"hypothesis\"]\n        and \"given\" not in namespace  # more reliably present than `example`\n    ):\n        decorator_func = \"hypothesis.example\"\n    else:\n        decorator_func = \"example\"\n\n    # Do the codemod and return a triple containing location and replacement info.\n    dedented, prefix = dedent(before)\n    try:\n        node = cst.parse_module(dedented)\n    except Exception:  # pragma: no cover\n        # inspect.getsource() sometimes returns a decorator alone, which is invalid\n        return None\n    after = AddExamplesCodemod(\n        CodemodContext(),\n        fn_examples={func.__name__: call_nodes},\n        strip_via=strip_via,\n        decorator=decorator_func,\n        width=88 - len(prefix),  # to match Black's default formatting\n    ).transform_module(node)\n    return (before, indent(after.code, prefix=prefix))\n\n\ndef make_patch(\n    triples: Sequence[tuple[str, str, str]],\n    *,\n    msg: str = \"Hypothesis: add explicit examples\",\n    when: datetime | None = None,\n    author: str = f\"Hypothesis {__version__} <no-reply@hypothesis.works>\",\n) -> str:\n    \"\"\"Create a patch for (fname, before, after) triples.\"\"\"\n    assert triples, \"attempted to create empty patch\"\n    when = when or datetime.now(tz=timezone.utc)\n\n    by_fname: dict[Path, list[tuple[str, str]]] = {}\n    for fname, before, after in triples:\n        by_fname.setdefault(Path(fname), []).append((before, after))\n\n    diffs = [HEADER.format(msg=msg, when=when, author=author)]\n    for fname, changes in sorted(by_fname.items()):\n        source_before = source_after = fname.read_text(encoding=\"utf-8\")\n        for before, after in changes:\n            source_after = source_after.replace(before.rstrip(), after.rstrip(), 1)\n        ud = difflib.unified_diff(\n            source_before.splitlines(keepends=True),\n            source_after.splitlines(keepends=True),\n            fromfile=f\"./{fname}\",  # git strips the first part of the path by default\n            tofile=f\"./{fname}\",\n        )\n        diffs.append(\"\".join(ud))\n    return \"\".join(diffs)\n\n\ndef save_patch(patch: str, *, slug: str = \"\") -> Path:  # pragma: no cover\n    assert re.fullmatch(r\"|[a-z]+-\", slug), f\"malformed {slug=}\"\n    now = date.today().isoformat()\n    cleaned = re.sub(r\"^Date: .+?$\", \"\", patch, count=1, flags=re.MULTILINE)\n    hash8 = hashlib.sha1(cleaned.encode()).hexdigest()[:8]\n    fname = Path(storage_directory(\"patches\", f\"{now}--{slug}{hash8}.patch\"))\n    fname.parent.mkdir(parents=True, exist_ok=True)\n    fname.write_text(patch, encoding=\"utf-8\")\n    return fname.relative_to(Path.cwd())\n\n\ndef gc_patches(slug: str = \"\") -> None:  # pragma: no cover\n    cutoff = date.today() - timedelta(days=7)\n    for fname in Path(storage_directory(\"patches\")).glob(\n        f\"????-??-??--{slug}????????.patch\"\n    ):\n        if date.fromisoformat(fname.stem.split(\"--\")[0]) < cutoff:\n            fname.unlink()\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/array_api.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nimport sys\nfrom collections.abc import Iterable, Iterator, Mapping, Sequence\nfrom numbers import Real\nfrom types import SimpleNamespace\nfrom typing import (\n    Any,\n    Literal,\n    NamedTuple,\n    TypeAlias,\n    TypeVar,\n    get_args,\n)\nfrom warnings import warn\nfrom weakref import WeakValueDictionary\n\nfrom hypothesis import strategies as st\nfrom hypothesis.errors import HypothesisWarning, InvalidArgument\nfrom hypothesis.extra._array_helpers import (\n    NDIM_MAX,\n    BasicIndex,\n    BasicIndexStrategy,\n    BroadcastableShapes,\n    Shape,\n    array_shapes,\n    broadcastable_shapes,\n    check_argument,\n    check_valid_dims,\n    mutually_broadcastable_shapes as _mutually_broadcastable_shapes,\n    order_check,\n    valid_tuple_axes as _valid_tuple_axes,\n)\nfrom hypothesis.internal.conjecture import utils as cu\nfrom hypothesis.internal.coverage import check_function\nfrom hypothesis.internal.floats import next_down\nfrom hypothesis.internal.reflection import proxies\nfrom hypothesis.internal.validation import (\n    check_type,\n    check_valid_bound,\n    check_valid_integer,\n    check_valid_interval,\n)\nfrom hypothesis.strategies._internal.strategies import check_strategy\nfrom hypothesis.strategies._internal.utils import defines_strategy\n\n__all__ = [\n    \"make_strategies_namespace\",\n]\n\n\nRELEASED_VERSIONS = (\"2021.12\", \"2022.12\", \"2023.12\", \"2024.12\", \"2025.12\")\nNOMINAL_VERSIONS = (*RELEASED_VERSIONS, \"draft\")\nassert sorted(NOMINAL_VERSIONS) == list(NOMINAL_VERSIONS)  # sanity check\nNominalVersion = Literal[\"2021.12\", \"2022.12\", \"2023.12\", \"2024.12\", \"2025.12\", \"draft\"]\nassert get_args(NominalVersion) == NOMINAL_VERSIONS  # sanity check\n\n\nINT_NAMES = (\"int8\", \"int16\", \"int32\", \"int64\")\nUINT_NAMES = (\"uint8\", \"uint16\", \"uint32\", \"uint64\")\nALL_INT_NAMES = INT_NAMES + UINT_NAMES\nFLOAT_NAMES = (\"float32\", \"float64\")\nREAL_NAMES = ALL_INT_NAMES + FLOAT_NAMES\nCOMPLEX_NAMES = (\"complex64\", \"complex128\")\nNUMERIC_NAMES = REAL_NAMES + COMPLEX_NAMES\nDTYPE_NAMES = (\"bool\", *NUMERIC_NAMES)\n\nDataType = TypeVar(\"DataType\")\n\n\n@check_function\ndef check_xp_attributes(xp: Any, attributes: list[str]) -> None:\n    missing_attrs = [attr for attr in attributes if not hasattr(xp, attr)]\n    if len(missing_attrs) > 0:\n        f_attrs = \", \".join(missing_attrs)\n        raise InvalidArgument(\n            f\"Array module {xp.__name__} does not have required attributes: {f_attrs}\"\n        )\n\n\ndef partition_attributes_and_stubs(\n    xp: Any, attributes: Iterable[str]\n) -> tuple[list[Any], list[str]]:\n    non_stubs = []\n    stubs = []\n    for attr in attributes:\n        try:\n            non_stubs.append(getattr(xp, attr))\n        except AttributeError:\n            stubs.append(attr)\n\n    return non_stubs, stubs\n\n\ndef warn_on_missing_dtypes(xp: Any, stubs: list[str]) -> None:\n    f_stubs = \", \".join(stubs)\n    warn(\n        f\"Array module {xp.__name__} does not have the following \"\n        f\"dtypes in its namespace: {f_stubs}\",\n        HypothesisWarning,\n        stacklevel=3,\n    )\n\n\ndef find_castable_builtin_for_dtype(\n    xp: Any, api_version: NominalVersion, dtype: DataType\n) -> type[bool | int | float | complex]:\n    \"\"\"Returns builtin type which can have values that are castable to the given\n    dtype, according to :xp-ref:`type promotion rules <type_promotion.html>`.\n\n    For floating dtypes we always return ``float``, even though ``int`` is also castable.\n    \"\"\"\n    stubs = []\n\n    try:\n        bool_dtype = xp.bool\n        if dtype == bool_dtype:\n            return bool\n    except AttributeError:\n        stubs.append(\"bool\")\n\n    int_dtypes, int_stubs = partition_attributes_and_stubs(xp, ALL_INT_NAMES)\n    if dtype in int_dtypes:\n        return int\n\n    float_dtypes, float_stubs = partition_attributes_and_stubs(xp, FLOAT_NAMES)\n    # None equals NumPy's xp.float64 object, so we specifically skip it here to\n    # ensure that InvalidArgument is still raised. xp.float64 is in fact an\n    # alias of np.dtype('float64'), and its equality with None is meant to be\n    # deprecated at some point. See https://github.com/numpy/numpy/issues/18434\n    if dtype is not None and dtype in float_dtypes:\n        return float\n\n    stubs.extend(int_stubs)\n    stubs.extend(float_stubs)\n\n    if api_version > \"2021.12\":\n        complex_dtypes, complex_stubs = partition_attributes_and_stubs(\n            xp, COMPLEX_NAMES\n        )\n        if dtype in complex_dtypes:\n            return complex\n        stubs.extend(complex_stubs)\n\n    if len(stubs) > 0:\n        warn_on_missing_dtypes(xp, stubs)\n    raise InvalidArgument(f\"dtype={dtype} not recognised in {xp.__name__}\")\n\n\n@check_function\ndef dtype_from_name(xp: Any, name: str) -> Any:\n    if name in DTYPE_NAMES:\n        try:\n            return getattr(xp, name)\n        except AttributeError as e:\n            raise InvalidArgument(\n                f\"Array module {xp.__name__} does not have dtype {name} in its namespace\"\n            ) from e\n    else:\n        f_valid_dtypes = \", \".join(DTYPE_NAMES)\n        raise InvalidArgument(\n            f\"{name} is not a valid Array API data type (pick from: {f_valid_dtypes})\"\n        )\n\n\ndef _from_dtype(\n    xp: Any,\n    api_version: NominalVersion,\n    dtype: DataType | str,\n    *,\n    min_value: int | float | None = None,\n    max_value: int | float | None = None,\n    allow_nan: bool | None = None,\n    allow_infinity: bool | None = None,\n    allow_subnormal: bool | None = None,\n    exclude_min: bool | None = None,\n    exclude_max: bool | None = None,\n) -> st.SearchStrategy[bool | int | float | complex]:\n    \"\"\"Return a strategy for any value of the given dtype.\n\n    Values generated are of the Python scalar which is\n    :xp-ref:`promotable <type_promotion.html>` to ``dtype``, where the values do\n    not exceed its bounds.\n\n    * ``dtype`` may be a dtype object or the string name of a\n      :xp-ref:`valid dtype <data_types.html>`.\n\n    Compatible ``**kwargs`` are passed to the inferred strategy function for\n    integers and floats.  This allows you to customise the min and max values,\n    and exclude non-finite numbers. This is particularly useful when kwargs are\n    passed through from :func:`arrays()`, as it seamlessly handles the ``width``\n    or other representable bounds for you.\n    \"\"\"\n    # TODO: for next released xp version, add note for complex dtype support\n    check_xp_attributes(xp, [\"iinfo\", \"finfo\"])\n\n    if isinstance(dtype, str):\n        dtype = dtype_from_name(xp, dtype)\n    builtin = find_castable_builtin_for_dtype(xp, api_version, dtype)\n\n    def check_valid_minmax(prefix, val, info_obj):\n        name = f\"{prefix}_value\"\n        check_valid_bound(val, name)\n        check_argument(\n            val >= info_obj.min,\n            f\"dtype={dtype} requires {name}={val} to be at least {info_obj.min}\",\n        )\n        check_argument(\n            val <= info_obj.max,\n            f\"dtype={dtype} requires {name}={val} to be at most {info_obj.max}\",\n        )\n\n    if builtin is bool:\n        return st.booleans()\n    elif builtin is int:\n        iinfo = xp.iinfo(dtype)\n        if min_value is None:\n            min_value = iinfo.min\n        if max_value is None:\n            max_value = iinfo.max\n        check_valid_integer(min_value, \"min_value\")\n        check_valid_integer(max_value, \"max_value\")\n        assert isinstance(min_value, int)\n        assert isinstance(max_value, int)\n        check_valid_minmax(\"min\", min_value, iinfo)\n        check_valid_minmax(\"max\", max_value, iinfo)\n        check_valid_interval(min_value, max_value, \"min_value\", \"max_value\")\n        return st.integers(min_value=min_value, max_value=max_value)\n    elif builtin is float:\n        finfo = xp.finfo(dtype)\n        kw = {}\n\n        # Whilst we know the boundary values of float dtypes from finfo, we do\n        # not assign them to the floats() strategy by default - passing min/max\n        # values will modify test case reduction behaviour so that simple bugs\n        # may become harder for users to identify. We plan to improve floats()\n        # behaviour in https://github.com/HypothesisWorks/hypothesis/issues/2907.\n        # Setting width should manage boundary values for us anyway.\n        if min_value is not None:\n            check_valid_bound(min_value, \"min_value\")\n            assert isinstance(min_value, Real)\n            check_valid_minmax(\"min\", min_value, finfo)\n            kw[\"min_value\"] = min_value\n        if max_value is not None:\n            check_valid_bound(max_value, \"max_value\")\n            assert isinstance(max_value, Real)\n            check_valid_minmax(\"max\", max_value, finfo)\n            if min_value is not None:\n                check_valid_interval(min_value, max_value, \"min_value\", \"max_value\")\n            kw[\"max_value\"] = max_value\n\n        # We infer whether an array module will flush subnormals to zero, as may\n        # be the case when libraries are built with compiler options that\n        # violate IEEE-754 (e.g. -ffast-math and -ftz=true). Note we do this for\n        # the specific dtype, as compilers may end up flushing subnormals for\n        # one float but supporting subnormals for the other.\n        #\n        # By default, floats() will generate subnormals if they are in the\n        # inferred values range. If we have detected that xp flushes to zero for\n        # the passed dtype, we ensure from_dtype() will not generate subnormals\n        # by default.\n        if allow_subnormal is not None:\n            kw[\"allow_subnormal\"] = allow_subnormal\n        else:\n            subnormal = next_down(float(finfo.smallest_normal), width=finfo.bits)\n            ftz = bool(xp.asarray(subnormal, dtype=dtype) == 0)\n            if ftz:\n                kw[\"allow_subnormal\"] = False\n\n        if allow_nan is not None:\n            kw[\"allow_nan\"] = allow_nan\n        if allow_infinity is not None:\n            kw[\"allow_infinity\"] = allow_infinity\n        if exclude_min is not None:\n            kw[\"exclude_min\"] = exclude_min\n        if exclude_max is not None:\n            kw[\"exclude_max\"] = exclude_max\n\n        return st.floats(width=finfo.bits, **kw)\n    else:\n        finfo = xp.finfo(dtype)\n        # See above comment on FTZ inference. We explicitly infer with a\n        # complex array, in case complex arrays have different FTZ behaviour\n        # than arrays of the respective composite float.\n        if allow_subnormal is None:\n            subnormal = next_down(float(finfo.smallest_normal), width=finfo.bits)\n            x = xp.asarray(complex(subnormal, subnormal), dtype=dtype)\n            builtin_x = complex(x)\n            allow_subnormal = builtin_x.real != 0 and builtin_x.imag != 0\n        return st.complex_numbers(\n            allow_nan=allow_nan,\n            allow_infinity=allow_infinity,\n            allow_subnormal=allow_subnormal,\n            width=finfo.bits * 2,\n        )\n\n\nclass ArrayStrategy(st.SearchStrategy):\n    def __init__(\n        self, *, xp, api_version, elements_strategy, dtype, shape, fill, unique\n    ):\n        super().__init__()\n        self.xp = xp\n        self.elements_strategy = elements_strategy\n        self.dtype = dtype\n        self.shape = shape\n        self.fill = fill\n        self.unique = unique\n        self.array_size = math.prod(shape)\n        self.builtin = find_castable_builtin_for_dtype(xp, api_version, dtype)\n        self.finfo = None if self.builtin is not float else xp.finfo(self.dtype)\n\n    def check_set_value(self, val, val_0d, strategy):\n        if val == val and self.builtin(val_0d) != val:\n            if self.builtin is float:\n                assert self.finfo is not None  # for mypy\n                try:\n                    is_subnormal = 0 < abs(val) < self.finfo.smallest_normal\n                except Exception:\n                    # val may be a non-float that does not support the\n                    # operations __lt__ and __abs__\n                    is_subnormal = False\n                if is_subnormal:\n                    raise InvalidArgument(\n                        f\"Generated subnormal float {val} from strategy \"\n                        f\"{strategy} resulted in {val_0d!r}, probably \"\n                        f\"as a result of array module {self.xp.__name__} \"\n                        \"being built with flush-to-zero compiler options. \"\n                        \"Consider passing allow_subnormal=False.\"\n                    )\n            raise InvalidArgument(\n                f\"Generated array element {val!r} from strategy {strategy} \"\n                f\"cannot be represented with dtype {self.dtype}. \"\n                f\"Array module {self.xp.__name__} instead \"\n                f\"represents the element as {val_0d}. \"\n                \"Consider using a more precise elements strategy, \"\n                \"for example passing the width argument to floats().\"\n            )\n\n    def do_draw(self, data):\n        if 0 in self.shape:\n            return self.xp.zeros(self.shape, dtype=self.dtype)\n\n        if self.fill.is_empty:\n            # We have no fill value (either because the user explicitly\n            # disabled it or because the default behaviour was used and our\n            # elements strategy does not produce reusable values), so we must\n            # generate a fully dense array with a freshly drawn value for each\n            # entry.\n            elems = data.draw(\n                st.lists(\n                    self.elements_strategy,\n                    min_size=self.array_size,\n                    max_size=self.array_size,\n                    unique=self.unique,\n                )\n            )\n            try:\n                result = self.xp.asarray(elems, dtype=self.dtype)\n            except Exception as e:\n                if len(elems) <= 6:\n                    f_elems = str(elems)\n                else:\n                    f_elems = f\"[{elems[0]}, {elems[1]}, ..., {elems[-2]}, {elems[-1]}]\"\n                types = tuple(\n                    sorted({type(e) for e in elems}, key=lambda t: t.__name__)\n                )\n                f_types = f\"type {types[0]}\" if len(types) == 1 else f\"types {types}\"\n                raise InvalidArgument(\n                    f\"Generated elements {f_elems} from strategy \"\n                    f\"{self.elements_strategy} could not be converted \"\n                    f\"to array of dtype {self.dtype}. \"\n                    f\"Consider if elements of {f_types} \"\n                    f\"are compatible with {self.dtype}.\"\n                ) from e\n            for i in range(self.array_size):\n                self.check_set_value(elems[i], result[i], self.elements_strategy)\n        else:\n            # We draw arrays as \"sparse with an offset\". We assume not every\n            # element will be assigned and so first draw a single value from our\n            # fill strategy to create a full array. We then draw a collection of\n            # index assignments within the array and assign fresh values from\n            # our elements strategy to those indices.\n\n            fill_val = data.draw(self.fill)\n            result_obj = [fill_val for _ in range(self.array_size)]\n            fill_mask = [True for _ in range(self.array_size)]\n\n            elements = cu.many(\n                data,\n                min_size=0,\n                max_size=self.array_size,\n                # sqrt isn't chosen for any particularly principled reason. It\n                # just grows reasonably quickly but sublinearly, and for small\n                # arrays it represents a decent fraction of the array size.\n                average_size=min(\n                    0.9 * self.array_size,  # ensure small arrays sometimes use fill\n                    max(10, math.sqrt(self.array_size)),  # ...but *only* sometimes\n                ),\n            )\n\n            assigned = set()\n            seen = set()\n\n            while elements.more():\n                i = data.draw_integer(0, self.array_size - 1)\n                if i in assigned:\n                    elements.reject(\"chose an array index we've already used\")\n                    continue\n                val = data.draw(self.elements_strategy)\n                if self.unique:\n                    if val in seen:\n                        elements.reject(\"chose an element we've already used\")\n                        continue\n                    seen.add(val)\n\n                result_obj[i] = val\n                assigned.add(i)\n                fill_mask[i] = False\n\n            try:\n                result = self.xp.asarray(result_obj, dtype=self.dtype)\n            except Exception as e:\n                f_expr = f\"xp.asarray({result_obj}, dtype={self.dtype})\"\n                raise InvalidArgument(f\"Could not create array via {f_expr}\") from e\n\n            for i, val in enumerate(result_obj):\n                val_0d = result[i]\n                if fill_mask[i] and self.unique:\n                    if not self.xp.isnan(val_0d):\n                        raise InvalidArgument(\n                            f\"Array module {self.xp.__name__} did not recognise fill \"\n                            f\"value {fill_val!r} as NaN - instead got {val_0d!r}. \"\n                            \"Cannot fill unique array with non-NaN values.\"\n                        )\n                else:\n                    self.check_set_value(val, val_0d, self.elements_strategy)\n\n        return self.xp.reshape(result, self.shape)\n\n\ndef _arrays(\n    xp: Any,\n    api_version: NominalVersion,\n    dtype: DataType | str | st.SearchStrategy[DataType] | st.SearchStrategy[str],\n    shape: int | Shape | st.SearchStrategy[Shape],\n    *,\n    elements: Mapping[str, Any] | st.SearchStrategy | None = None,\n    fill: st.SearchStrategy[Any] | None = None,\n    unique: bool = False,\n) -> st.SearchStrategy:\n    \"\"\"Returns a strategy for :xp-ref:`arrays <array_object.html>`.\n\n    * ``dtype`` may be a :xp-ref:`valid dtype <data_types.html>` object or name,\n      or a strategy that generates such values.\n    * ``shape`` may be an integer >= 0, a tuple of such integers, or a strategy\n      that generates such values.\n    * ``elements`` is a strategy for values to put in the array. If ``None``\n      then a suitable value will be inferred based on the dtype, which may give\n      any legal value (including e.g. NaN for floats). If a mapping, it will be\n      passed as ``**kwargs`` to :func:`from_dtype()` when inferring based on the dtype.\n    * ``fill`` is a strategy that may be used to generate a single background\n      value for the array. If ``None``, a suitable default will be inferred\n      based on the other arguments. If set to\n      :func:`~hypothesis.strategies.nothing` then filling behaviour will be\n      disabled entirely and every element will be generated independently.\n    * ``unique`` specifies if the elements of the array should all be distinct\n      from one another; if fill is also set, the only valid values for fill to\n      return are NaN values.\n\n    Arrays of specified ``dtype`` and ``shape`` are generated for example\n    like this:\n\n    .. code-block:: pycon\n\n      >>> from numpy import array_api as xp\n      >>> xps.arrays(xp, xp.int8, (2, 3)).example()\n      Array([[-8,  6,  3],\n             [-6,  4,  6]], dtype=int8)\n\n    Specifying element boundaries by a :obj:`python:dict` of the kwargs to pass\n    to :func:`from_dtype` will ensure ``dtype`` bounds will be respected.\n\n    .. code-block:: pycon\n\n      >>> xps.arrays(xp, xp.int8, 3, elements={\"min_value\": 10}).example()\n      Array([125, 13, 79], dtype=int8)\n\n    .. code-block:: pycon\n\n      >>> xps.arrays(xp, xp.float32, 3, elements=floats(0, 1, width=32)).example()\n      Array([ 0.88974794,  0.77387938,  0.1977879 ], dtype=float32)\n\n    Array values are generated in two parts:\n\n    1. A single value is drawn from the fill strategy and is used to create a\n       filled array.\n    2. Some subset of the coordinates of the array are populated with a value\n       drawn from the elements strategy (or its inferred form).\n\n    You can set ``fill`` to :func:`~hypothesis.strategies.nothing` if you want\n    to disable this behaviour and draw a value for every element.\n\n    By default ``arrays`` will attempt to infer the correct fill behaviour: if\n    ``unique`` is also ``True``, no filling will occur. Otherwise, if it looks\n    safe to reuse the values of elements across multiple coordinates (this will\n    be the case for any inferred strategy, and for most of the builtins, but is\n    not the case for mutable values or strategies built with flatmap, map,\n    composite, etc.) then it will use the elements strategy as the fill, else it\n    will default to having no fill.\n\n    Having a fill helps Hypothesis craft high quality examples, but its\n    main importance is when the array generated is large: Hypothesis is\n    primarily designed around testing small examples. If you have arrays with\n    hundreds or more elements, having a fill value is essential if you want\n    your tests to run in reasonable time.\n    \"\"\"\n    check_xp_attributes(\n        xp, [\"finfo\", \"asarray\", \"zeros\", \"all\", \"isnan\", \"isfinite\", \"reshape\"]\n    )\n\n    if isinstance(dtype, st.SearchStrategy):\n        return dtype.flatmap(\n            lambda d: _arrays(\n                xp, api_version, d, shape, elements=elements, fill=fill, unique=unique\n            )\n        )\n    elif isinstance(dtype, str):\n        dtype = dtype_from_name(xp, dtype)\n\n    if isinstance(shape, st.SearchStrategy):\n        return shape.flatmap(\n            lambda s: _arrays(\n                xp, api_version, dtype, s, elements=elements, fill=fill, unique=unique\n            )\n        )\n    elif isinstance(shape, int):\n        shape = (shape,)\n    elif not isinstance(shape, tuple):\n        raise InvalidArgument(f\"shape={shape} is not a valid shape or strategy\")\n    check_argument(\n        all(isinstance(x, int) and x >= 0 for x in shape),\n        f\"{shape=}, but all dimensions must be non-negative integers.\",\n    )\n\n    if elements is None:\n        elements = _from_dtype(xp, api_version, dtype)\n    elif isinstance(elements, Mapping):\n        elements = _from_dtype(xp, api_version, dtype, **elements)\n    check_strategy(elements, \"elements\")\n\n    if fill is None:\n        assert isinstance(elements, st.SearchStrategy)  # for mypy\n        if unique or not elements.has_reusable_values:\n            fill = st.nothing()\n        else:\n            fill = elements\n    check_strategy(fill, \"fill\")\n\n    return ArrayStrategy(\n        xp=xp,\n        api_version=api_version,\n        elements_strategy=elements,\n        dtype=dtype,\n        shape=shape,\n        fill=fill,\n        unique=unique,\n    )\n\n\n@check_function\ndef check_dtypes(xp: Any, dtypes: list[DataType], stubs: list[str]) -> None:\n    if len(dtypes) == 0:\n        assert len(stubs) > 0, \"No dtypes passed but stubs is empty\"\n        f_stubs = \", \".join(stubs)\n        raise InvalidArgument(\n            f\"Array module {xp.__name__} does not have the following \"\n            f\"required dtypes in its namespace: {f_stubs}\"\n        )\n    elif len(stubs) > 0:\n        warn_on_missing_dtypes(xp, stubs)\n\n\ndef _scalar_dtypes(xp: Any, api_version: NominalVersion) -> st.SearchStrategy[DataType]:\n    \"\"\"Return a strategy for all :xp-ref:`valid dtype <data_types.html>` objects.\"\"\"\n    return st.one_of(_boolean_dtypes(xp), _numeric_dtypes(xp, api_version))\n\n\ndef _boolean_dtypes(xp: Any) -> st.SearchStrategy[DataType]:\n    \"\"\"Return a strategy for just the boolean dtype object.\"\"\"\n    try:\n        return st.just(xp.bool)\n    except AttributeError:\n        raise InvalidArgument(\n            f\"Array module {xp.__name__} does not have a bool dtype in its namespace\"\n        ) from None\n\n\ndef _real_dtypes(xp: Any) -> st.SearchStrategy[DataType]:\n    \"\"\"Return a strategy for all real-valued dtype objects.\"\"\"\n    return st.one_of(\n        _integer_dtypes(xp),\n        _unsigned_integer_dtypes(xp),\n        _floating_dtypes(xp),\n    )\n\n\ndef _numeric_dtypes(\n    xp: Any, api_version: NominalVersion\n) -> st.SearchStrategy[DataType]:\n    \"\"\"Return a strategy for all numeric dtype objects.\"\"\"\n    strat: st.SearchStrategy[DataType] = _real_dtypes(xp)\n    if api_version > \"2021.12\":\n        strat |= _complex_dtypes(xp)\n    return strat\n\n\n@check_function\ndef check_valid_sizes(\n    category: str, sizes: Sequence[int], valid_sizes: Sequence[int]\n) -> None:\n    check_argument(len(sizes) > 0, \"No sizes passed\")\n\n    invalid_sizes = [s for s in sizes if s not in valid_sizes]\n    f_valid_sizes = \", \".join(str(s) for s in valid_sizes)\n    f_invalid_sizes = \", \".join(str(s) for s in invalid_sizes)\n    check_argument(\n        len(invalid_sizes) == 0,\n        f\"The following sizes are not valid for {category} dtypes: \"\n        f\"{f_invalid_sizes} (valid sizes: {f_valid_sizes})\",\n    )\n\n\ndef numeric_dtype_names(base_name: str, sizes: Sequence[int]) -> Iterator[str]:\n    for size in sizes:\n        yield f\"{base_name}{size}\"\n\n\nIntSize: TypeAlias = Literal[8, 16, 32, 64]\nFltSize: TypeAlias = Literal[32, 64]\nCpxSize: TypeAlias = Literal[64, 128]\n\n\ndef _integer_dtypes(\n    xp: Any, *, sizes: IntSize | Sequence[IntSize] = (8, 16, 32, 64)\n) -> st.SearchStrategy[DataType]:\n    \"\"\"Return a strategy for signed integer dtype objects.\n\n    ``sizes`` contains the signed integer sizes in bits, defaulting to\n    ``(8, 16, 32, 64)`` which covers all valid sizes.\n    \"\"\"\n    if isinstance(sizes, int):\n        sizes = (sizes,)\n    check_valid_sizes(\"int\", sizes, (8, 16, 32, 64))\n    dtypes, stubs = partition_attributes_and_stubs(\n        xp, numeric_dtype_names(\"int\", sizes)\n    )\n    check_dtypes(xp, dtypes, stubs)\n    return st.sampled_from(dtypes)\n\n\ndef _unsigned_integer_dtypes(\n    xp: Any, *, sizes: IntSize | Sequence[IntSize] = (8, 16, 32, 64)\n) -> st.SearchStrategy[DataType]:\n    \"\"\"Return a strategy for unsigned integer dtype objects.\n\n    ``sizes`` contains the unsigned integer sizes in bits, defaulting to\n    ``(8, 16, 32, 64)`` which covers all valid sizes.\n    \"\"\"\n    if isinstance(sizes, int):\n        sizes = (sizes,)\n    check_valid_sizes(\"int\", sizes, (8, 16, 32, 64))\n\n    dtypes, stubs = partition_attributes_and_stubs(\n        xp, numeric_dtype_names(\"uint\", sizes)\n    )\n    check_dtypes(xp, dtypes, stubs)\n\n    return st.sampled_from(dtypes)\n\n\ndef _floating_dtypes(\n    xp: Any, *, sizes: FltSize | Sequence[FltSize] = (32, 64)\n) -> st.SearchStrategy[DataType]:\n    \"\"\"Return a strategy for real-valued floating-point dtype objects.\n\n    ``sizes`` contains the floating-point sizes in bits, defaulting to\n    ``(32, 64)`` which covers all valid sizes.\n    \"\"\"\n    if isinstance(sizes, int):\n        sizes = (sizes,)\n    check_valid_sizes(\"int\", sizes, (32, 64))\n    dtypes, stubs = partition_attributes_and_stubs(\n        xp, numeric_dtype_names(\"float\", sizes)\n    )\n    check_dtypes(xp, dtypes, stubs)\n    return st.sampled_from(dtypes)\n\n\ndef _complex_dtypes(\n    xp: Any, *, sizes: CpxSize | Sequence[CpxSize] = (64, 128)\n) -> st.SearchStrategy[DataType]:\n    \"\"\"Return a strategy for complex dtype objects.\n\n    ``sizes`` contains the complex sizes in bits, defaulting to ``(64, 128)``\n    which covers all valid sizes.\n    \"\"\"\n    if isinstance(sizes, int):\n        sizes = (sizes,)\n    check_valid_sizes(\"complex\", sizes, (64, 128))\n    dtypes, stubs = partition_attributes_and_stubs(\n        xp, numeric_dtype_names(\"complex\", sizes)\n    )\n    check_dtypes(xp, dtypes, stubs)\n    return st.sampled_from(dtypes)\n\n\n@proxies(_valid_tuple_axes)\ndef valid_tuple_axes(*args, **kwargs):\n    return _valid_tuple_axes(*args, **kwargs)\n\n\nvalid_tuple_axes.__doc__ = f\"\"\"\n    Return a strategy for permissible tuple-values for the ``axis``\n    argument in Array API sequential methods e.g. ``sum``, given the specified\n    dimensionality.\n\n    {_valid_tuple_axes.__doc__}\n    \"\"\"\n\n\n@defines_strategy()\ndef mutually_broadcastable_shapes(\n    num_shapes: int,\n    *,\n    base_shape: Shape = (),\n    min_dims: int = 0,\n    max_dims: int | None = None,\n    min_side: int = 1,\n    max_side: int | None = None,\n) -> st.SearchStrategy[BroadcastableShapes]:\n    return _mutually_broadcastable_shapes(\n        num_shapes=num_shapes,\n        base_shape=base_shape,\n        min_dims=min_dims,\n        max_dims=max_dims,\n        min_side=min_side,\n        max_side=max_side,\n    )\n\n\nmutually_broadcastable_shapes.__doc__ = _mutually_broadcastable_shapes.__doc__\n\n\n@defines_strategy()\ndef indices(\n    shape: Shape,\n    *,\n    min_dims: int = 0,\n    max_dims: int | None = None,\n    allow_newaxis: bool = False,\n    allow_ellipsis: bool = True,\n) -> st.SearchStrategy[BasicIndex]:\n    \"\"\"Return a strategy for :xp-ref:`valid indices <indexing.html>` of\n    arrays with the specified shape, which may include dimensions of size zero.\n\n    It generates tuples containing some mix of integers, :obj:`python:slice`\n    objects, ``...`` (an ``Ellipsis``), and ``None``. When a length-one tuple\n    would be generated, this strategy may instead return the element which will\n    index the first axis, e.g. ``5`` instead of ``(5,)``.\n\n    * ``shape`` is the shape of the array that will be indexed, as a tuple of\n      integers >= 0. This must be at least two-dimensional for a tuple to be a\n      valid index;  for one-dimensional arrays use\n      :func:`~hypothesis.strategies.slices` instead.\n    * ``min_dims`` is the minimum dimensionality of the resulting array from use\n      of the generated index.\n    * ``max_dims`` is the maximum dimensionality of the resulting array,\n      defaulting to ``len(shape) if not allow_newaxis else\n      max(len(shape), min_dims) + 2``.\n    * ``allow_ellipsis`` specifies whether ``None`` is allowed in the index.\n    * ``allow_ellipsis`` specifies whether ``...`` is allowed in the index.\n    \"\"\"\n    check_type(tuple, shape, \"shape\")\n    check_argument(\n        all(isinstance(x, int) and x >= 0 for x in shape),\n        f\"{shape=}, but all dimensions must be non-negative integers.\",\n    )\n    check_type(bool, allow_newaxis, \"allow_newaxis\")\n    check_type(bool, allow_ellipsis, \"allow_ellipsis\")\n    check_type(int, min_dims, \"min_dims\")\n    if not allow_newaxis:\n        check_argument(\n            min_dims <= len(shape),\n            f\"min_dims={min_dims} is larger than len(shape)={len(shape)}, \"\n            \"but it is impossible for an indexing operation to add dimensions \",\n            \"when allow_newaxis=False.\",\n        )\n    check_valid_dims(min_dims, \"min_dims\")\n\n    if max_dims is None:\n        if allow_newaxis:\n            max_dims = min(max(len(shape), min_dims) + 2, NDIM_MAX)\n        else:\n            max_dims = min(len(shape), NDIM_MAX)\n    check_type(int, max_dims, \"max_dims\")\n    assert isinstance(max_dims, int)\n    if not allow_newaxis:\n        check_argument(\n            max_dims <= len(shape),\n            f\"max_dims={max_dims} is larger than len(shape)={len(shape)}, \"\n            \"but it is impossible for an indexing operation to add dimensions \",\n            \"when allow_newaxis=False.\",\n        )\n    check_valid_dims(max_dims, \"max_dims\")\n\n    order_check(\"dims\", 0, min_dims, max_dims)\n\n    return BasicIndexStrategy(\n        shape,\n        min_dims=min_dims,\n        max_dims=max_dims,\n        allow_ellipsis=allow_ellipsis,\n        allow_newaxis=allow_newaxis,\n        allow_fewer_indices_than_dims=False,\n    )\n\n\n# Cache for make_strategies_namespace()\n_args_to_xps: WeakValueDictionary = WeakValueDictionary()\n\n\ndef make_strategies_namespace(\n    xp: Any, *, api_version: NominalVersion | None = None\n) -> SimpleNamespace:\n    \"\"\"Creates a strategies namespace for the given array module.\n\n    * ``xp`` is the Array API library to automatically pass to the namespaced methods.\n    * ``api_version`` is the version of the Array API which the returned\n      strategies namespace should conform to. If ``None``, the latest API\n      version which ``xp`` supports will be inferred from ``xp.__array_api_version__``.\n      If a version string in the ``YYYY.MM`` format, the strategies namespace\n      will conform to that version if supported.\n\n    A :obj:`python:types.SimpleNamespace` is returned which contains all the\n    strategy methods in this module but without requiring the ``xp`` argument.\n    Creating and using a strategies namespace for NumPy's Array API\n    implementation would go like this:\n\n    .. code-block:: pycon\n\n      >>> xp.__array_api_version__  # xp is your desired array library\n      '2021.12'\n      >>> xps = make_strategies_namespace(xp)\n      >>> xps.api_version\n      '2021.12'\n      >>> x = xps.arrays(xp.int8, (2, 3)).example()\n      >>> x\n      Array([[-8,  6,  3],\n             [-6,  4,  6]], dtype=int8)\n      >>> x.__array_namespace__() is xp\n      True\n\n    \"\"\"\n    not_available_msg = (\n        \"If the standard version you want is not available, please ensure \"\n        \"you're using the latest version of Hypothesis, then open an issue if \"\n        \"one doesn't already exist.\"\n    )\n    if api_version is None:\n        check_argument(\n            hasattr(xp, \"__array_api_version__\"),\n            f\"Array module {xp.__name__} has no attribute __array_api_version__, \"\n            \"which is required when inferring api_version. If you believe \"\n            f\"{xp.__name__} is indeed an Array API module, try explicitly \"\n            \"passing an api_version.\",\n        )\n        check_argument(\n            isinstance(xp.__array_api_version__, str)\n            and xp.__array_api_version__ in RELEASED_VERSIONS,\n            f\"{xp.__array_api_version__=}, but it must \"\n            f\"be a valid version string {RELEASED_VERSIONS}. {not_available_msg}\",\n        )\n        api_version = xp.__array_api_version__\n        inferred_version = True\n    else:\n        check_argument(\n            isinstance(api_version, str) and api_version in NOMINAL_VERSIONS,\n            f\"{api_version=}, but it must be None, or a valid version \"\n            f\"string in {RELEASED_VERSIONS}. {not_available_msg}\",\n        )\n        inferred_version = False\n    try:\n        array = xp.zeros(1)\n        array.__array_namespace__()\n    except Exception:\n        warn(\n            f\"Could not determine whether module {xp.__name__} is an Array API library\",\n            HypothesisWarning,\n            stacklevel=2,\n        )\n\n    try:\n        namespace = _args_to_xps[(xp, api_version)]\n    except (KeyError, TypeError):\n        pass\n    else:\n        return namespace\n\n    @defines_strategy(force_reusable_values=True)\n    def from_dtype(\n        dtype: DataType | str,\n        *,\n        min_value: int | float | None = None,\n        max_value: int | float | None = None,\n        allow_nan: bool | None = None,\n        allow_infinity: bool | None = None,\n        allow_subnormal: bool | None = None,\n        exclude_min: bool | None = None,\n        exclude_max: bool | None = None,\n    ) -> st.SearchStrategy[bool | int | float | complex]:\n        return _from_dtype(\n            xp,\n            api_version,\n            dtype,\n            min_value=min_value,\n            max_value=max_value,\n            allow_nan=allow_nan,\n            allow_infinity=allow_infinity,\n            allow_subnormal=allow_subnormal,\n            exclude_min=exclude_min,\n            exclude_max=exclude_max,\n        )\n\n    @defines_strategy(force_reusable_values=True)\n    def arrays(\n        dtype: DataType | str | st.SearchStrategy[DataType] | st.SearchStrategy[str],\n        shape: int | Shape | st.SearchStrategy[Shape],\n        *,\n        elements: Mapping[str, Any] | st.SearchStrategy | None = None,\n        fill: st.SearchStrategy[Any] | None = None,\n        unique: bool = False,\n    ) -> st.SearchStrategy:\n        return _arrays(\n            xp,\n            api_version,\n            dtype,\n            shape,\n            elements=elements,\n            fill=fill,\n            unique=unique,\n        )\n\n    @defines_strategy()\n    def scalar_dtypes() -> st.SearchStrategy[DataType]:\n        return _scalar_dtypes(xp, api_version)\n\n    @defines_strategy()\n    def boolean_dtypes() -> st.SearchStrategy[DataType]:\n        return _boolean_dtypes(xp)\n\n    @defines_strategy()\n    def real_dtypes() -> st.SearchStrategy[DataType]:\n        return _real_dtypes(xp)\n\n    @defines_strategy()\n    def numeric_dtypes() -> st.SearchStrategy[DataType]:\n        return _numeric_dtypes(xp, api_version)\n\n    @defines_strategy()\n    def integer_dtypes(\n        *, sizes: IntSize | Sequence[IntSize] = (8, 16, 32, 64)\n    ) -> st.SearchStrategy[DataType]:\n        return _integer_dtypes(xp, sizes=sizes)\n\n    @defines_strategy()\n    def unsigned_integer_dtypes(\n        *, sizes: IntSize | Sequence[IntSize] = (8, 16, 32, 64)\n    ) -> st.SearchStrategy[DataType]:\n        return _unsigned_integer_dtypes(xp, sizes=sizes)\n\n    @defines_strategy()\n    def floating_dtypes(\n        *, sizes: FltSize | Sequence[FltSize] = (32, 64)\n    ) -> st.SearchStrategy[DataType]:\n        return _floating_dtypes(xp, sizes=sizes)\n\n    from_dtype.__doc__ = _from_dtype.__doc__\n    arrays.__doc__ = _arrays.__doc__\n    scalar_dtypes.__doc__ = _scalar_dtypes.__doc__\n    boolean_dtypes.__doc__ = _boolean_dtypes.__doc__\n    real_dtypes.__doc__ = _real_dtypes.__doc__\n    numeric_dtypes.__doc__ = _numeric_dtypes.__doc__\n    integer_dtypes.__doc__ = _integer_dtypes.__doc__\n    unsigned_integer_dtypes.__doc__ = _unsigned_integer_dtypes.__doc__\n    floating_dtypes.__doc__ = _floating_dtypes.__doc__\n\n    class StrategiesNamespace(SimpleNamespace):\n        def __init__(self, **kwargs):\n            for attr in [\"name\", \"api_version\"]:\n                if attr not in kwargs:\n                    raise ValueError(f\"'{attr}' kwarg required\")\n            super().__init__(**kwargs)\n\n        @property\n        def complex_dtypes(self):\n            try:\n                return self.__dict__[\"complex_dtypes\"]\n            except KeyError as e:\n                raise AttributeError(\n                    \"You attempted to access 'complex_dtypes', but it is not \"\n                    f\"available for api_version='{self.api_version}' of \"\n                    f\"xp={self.name}.\"\n                ) from e\n\n        def __repr__(self):\n            f_args = self.name\n            if not inferred_version:\n                f_args += f\", api_version='{self.api_version}'\"\n            return f\"make_strategies_namespace({f_args})\"\n\n    kwargs = {\n        \"name\": xp.__name__,\n        \"api_version\": api_version,\n        \"from_dtype\": from_dtype,\n        \"arrays\": arrays,\n        \"array_shapes\": array_shapes,\n        \"scalar_dtypes\": scalar_dtypes,\n        \"boolean_dtypes\": boolean_dtypes,\n        \"real_dtypes\": real_dtypes,\n        \"numeric_dtypes\": numeric_dtypes,\n        \"integer_dtypes\": integer_dtypes,\n        \"unsigned_integer_dtypes\": unsigned_integer_dtypes,\n        \"floating_dtypes\": floating_dtypes,\n        \"valid_tuple_axes\": valid_tuple_axes,\n        \"broadcastable_shapes\": broadcastable_shapes,\n        \"mutually_broadcastable_shapes\": mutually_broadcastable_shapes,\n        \"indices\": indices,\n    }\n\n    if api_version > \"2021.12\":\n\n        @defines_strategy()\n        def complex_dtypes(\n            *, sizes: CpxSize | Sequence[CpxSize] = (64, 128)\n        ) -> st.SearchStrategy[DataType]:\n            return _complex_dtypes(xp, sizes=sizes)\n\n        complex_dtypes.__doc__ = _complex_dtypes.__doc__\n        kwargs[\"complex_dtypes\"] = complex_dtypes\n\n    namespace = StrategiesNamespace(**kwargs)\n    try:\n        _args_to_xps[(xp, api_version)] = namespace\n    except TypeError:\n        pass\n\n    return namespace\n\n\ntry:\n    import numpy as np\nexcept ImportError:\n    if \"sphinx\" in sys.modules:\n        # This is pretty awkward, but also the best way available\n        from unittest.mock import Mock\n\n        np = Mock()\n    else:\n        np = None  # type: ignore[assignment]\nif np is not None:\n\n    class FloatInfo(NamedTuple):\n        bits: int\n        eps: float\n        max: float\n        min: float\n        smallest_normal: float\n\n    def mock_finfo(dtype: DataType) -> FloatInfo:\n        \"\"\"Returns a finfo object compliant with the Array API\n\n        Ensures all attributes are Python scalars and not NumPy scalars. This\n        lets us ignore corner cases with how NumPy scalars operate, such as\n        NumPy floats breaking our next_down() util.\n\n        Also ensures the finfo obj has the smallest_normal attribute. NumPy only\n        introduced it in v1.21.1, so we just use the equivalent tiny attribute\n        to keep mocking with older versions working.\n        \"\"\"\n        _finfo = np.finfo(dtype)  # type: ignore[call-overload]\n        return FloatInfo(\n            int(_finfo.bits),\n            float(_finfo.eps),\n            float(_finfo.max),\n            float(_finfo.min),\n            float(_finfo.tiny),\n        )\n\n    mock_xp = SimpleNamespace(\n        __name__=\"mock\",\n        __array_api_version__=\"2022.12\",\n        # Data types\n        int8=np.int8,\n        int16=np.int16,\n        int32=np.int32,\n        int64=np.int64,\n        uint8=np.uint8,\n        uint16=np.uint16,\n        uint32=np.uint32,\n        uint64=np.uint64,\n        float32=np.float32,\n        float64=np.float64,\n        complex64=np.complex64,\n        complex128=np.complex128,\n        bool=np.bool_,\n        # Constants\n        nan=np.nan,\n        # Data type functions\n        astype=lambda x, d: x.astype(d),\n        iinfo=np.iinfo,\n        finfo=mock_finfo,\n        broadcast_arrays=np.broadcast_arrays,\n        # Creation functions\n        arange=np.arange,\n        asarray=np.asarray,\n        empty=np.empty,\n        zeros=np.zeros,\n        ones=np.ones,\n        # Manipulation functions\n        reshape=np.reshape,\n        # Element-wise functions\n        isnan=np.isnan,\n        isfinite=np.isfinite,\n        logical_or=np.logical_or,\n        # Statistical functions\n        sum=np.sum,\n        # Searching functions\n        nonzero=np.nonzero,\n        # Sorting functions\n        sort=np.sort,\n        # Set functions\n        unique_values=np.unique,\n        # Utility functions\n        any=np.any,\n        all=np.all,\n    )\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/cli.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\n::\n\n    $ hypothesis --help\n    Usage: hypothesis [OPTIONS] COMMAND [ARGS]...\n\n    Options:\n      --version   Show the version and exit.\n      -h, --help  Show this message and exit.\n\n    Commands:\n      codemod  `hypothesis codemod` refactors deprecated or inefficient code.\n      fuzz     [hypofuzz] runs tests with an adaptive coverage-guided fuzzer.\n      write    `hypothesis write` writes property-based tests for you!\n\nThis module requires the :pypi:`click` package, and provides Hypothesis' command-line\ninterface, for e.g. :ref:`'ghostwriting' tests <ghostwriter>` via the terminal.\nIt's also where `HypoFuzz <https://hypofuzz.com/>`__ adds the :command:`hypothesis fuzz`\ncommand (`learn more about that here <https://hypofuzz.com/docs/quickstart.html>`__).\n\"\"\"\n\nimport builtins\nimport importlib\nimport inspect\nimport sys\nimport types\nfrom difflib import get_close_matches\nfrom functools import partial\nfrom multiprocessing import Pool\nfrom pathlib import Path\n\ntry:\n    import pytest\nexcept ImportError:\n    pytest = None  # type: ignore\n\nMESSAGE = \"\"\"\nThe Hypothesis command-line interface requires the `{}` package,\nwhich you do not have installed.  Run:\n\n    python -m pip install --upgrade 'hypothesis[cli]'\n\nand try again.\n\"\"\"\n\ntry:\n    import click\nexcept ImportError:\n\n    def main():\n        \"\"\"If `click` is not installed, tell the user to install it then exit.\"\"\"\n        sys.stderr.write(MESSAGE.format(\"click\"))\n        sys.exit(1)\n\nelse:\n    # Ensure that Python scripts in the current working directory are importable,\n    # on the principle that Ghostwriter should 'just work' for novice users.  Note\n    # that we append rather than prepend to the module search path, so this will\n    # never shadow the stdlib or installed packages.\n    sys.path.append(\".\")\n\n    @click.group(context_settings={\"help_option_names\": (\"-h\", \"--help\")})\n    @click.version_option()\n    def main():\n        pass\n\n    def obj_name(s: str) -> object:\n        \"\"\"This \"type\" imports whatever object is named by a dotted string.\"\"\"\n        s = s.strip()\n        if \"/\" in s or \"\\\\\" in s:\n            raise click.UsageError(\n                \"Remember that the ghostwriter should be passed the name of a module, not a path.\"\n            ) from None\n        try:\n            return importlib.import_module(s)\n        except ImportError:\n            pass\n        classname = None\n        if \".\" not in s:\n            modulename, module, funcname = \"builtins\", builtins, s\n        else:\n            modulename, funcname = s.rsplit(\".\", 1)\n            try:\n                module = importlib.import_module(modulename)\n            except ImportError as err:\n                try:\n                    modulename, classname = modulename.rsplit(\".\", 1)\n                    module = importlib.import_module(modulename)\n                except (ImportError, ValueError):\n                    if s.endswith(\".py\"):\n                        raise click.UsageError(\n                            \"Remember that the ghostwriter should be passed the name of a module, not a file.\"\n                        ) from None\n                    raise click.UsageError(\n                        f\"Failed to import the {modulename} module for introspection.  \"\n                        \"Check spelling and your Python import path, or use the Python API?\"\n                    ) from err\n\n        def describe_close_matches(\n            module_or_class: types.ModuleType, objname: str\n        ) -> str:\n            public_names = [\n                name for name in vars(module_or_class) if not name.startswith(\"_\")\n            ]\n            matches = get_close_matches(objname, public_names)\n            if matches:\n                return f\"  Closest matches: {matches!r}\"\n            else:\n                return \"\"\n\n        if classname is None:\n            try:\n                return getattr(module, funcname)\n            except AttributeError as err:\n                if funcname == \"py\":\n                    # Likely attempted to pass a local file (Eg., \"myscript.py\") instead of a module name\n                    raise click.UsageError(\n                        \"Remember that the ghostwriter should be passed the name of a module, not a file.\"\n                        f\"\\n\\tTry: hypothesis write {s[:-3]}\"\n                    ) from None\n                raise click.UsageError(\n                    f\"Found the {modulename!r} module, but it doesn't have a \"\n                    f\"{funcname!r} attribute.\"\n                    + describe_close_matches(module, funcname)\n                ) from err\n        else:\n            try:\n                func_class = getattr(module, classname)\n            except AttributeError as err:\n                raise click.UsageError(\n                    f\"Found the {modulename!r} module, but it doesn't have a \"\n                    f\"{classname!r} class.\" + describe_close_matches(module, classname)\n                ) from err\n            try:\n                return getattr(func_class, funcname)\n            except AttributeError as err:\n                if inspect.isclass(func_class):\n                    func_class_is = \"class\"\n                else:\n                    func_class_is = \"attribute\"\n                raise click.UsageError(\n                    f\"Found the {modulename!r} module and {classname!r} {func_class_is}, \"\n                    f\"but it doesn't have a {funcname!r} attribute.\"\n                    + describe_close_matches(func_class, funcname)\n                ) from err\n\n    def _refactor(func, fname):\n        try:\n            oldcode = Path(fname).read_text(encoding=\"utf-8\")\n        except (OSError, UnicodeError) as err:\n            # Permissions or encoding issue, or file deleted, etc.\n            return f\"skipping {fname!r} due to {err}\"\n\n        if \"hypothesis\" not in oldcode:\n            return  # This is a fast way to avoid running slow no-op codemods\n\n        try:\n            newcode = func(oldcode)\n        except Exception as err:\n            from libcst import ParserSyntaxError\n\n            if isinstance(err, ParserSyntaxError):\n                from hypothesis.extra._patching import indent\n\n                msg = indent(str(err).replace(\"\\n\\n\", \"\\n\"), \"    \").strip()\n                return f\"skipping {fname!r} due to {msg}\"\n            raise\n\n        if newcode != oldcode:\n            Path(fname).write_text(newcode, encoding=\"utf-8\")\n\n    @main.command()  # type: ignore  # Click adds the .command attribute\n    @click.argument(\"path\", type=str, required=True, nargs=-1)\n    def codemod(path):\n        \"\"\"`hypothesis codemod` refactors deprecated or inefficient code.\n\n        It adapts `python -m libcst.tool`, removing many features and config options\n        which are rarely relevant for this purpose.  If you need more control, we\n        encourage you to use the libcst CLI directly; if not this one is easier.\n\n        PATH is the file(s) or directories of files to format in place, or\n        \"-\" to read from stdin and write to stdout.\n        \"\"\"\n        try:\n            from libcst.codemod import gather_files\n\n            from hypothesis.extra import codemods\n        except ImportError:\n            sys.stderr.write(\n                \"You are missing required dependencies for this option.  Run:\\n\\n\"\n                \"    python -m pip install --upgrade hypothesis[codemods]\\n\\n\"\n                \"and try again.\"\n            )\n            sys.exit(1)\n\n        # Special case for stdin/stdout usage\n        if \"-\" in path:\n            if len(path) > 1:\n                raise Exception(\n                    \"Cannot specify multiple paths when reading from stdin!\"\n                )\n            print(\"Codemodding from stdin\", file=sys.stderr)\n            print(codemods.refactor(sys.stdin.read()))\n            return 0\n\n        # Find all the files to refactor, and then codemod them\n        files = gather_files(path)\n        errors = set()\n        if len(files) <= 1:\n            errors.add(_refactor(codemods.refactor, *files))\n        else:\n            with Pool() as pool:\n                for msg in pool.imap_unordered(\n                    partial(_refactor, codemods.refactor), files\n                ):\n                    errors.add(msg)\n        errors.discard(None)\n        for msg in errors:\n            print(msg, file=sys.stderr)\n        return 1 if errors else 0\n\n    @main.command()  # type: ignore  # Click adds the .command attribute\n    @click.argument(\"func\", type=obj_name, required=True, nargs=-1)\n    @click.option(\n        \"--roundtrip\",\n        \"writer\",\n        flag_value=\"roundtrip\",\n        help=\"start by testing write/read or encode/decode!\",\n    )\n    @click.option(\n        \"--equivalent\",\n        \"writer\",\n        flag_value=\"equivalent\",\n        help=\"very useful when optimising or refactoring code\",\n    )\n    @click.option(\n        \"--errors-equivalent\",\n        \"writer\",\n        flag_value=\"errors-equivalent\",\n        help=\"--equivalent, but also allows consistent errors\",\n    )\n    @click.option(\n        \"--idempotent\",\n        \"writer\",\n        flag_value=\"idempotent\",\n        help=\"check that f(x) == f(f(x))\",\n    )\n    @click.option(\n        \"--binary-op\",\n        \"writer\",\n        flag_value=\"binary_operation\",\n        help=\"associativity, commutativity, identity element\",\n    )\n    # Note: we deliberately omit a --ufunc flag, because the magic()\n    # detection of ufuncs is both precise and complete.\n    @click.option(\n        \"--style\",\n        type=click.Choice([\"pytest\", \"unittest\"]),\n        default=\"pytest\" if pytest else \"unittest\",\n        help=\"pytest-style function, or unittest-style method?\",\n    )\n    @click.option(\n        \"-e\",\n        \"--except\",\n        \"except_\",\n        type=obj_name,\n        multiple=True,\n        help=\"dotted name of exception(s) to ignore\",\n    )\n    @click.option(\n        \"--annotate/--no-annotate\",\n        default=None,\n        help=\"force ghostwritten tests to be type-annotated (or not).  \"\n        \"By default, match the code to test.\",\n    )\n    def write(func, writer, except_, style, annotate):  # \\b disables autowrap\n        \"\"\"`hypothesis write` writes property-based tests for you!\n\n        Type annotations are helpful but not required for our advanced introspection\n        and templating logic.  Try running the examples below to see how it works:\n\n        \\b\n            hypothesis write gzip\n            hypothesis write numpy.matmul\n            hypothesis write pandas.from_dummies\n            hypothesis write re.compile --except re.error\n            hypothesis write --equivalent ast.literal_eval eval\n            hypothesis write --roundtrip json.dumps json.loads\n            hypothesis write --style=unittest --idempotent sorted\n            hypothesis write --binary-op operator.add\n        \"\"\"\n        # NOTE: if you want to call this function from Python, look instead at the\n        # ``hypothesis.extra.ghostwriter`` module.  Click-decorated functions have\n        # a different calling convention, and raise SystemExit instead of returning.\n        kwargs = {\"except_\": except_ or (), \"style\": style, \"annotate\": annotate}\n        if writer is None:\n            writer = \"magic\"\n        elif writer == \"idempotent\" and len(func) > 1:\n            raise click.UsageError(\"Test functions for idempotence one at a time.\")\n        elif writer == \"roundtrip\" and len(func) == 1:\n            writer = \"idempotent\"\n        elif \"equivalent\" in writer and len(func) == 1:\n            writer = \"fuzz\"\n        if writer == \"errors-equivalent\":\n            writer = \"equivalent\"\n            kwargs[\"allow_same_errors\"] = True\n\n        try:\n            from hypothesis.extra import ghostwriter\n        except ImportError:\n            sys.stderr.write(MESSAGE.format(\"black\"))\n            sys.exit(1)\n\n        code = getattr(ghostwriter, writer)(*func, **kwargs)\n        try:\n            from rich.console import Console\n            from rich.syntax import Syntax\n\n            from hypothesis.utils.terminal import guess_background_color\n        except ImportError:\n            print(code)\n        else:\n            try:\n                theme = \"default\" if guess_background_color() == \"light\" else \"monokai\"\n                code = Syntax(code, \"python\", background_color=\"default\", theme=theme)\n                Console().print(code, soft_wrap=True)\n            except Exception:\n                print(\"# Error while syntax-highlighting code\", file=sys.stderr)\n                print(code)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/codemods.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\nThis module provides codemods based on the :pypi:`LibCST` library, which can\nboth detect *and automatically fix* issues with code that uses Hypothesis,\nincluding upgrading from deprecated features to our recommended style.\n\nYou can run the codemods via our CLI::\n\n    $ hypothesis codemod --help\n    Usage: hypothesis codemod [OPTIONS] PATH...\n\n      `hypothesis codemod` refactors deprecated or inefficient code.\n\n      It adapts `python -m libcst.tool`, removing many features and config\n      options which are rarely relevant for this purpose.  If you need more\n      control, we encourage you to use the libcst CLI directly; if not this one\n      is easier.\n\n      PATH is the file(s) or directories of files to format in place, or \"-\" to\n      read from stdin and write to stdout.\n\n    Options:\n      -h, --help  Show this message and exit.\n\nAlternatively you can use ``python -m libcst.tool``, which offers more control\nat the cost of additional configuration (adding ``'hypothesis.extra'`` to the\n``modules`` list in ``.libcst.codemod.yaml``) and `some issues on Windows\n<https://github.com/Instagram/LibCST/issues/435>`__.\n\n.. autofunction:: refactor\n\"\"\"\n\nimport functools\nimport importlib\nfrom inspect import Parameter, signature\nfrom typing import ClassVar\n\nimport libcst as cst\nimport libcst.matchers as m\nfrom libcst.codemod import VisitorBasedCodemodCommand\n\n\ndef refactor(code: str) -> str:\n    \"\"\"Update a source code string from deprecated to modern Hypothesis APIs.\n\n    This may not fix *all* the deprecation warnings in your code, but we're\n    confident that it will be easier than doing it all by hand.\n\n    We recommend using the CLI, but if you want a Python function here it is.\n    \"\"\"\n    context = cst.codemod.CodemodContext()\n    mod = cst.parse_module(code)\n    transforms: list[VisitorBasedCodemodCommand] = [\n        HypothesisFixPositionalKeywonlyArgs(context),\n        HypothesisFixComplexMinMagnitude(context),\n        HypothesisFixHealthCheckAll(context),\n        HypothesisFixCharactersArguments(context),\n    ]\n    for transform in transforms:\n        mod = transform.transform_module(mod)\n    return mod.code\n\n\ndef match_qualname(name):\n    # We use the metadata to get qualname instead of matching directly on function\n    # name, because this handles some scope and \"from x import y as z\" issues.\n    return m.MatchMetadataIfTrue(\n        cst.metadata.QualifiedNameProvider,\n        # If there are multiple possible qualnames, e.g. due to conditional imports,\n        # be conservative.  Better to leave the user to fix a few things by hand than\n        # to break their code while attempting to refactor it!\n        lambda qualnames: all(n.name == name for n in qualnames),\n    )\n\n\nclass HypothesisFixComplexMinMagnitude(VisitorBasedCodemodCommand):\n    \"\"\"Fix a deprecated min_magnitude=None argument for complex numbers::\n\n        st.complex_numbers(min_magnitude=None) -> st.complex_numbers(min_magnitude=0)\n\n    Note that this should be run *after* ``HypothesisFixPositionalKeywonlyArgs``,\n    in order to handle ``st.complex_numbers(None)``.\n    \"\"\"\n\n    DESCRIPTION = \"Fix a deprecated min_magnitude=None argument for complex numbers.\"\n    METADATA_DEPENDENCIES = (cst.metadata.QualifiedNameProvider,)\n\n    @m.call_if_inside(\n        m.Call(metadata=match_qualname(\"hypothesis.strategies.complex_numbers\"))\n    )\n    def leave_Arg(self, original_node, updated_node):\n        if m.matches(\n            updated_node, m.Arg(keyword=m.Name(\"min_magnitude\"), value=m.Name(\"None\"))\n        ):\n            return updated_node.with_changes(value=cst.Integer(\"0\"))\n        return updated_node\n\n\n@functools.lru_cache\ndef get_fn(import_path):\n    mod, fn = import_path.rsplit(\".\", 1)\n    return getattr(importlib.import_module(mod), fn)\n\n\nclass HypothesisFixPositionalKeywonlyArgs(VisitorBasedCodemodCommand):\n    \"\"\"Fix positional arguments for newly keyword-only parameters, e.g.::\n\n        st.fractions(0, 1, 9) -> st.fractions(0, 1, max_denominator=9)\n\n    Applies to a majority of our public API, since keyword-only parameters are\n    great but we couldn't use them until after we dropped support for Python 2.\n    \"\"\"\n\n    DESCRIPTION = \"Fix positional arguments for newly keyword-only parameters.\"\n    METADATA_DEPENDENCIES = (cst.metadata.QualifiedNameProvider,)\n\n    kwonly_functions = (\n        \"hypothesis.target\",\n        \"hypothesis.find\",\n        \"hypothesis.extra.lark.from_lark\",\n        \"hypothesis.extra.numpy.arrays\",\n        \"hypothesis.extra.numpy.array_shapes\",\n        \"hypothesis.extra.numpy.unsigned_integer_dtypes\",\n        \"hypothesis.extra.numpy.integer_dtypes\",\n        \"hypothesis.extra.numpy.floating_dtypes\",\n        \"hypothesis.extra.numpy.complex_number_dtypes\",\n        \"hypothesis.extra.numpy.datetime64_dtypes\",\n        \"hypothesis.extra.numpy.timedelta64_dtypes\",\n        \"hypothesis.extra.numpy.byte_string_dtypes\",\n        \"hypothesis.extra.numpy.unicode_string_dtypes\",\n        \"hypothesis.extra.numpy.array_dtypes\",\n        \"hypothesis.extra.numpy.nested_dtypes\",\n        \"hypothesis.extra.numpy.valid_tuple_axes\",\n        \"hypothesis.extra.numpy.broadcastable_shapes\",\n        \"hypothesis.extra.pandas.indexes\",\n        \"hypothesis.extra.pandas.series\",\n        \"hypothesis.extra.pandas.columns\",\n        \"hypothesis.extra.pandas.data_frames\",\n        \"hypothesis.provisional.domains\",\n        \"hypothesis.stateful.run_state_machine_as_test\",\n        \"hypothesis.stateful.rule\",\n        \"hypothesis.stateful.initialize\",\n        \"hypothesis.strategies.floats\",\n        \"hypothesis.strategies.lists\",\n        \"hypothesis.strategies.sets\",\n        \"hypothesis.strategies.frozensets\",\n        \"hypothesis.strategies.iterables\",\n        \"hypothesis.strategies.dictionaries\",\n        \"hypothesis.strategies.characters\",\n        \"hypothesis.strategies.text\",\n        \"hypothesis.strategies.from_regex\",\n        \"hypothesis.strategies.binary\",\n        \"hypothesis.strategies.fractions\",\n        \"hypothesis.strategies.decimals\",\n        \"hypothesis.strategies.recursive\",\n        \"hypothesis.strategies.complex_numbers\",\n        \"hypothesis.strategies.shared\",\n        \"hypothesis.strategies.uuids\",\n        \"hypothesis.strategies.runner\",\n        \"hypothesis.strategies.functions\",\n        \"hypothesis.strategies.datetimes\",\n        \"hypothesis.strategies.times\",\n    )\n\n    def leave_Call(self, original_node, updated_node):\n        \"\"\"Convert positional to keyword arguments.\"\"\"\n        metadata = self.get_metadata(cst.metadata.QualifiedNameProvider, original_node)\n        qualnames = {qn.name for qn in metadata}\n\n        # If this isn't one of our known functions, or it has no posargs, stop there.\n        if (\n            len(qualnames) != 1\n            or not qualnames.intersection(self.kwonly_functions)\n            or not m.matches(\n                updated_node,\n                m.Call(\n                    func=m.DoesNotMatch(m.Call()),\n                    args=[m.Arg(keyword=None), m.ZeroOrMore()],\n                ),\n            )\n        ):\n            return updated_node\n\n        # Get the actual function object so that we can inspect the signature.\n        # This does e.g. incur a dependency on Numpy to fix Numpy-dependent code,\n        # but having a single source of truth about the signatures is worth it.\n        try:\n            params = signature(get_fn(*qualnames)).parameters.values()\n        except ModuleNotFoundError:\n            return updated_node\n\n        # st.floats() has a new allow_subnormal kwonly argument not at the end,\n        # so we do a bit more of a dance here.\n        if qualnames == {\"hypothesis.strategies.floats\"}:\n            params = [p for p in params if p.name != \"allow_subnormal\"]\n\n        if len(updated_node.args) > len(params):\n            return updated_node\n\n        # Create new arg nodes with the newly required keywords\n        assign_nospace = cst.AssignEqual(\n            whitespace_before=cst.SimpleWhitespace(\"\"),\n            whitespace_after=cst.SimpleWhitespace(\"\"),\n        )\n        newargs = [\n            (\n                arg\n                if arg.keyword or arg.star or p.kind is not Parameter.KEYWORD_ONLY\n                else arg.with_changes(keyword=cst.Name(p.name), equal=assign_nospace)\n            )\n            for p, arg in zip(params, updated_node.args, strict=False)\n        ]\n        return updated_node.with_changes(args=newargs)\n\n\nclass HypothesisFixHealthCheckAll(VisitorBasedCodemodCommand):\n    \"\"\"Replace HealthCheck.all() with list(HealthCheck)\"\"\"\n\n    DESCRIPTION = \"Replace HealthCheck.all() with list(HealthCheck)\"\n\n    @m.leave(m.Call(func=m.Attribute(m.Name(\"HealthCheck\"), m.Name(\"all\")), args=[]))\n    def replace_healthcheck(self, original_node, updated_node):\n        return updated_node.with_changes(\n            func=cst.Name(\"list\"),\n            args=[cst.Arg(value=cst.Name(\"HealthCheck\"))],\n        )\n\n\nclass HypothesisFixCharactersArguments(VisitorBasedCodemodCommand):\n    \"\"\"Fix deprecated white/blacklist arguments to characters::\n\n        st.characters(whitelist_categories=...) -> st.characters(categories=...)\n        st.characters(blacklist_categories=...) -> st.characters(exclude_categories=...)\n        st.characters(whitelist_characters=...) -> st.characters(include_characters=...)\n        st.characters(blacklist_characters=...) -> st.characters(exclude_characters=...)\n\n    Additionally, we drop `exclude_categories=` if `categories=` is present,\n    because this argument is always redundant (or an error).\n    \"\"\"\n\n    DESCRIPTION = \"Fix deprecated white/blacklist arguments to characters.\"\n    METADATA_DEPENDENCIES = (cst.metadata.QualifiedNameProvider,)\n\n    _replacements: ClassVar = {\n        \"whitelist_categories\": \"categories\",\n        \"blacklist_categories\": \"exclude_categories\",\n        \"whitelist_characters\": \"include_characters\",\n        \"blacklist_characters\": \"exclude_characters\",\n    }\n\n    @m.leave(\n        m.Call(\n            metadata=match_qualname(\"hypothesis.strategies.characters\"),\n            args=[\n                m.ZeroOrMore(),\n                m.Arg(keyword=m.OneOf(*map(m.Name, _replacements))),\n                m.ZeroOrMore(),\n            ],\n        ),\n    )\n    def fn(self, original_node, updated_node):\n        # Update to the new names\n        newargs = []\n        for arg in updated_node.args:\n            kw = self._replacements.get(arg.keyword.value, arg.keyword.value)\n            newargs.append(arg.with_changes(keyword=cst.Name(kw)))\n        # Drop redundant exclude_categories, which is now an error\n        if any(m.matches(arg, m.Arg(keyword=m.Name(\"categories\"))) for arg in newargs):\n            ex = m.Arg(keyword=m.Name(\"exclude_categories\"))\n            newargs = [a for a in newargs if m.matches(a, ~ex)]\n        return updated_node.with_changes(args=newargs)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/dateutil.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\nThis module provides :pypi:`dateutil <python-dateutil>` timezones.\n\nYou can use this strategy to make :func:`~hypothesis.strategies.datetimes`\nand :func:`~hypothesis.strategies.times` produce timezone-aware values.\n\n.. tip::\n    Consider using the stdlib :mod:`zoneinfo` module, via\n    :func:`st.timezones() <hypothesis.strategies.timezones>`.\n\"\"\"\n\nimport datetime as dt\n\nfrom dateutil import tz, zoneinfo  # type: ignore\n\nfrom hypothesis import strategies as st\nfrom hypothesis.strategies._internal.utils import cacheable, defines_strategy\n\n__all__ = [\"timezones\"]\n\n\ndef __zone_sort_key(zone):\n    \"\"\"Sort by absolute UTC offset at reference date,\n    positive first, with ties broken by name.\n    \"\"\"\n    assert zone is not None\n    offset = zone.utcoffset(dt.datetime(2000, 1, 1))\n    offset = 999 if offset is None else offset\n    return (abs(offset), -offset, str(zone))\n\n\n@cacheable\n@defines_strategy()\ndef timezones() -> st.SearchStrategy[dt.tzinfo]:\n    \"\"\"Any timezone from :pypi:`dateutil <python-dateutil>`.\n\n    This strategy minimises to UTC, or the timezone with the smallest offset\n    from UTC as of 2000-01-01, and is designed for use with\n    :py:func:`~hypothesis.strategies.datetimes`.\n\n    Note that the timezones generated by the strategy may vary depending on the\n    configuration of your machine. See the dateutil documentation for more\n    information.\n    \"\"\"\n    all_timezones = sorted(\n        (tz.gettz(t) for t in zoneinfo.get_zonefile_instance().zones),\n        key=__zone_sort_key,\n    )\n    all_timezones.insert(0, tz.UTC)\n    # We discard Nones in the list comprehension because Mypy knows that\n    # tz.gettz may return None.  However this should never happen for known\n    # zone names, so we assert that it's impossible first.\n    assert None not in all_timezones\n    return st.sampled_from([z for z in all_timezones if z is not None])\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/django/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.extra.django._fields import from_field, register_field_strategy\nfrom hypothesis.extra.django._impl import (\n    LiveServerTestCase,\n    SimpleTestCase,\n    StaticLiveServerTestCase,\n    TestCase,\n    TransactionTestCase,\n    from_form,\n    from_model,\n)\n\n__all__ = [\n    \"LiveServerTestCase\",\n    \"SimpleTestCase\",\n    \"StaticLiveServerTestCase\",\n    \"TestCase\",\n    \"TransactionTestCase\",\n    \"from_field\",\n    \"from_form\",\n    \"from_model\",\n    \"register_field_strategy\",\n]\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/django/_fields.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\nimport string\nfrom collections.abc import Callable\nfrom datetime import datetime, timedelta\nfrom decimal import Decimal\nfrom functools import lru_cache\nfrom typing import Any, TypeAlias, TypeVar, Union\n\nimport django\nfrom django import forms as df\nfrom django.conf import settings\nfrom django.core.files.base import ContentFile\nfrom django.core.validators import (\n    validate_ipv4_address,\n    validate_ipv6_address,\n    validate_ipv46_address,\n)\nfrom django.db import models as dm\n\nfrom hypothesis import strategies as st\nfrom hypothesis.errors import InvalidArgument, ResolutionFailed\nfrom hypothesis.internal.validation import check_type\nfrom hypothesis.provisional import urls\nfrom hypothesis.strategies import emails\n\n# Use old-style union to avoid hitting\n# https://github.com/sphinx-doc/sphinx/issues/11211\nAnyField: TypeAlias = Union[dm.Field, df.Field]  # noqa: UP007\nF = TypeVar(\"F\", bound=AnyField)\n\n\ndef numeric_bounds_from_validators(\n    field, min_value=float(\"-inf\"), max_value=float(\"inf\")\n):\n    for v in field.validators:\n        if isinstance(v, django.core.validators.MinValueValidator):\n            min_value = max(min_value, v.limit_value)\n        elif isinstance(v, django.core.validators.MaxValueValidator):\n            max_value = min(max_value, v.limit_value)\n    return min_value, max_value\n\n\ndef integers_for_field(min_value, max_value):\n    def inner(field):\n        return st.integers(*numeric_bounds_from_validators(field, min_value, max_value))\n\n    return inner\n\n\n@lru_cache\ndef timezones():\n    # From Django 4.0, the default is to use zoneinfo instead of pytz.\n    assert getattr(django.conf.settings, \"USE_TZ\", False)\n    if django.VERSION < (5, 0, 0) and getattr(\n        django.conf.settings, \"USE_DEPRECATED_PYTZ\", True\n    ):\n        from hypothesis.extra.pytz import timezones\n    else:\n        from hypothesis.strategies import timezones\n\n    return timezones()\n\n\n# Mapping of field types, to strategy objects or functions of (type) -> strategy\n_FieldLookUpType = dict[\n    type[AnyField],\n    st.SearchStrategy | Callable[[Any], st.SearchStrategy],\n]\n_global_field_lookup: _FieldLookUpType = {\n    dm.SmallIntegerField: integers_for_field(-32768, 32767),\n    dm.IntegerField: integers_for_field(-2147483648, 2147483647),\n    dm.BigIntegerField: integers_for_field(-9223372036854775808, 9223372036854775807),\n    dm.PositiveIntegerField: integers_for_field(0, 2147483647),\n    dm.PositiveSmallIntegerField: integers_for_field(0, 32767),\n    dm.BooleanField: st.booleans(),\n    dm.DateField: st.dates(),\n    dm.EmailField: emails(),\n    dm.FloatField: st.floats(),\n    dm.NullBooleanField: st.one_of(st.none(), st.booleans()),\n    dm.URLField: urls(),\n    dm.UUIDField: st.uuids(),\n    df.DateField: st.dates(),\n    df.DurationField: st.timedeltas(),\n    df.EmailField: emails(),\n    df.FloatField: lambda field: st.floats(\n        *numeric_bounds_from_validators(field), allow_nan=False, allow_infinity=False\n    ),\n    df.IntegerField: integers_for_field(-2147483648, 2147483647),\n    df.NullBooleanField: st.one_of(st.none(), st.booleans()),\n    df.URLField: urls(),\n    df.UUIDField: st.uuids(),\n    df.FileField: st.builds(\n        ContentFile, st.binary(min_size=1), name=st.text(min_size=1, max_size=100)\n    ),\n}\n\n_ipv6_strings = st.one_of(\n    st.ip_addresses(v=6).map(str),\n    st.ip_addresses(v=6).map(lambda addr: addr.exploded),\n)\n\n\ndef register_for(field_type):\n    def inner(func):\n        _global_field_lookup[field_type] = func\n        return func\n\n    return inner\n\n\n@register_for(dm.DateTimeField)\n@register_for(df.DateTimeField)\ndef _for_datetime(field):\n    if getattr(django.conf.settings, \"USE_TZ\", False):\n        # avoid https://code.djangoproject.com/ticket/35683\n        return st.datetimes(\n            min_value=datetime.min + timedelta(days=1),\n            max_value=datetime.max - timedelta(days=1),\n            timezones=timezones(),\n        )\n    return st.datetimes()\n\n\ndef using_sqlite():\n    try:\n        return (\n            getattr(django.conf.settings, \"DATABASES\", {})\n            .get(\"default\", {})\n            .get(\"ENGINE\", \"\")\n            .endswith(\".sqlite3\")\n        )\n    except django.core.exceptions.ImproperlyConfigured:\n        return None\n\n\n@register_for(dm.TimeField)\ndef _for_model_time(field):\n    # SQLITE supports TZ-aware datetimes, but not TZ-aware times.\n    if getattr(django.conf.settings, \"USE_TZ\", False) and not using_sqlite():\n        return st.times(timezones=timezones())\n    return st.times()\n\n\n@register_for(df.TimeField)\ndef _for_form_time(field):\n    if getattr(django.conf.settings, \"USE_TZ\", False):\n        return st.times(timezones=timezones())\n    return st.times()\n\n\n@register_for(dm.DurationField)\ndef _for_duration(field):\n    # SQLite stores timedeltas as six bytes of microseconds\n    if using_sqlite():\n        delta = timedelta(microseconds=2**47 - 1)\n        return st.timedeltas(-delta, delta)\n    return st.timedeltas()\n\n\n@register_for(dm.SlugField)\n@register_for(df.SlugField)\ndef _for_slug(field):\n    min_size = 1\n    if getattr(field, \"blank\", False) or not getattr(field, \"required\", True):\n        min_size = 0\n    return st.text(\n        alphabet=string.ascii_letters + string.digits,\n        min_size=min_size,\n        max_size=field.max_length,\n    )\n\n\n@register_for(dm.GenericIPAddressField)\ndef _for_model_ip(field):\n    return {\n        \"ipv4\": st.ip_addresses(v=4).map(str),\n        \"ipv6\": _ipv6_strings,\n        \"both\": st.ip_addresses(v=4).map(str) | _ipv6_strings,\n    }[field.protocol.lower()]\n\n\n@register_for(df.GenericIPAddressField)\ndef _for_form_ip(field):\n    # the IP address form fields have no direct indication of which type\n    #  of address they want, so direct comparison with the validator\n    #  function has to be used instead. Sorry for the potato logic here\n    if validate_ipv46_address in field.default_validators:\n        return st.ip_addresses(v=4).map(str) | _ipv6_strings\n    if validate_ipv4_address in field.default_validators:\n        return st.ip_addresses(v=4).map(str)\n    if validate_ipv6_address in field.default_validators:\n        return _ipv6_strings\n    raise ResolutionFailed(f\"No IP version validator on {field=}\")\n\n\n@register_for(dm.DecimalField)\n@register_for(df.DecimalField)\ndef _for_decimal(field):\n    min_value, max_value = numeric_bounds_from_validators(field)\n    bound = Decimal(10**field.max_digits - 1) / (10**field.decimal_places)\n    return st.decimals(\n        min_value=max(min_value, -bound),\n        max_value=min(max_value, bound),\n        places=field.decimal_places,\n    )\n\n\ndef length_bounds_from_validators(field):\n    min_size = 1\n    max_size = field.max_length\n    for v in field.validators:\n        if isinstance(v, django.core.validators.MinLengthValidator):\n            min_size = max(min_size, v.limit_value)\n        elif isinstance(v, django.core.validators.MaxLengthValidator):\n            max_size = min(max_size or v.limit_value, v.limit_value)\n    return min_size, max_size\n\n\n@register_for(dm.BinaryField)\ndef _for_binary(field):\n    min_size, max_size = length_bounds_from_validators(field)\n    if getattr(field, \"blank\", False) or not getattr(field, \"required\", True):\n        return st.just(b\"\") | st.binary(min_size=min_size, max_size=max_size)\n    return st.binary(min_size=min_size, max_size=max_size)\n\n\n@register_for(dm.CharField)\n@register_for(dm.TextField)\n@register_for(df.CharField)\n@register_for(df.RegexField)\ndef _for_text(field):\n    # We can infer a vastly more precise strategy by considering the\n    # validators as well as the field type.  This is a minimal proof of\n    # concept, but we intend to leverage the idea much more heavily soon.\n    # See https://github.com/HypothesisWorks/hypothesis-python/issues/1116\n    regexes = [\n        re.compile(v.regex, v.flags) if isinstance(v.regex, str) else v.regex\n        for v in field.validators\n        if isinstance(v, django.core.validators.RegexValidator) and not v.inverse_match\n    ]\n    if regexes:\n        # This strategy generates according to one of the regexes, and\n        # filters using the others.  It can therefore learn to generate\n        # from the most restrictive and filter with permissive patterns.\n        # Not maximally efficient, but it makes pathological cases rarer.\n        # If you want a challenge: extend https://qntm.org/greenery to\n        # compute intersections of the full Python regex language.\n        return st.one_of(*(st.from_regex(r) for r in regexes))\n    # If there are no (usable) regexes, we use a standard text strategy.\n    min_size, max_size = length_bounds_from_validators(field)\n    strategy = st.text(\n        alphabet=st.characters(exclude_characters=\"\\x00\", exclude_categories=(\"Cs\",)),\n        min_size=min_size,\n        max_size=max_size,\n    ).filter(lambda s: min_size <= len(s.strip()))\n    if getattr(field, \"blank\", False) or not getattr(field, \"required\", True):\n        return st.just(\"\") | strategy\n    return strategy\n\n\nif \"django.contrib.auth\" in settings.INSTALLED_APPS:\n    from django.contrib.auth.forms import UsernameField\n\n    register_for(UsernameField)(_for_text)\n\n\n@register_for(df.BooleanField)\ndef _for_form_boolean(field):\n    if field.required:\n        return st.just(True)\n    return st.booleans()\n\n\ndef _model_choice_strategy(field):\n    def _strategy():\n        if field.choices is None:\n            # The field was instantiated with queryset=None, and not\n            # subsequently updated.\n            raise InvalidArgument(\n                \"Cannot create strategy for ModelChoicesField with no choices\"\n            )\n        elif hasattr(field, \"_choices\"):\n            # The choices property was set manually.\n            choices = field._choices\n        else:\n            # choices is not None, and was not set manually, so we\n            # must have a QuerySet.\n            choices = field.queryset\n\n        if not choices.ordered:\n            raise InvalidArgument(\n                f\"Cannot create strategy for {field.__class__.__name__} with a choices \"\n                \"attribute derived from a QuerySet without an explicit ordering - this may \"\n                \"cause Hypothesis to produce unstable results between runs.\"\n            )\n\n        return st.sampled_from(\n            [\n                (\n                    choice.value\n                    if isinstance(choice, df.models.ModelChoiceIteratorValue)\n                    else choice  # Empty value, if included.\n                )\n                for choice, _ in field.choices\n            ]\n        )\n\n    # Accessing field.choices causes database access, so defer the strategy.\n    return st.deferred(_strategy)\n\n\n@register_for(df.ModelChoiceField)\ndef _for_model_choice(field):\n    return _model_choice_strategy(field)\n\n\n@register_for(df.ModelMultipleChoiceField)\ndef _for_model_multiple_choice(field):\n    min_size = 1 if field.required else 0\n    return st.lists(_model_choice_strategy(field), min_size=min_size, unique=True)\n\n\ndef register_field_strategy(\n    field_type: type[AnyField], strategy: st.SearchStrategy\n) -> None:\n    \"\"\"Add an entry to the global field-to-strategy lookup used by\n    :func:`~hypothesis.extra.django.from_field`.\n\n    ``field_type`` must be a subtype of :class:`django.db.models.Field` or\n    :class:`django.forms.Field`, which must not already be registered.\n    ``strategy`` must be a :class:`~hypothesis.strategies.SearchStrategy`.\n    \"\"\"\n    if not issubclass(field_type, (dm.Field, df.Field)):\n        raise InvalidArgument(f\"{field_type=} must be a subtype of Field\")\n    check_type(st.SearchStrategy, strategy, \"strategy\")\n    if field_type in _global_field_lookup:\n        raise InvalidArgument(\n            f\"{field_type=} already has a registered \"\n            f\"strategy ({_global_field_lookup[field_type]!r})\"\n        )\n    if issubclass(field_type, dm.AutoField):\n        raise InvalidArgument(\"Cannot register a strategy for an AutoField\")\n    _global_field_lookup[field_type] = strategy\n\n\ndef from_field(field: F) -> st.SearchStrategy[F | None]:\n    \"\"\"Return a strategy for values that fit the given field.\n\n    This function is used by :func:`~hypothesis.extra.django.from_form` and\n    :func:`~hypothesis.extra.django.from_model` for any fields that require\n    a value, or for which you passed ``...`` (:obj:`python:Ellipsis`) to infer\n    a strategy from an annotation.\n\n    It's pretty similar to the core :func:`~hypothesis.strategies.from_type`\n    function, with a subtle but important difference: ``from_field`` takes a\n    Field *instance*, rather than a Field *subtype*, so that it has access to\n    instance attributes such as string length and validators.\n    \"\"\"\n    check_type((dm.Field, df.Field), field, \"field\")\n\n    # The following isinstance check must occur *before* the getattr\n    # check. In the case of ModelChoicesField, evaluating\n    # field.choices causes database access, which we want to avoid if\n    # we don't have a connection (the generated strategies for\n    # ModelChoicesField defer evaluation of `choices').\n    if not isinstance(field, df.ModelChoiceField) and getattr(field, \"choices\", False):\n        choices: list = []\n        for value, name_or_optgroup in field.choices:\n            if isinstance(name_or_optgroup, (list, tuple)):\n                choices.extend(key for key, _ in name_or_optgroup)\n            else:\n                choices.append(value)\n        # form fields automatically include an empty choice, strip it out\n        if \"\" in choices:\n            choices.remove(\"\")\n        min_size = 1\n        if isinstance(field, (dm.CharField, dm.TextField)) and field.blank:\n            choices.insert(0, \"\")\n        elif isinstance(field, (df.Field)) and not field.required:\n            choices.insert(0, \"\")\n            min_size = 0\n        strategy = st.sampled_from(choices)\n        if isinstance(field, (df.MultipleChoiceField, df.TypedMultipleChoiceField)):\n            strategy = st.lists(st.sampled_from(choices), min_size=min_size)\n    else:\n        if type(field) not in _global_field_lookup:\n            if getattr(field, \"null\", False):\n                return st.none()\n            raise ResolutionFailed(f\"Could not infer a strategy for {field!r}\")\n        strategy = _global_field_lookup[type(field)]  # type: ignore\n        if not isinstance(strategy, st.SearchStrategy):\n            strategy = strategy(field)\n    assert isinstance(strategy, st.SearchStrategy)\n    if field.validators:\n\n        def validate(value):\n            try:\n                field.run_validators(value)\n                return True\n            except django.core.exceptions.ValidationError:\n                return False\n\n        strategy = strategy.filter(validate)\n\n    if getattr(field, \"null\", False):\n        return st.none() | strategy\n    return strategy\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/django/_impl.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport unittest\nfrom functools import partial\nfrom types import EllipsisType\nfrom typing import Any, TypeVar\n\nfrom django import forms as df, test as dt\nfrom django.contrib.staticfiles import testing as dst\nfrom django.core.exceptions import ValidationError\nfrom django.db import IntegrityError, models as dm\n\nfrom hypothesis import reject, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra.django._fields import from_field\nfrom hypothesis.strategies._internal.utils import defines_strategy\n\nModelT = TypeVar(\"ModelT\", bound=dm.Model)\n\n\nclass HypothesisTestCase:\n    def setup_example(self):\n        self._pre_setup()\n\n    def teardown_example(self, example):\n        self._post_teardown()\n\n    def __call__(self, result=None):\n        testMethod = getattr(self, self._testMethodName)\n        if getattr(testMethod, \"is_hypothesis_test\", False):\n            return unittest.TestCase.__call__(self, result)\n        else:\n            return dt.SimpleTestCase.__call__(self, result)\n\n\nclass SimpleTestCase(HypothesisTestCase, dt.SimpleTestCase):\n    pass\n\n\nclass TestCase(HypothesisTestCase, dt.TestCase):\n    pass\n\n\nclass TransactionTestCase(HypothesisTestCase, dt.TransactionTestCase):\n    pass\n\n\nclass LiveServerTestCase(HypothesisTestCase, dt.LiveServerTestCase):\n    pass\n\n\nclass StaticLiveServerTestCase(HypothesisTestCase, dst.StaticLiveServerTestCase):\n    pass\n\n\n@defines_strategy()\ndef from_model(\n    model: type[ModelT], /, **field_strategies: st.SearchStrategy | EllipsisType\n) -> st.SearchStrategy[ModelT]:\n    \"\"\"Return a strategy for examples of ``model``.\n\n    .. warning::\n        Hypothesis creates saved models. This will run inside your testing\n        transaction when using the test runner, but if you use the dev console\n        this will leave debris in your database.\n\n    ``model`` must be an subclass of :class:`~django:django.db.models.Model`.\n    Strategies for fields may be passed as keyword arguments, for example\n    ``is_staff=st.just(False)``.  In order to support models with fields named\n    \"model\", this is a positional-only parameter.\n\n    Hypothesis can often infer a strategy based the field type and validators,\n    and will attempt to do so for any required fields.  No strategy will be\n    inferred for an :class:`~django:django.db.models.AutoField`, nullable field,\n    foreign key, or field for which a keyword\n    argument is passed to ``from_model()``.  For example,\n    a Shop type with a foreign key to Company could be generated with::\n\n        shop_strategy = from_model(Shop, company=from_model(Company))\n\n    Like for :func:`~hypothesis.strategies.builds`, you can pass\n    ``...`` (:obj:`python:Ellipsis`) as a keyword argument to infer a strategy for\n    a field which has a default value instead of using the default.\n    \"\"\"\n    if not issubclass(model, dm.Model):\n        raise InvalidArgument(f\"{model=} must be a subtype of Model\")\n\n    fields_by_name = {f.name: f for f in model._meta.concrete_fields}\n    for name, value in sorted(field_strategies.items()):\n        if value is ...:\n            field_strategies[name] = from_field(fields_by_name[name])\n    for name, field in sorted(fields_by_name.items()):\n        if (\n            name not in field_strategies\n            and not field.auto_created\n            and not isinstance(field, dm.AutoField)\n            and not isinstance(field, getattr(dm, \"GeneratedField\", ()))\n            and field.default is dm.fields.NOT_PROVIDED\n        ):\n            field_strategies[name] = from_field(field)\n\n    for field in field_strategies:\n        if model._meta.get_field(field).primary_key:\n            # The primary key is generated as part of the strategy. We\n            # want to find any existing row with this primary key and\n            # overwrite its contents.\n            kwargs = {field: field_strategies.pop(field)}\n            kwargs[\"defaults\"] = st.fixed_dictionaries(field_strategies)  # type: ignore\n            return _models_impl(st.builds(model.objects.update_or_create, **kwargs))\n\n    # The primary key is not generated as part of the strategy, so we\n    # just match against any row that has the same value for all\n    # fields.\n    return _models_impl(st.builds(model.objects.get_or_create, **field_strategies))\n\n\n@st.composite\ndef _models_impl(draw, strat):\n    \"\"\"Handle the nasty part of drawing a value for models()\"\"\"\n    try:\n        return draw(strat)[0]\n    except IntegrityError:\n        reject()\n\n\n@defines_strategy()\ndef from_form(\n    form: type[df.Form],\n    form_kwargs: dict | None = None,\n    **field_strategies: st.SearchStrategy | EllipsisType,\n) -> st.SearchStrategy[df.Form]:\n    \"\"\"Return a strategy for examples of ``form``.\n\n    ``form`` must be an subclass of :class:`~django:django.forms.Form`.\n    Strategies for fields may be passed as keyword arguments, for example\n    ``is_staff=st.just(False)``.\n\n    Hypothesis can often infer a strategy based the field type and validators,\n    and will attempt to do so for any required fields.  No strategy will be\n    inferred for a disabled field or field for which a keyword argument\n    is passed to ``from_form()``.\n\n    This function uses the fields of an unbound ``form`` instance to determine\n    field strategies, any keyword arguments needed to instantiate the unbound\n    ``form`` instance can be passed into ``from_form()`` as a dict with the\n    keyword ``form_kwargs``. E.g.::\n\n        shop_strategy = from_form(Shop, form_kwargs={\"company_id\": 5})\n\n    Like for :func:`~hypothesis.strategies.builds`, you can pass\n    ``...`` (:obj:`python:Ellipsis`) as a keyword argument to infer a strategy for\n    a field which has a default value instead of using the default.\n    \"\"\"\n    # currently unsupported:\n    # ComboField\n    # FilePathField\n    # ImageField\n    form_kwargs = form_kwargs or {}\n    if not issubclass(form, df.BaseForm):\n        raise InvalidArgument(f\"{form=} must be a subtype of Form\")\n\n    # Forms are a little bit different from models. Model classes have\n    # all their fields defined, whereas forms may have different fields\n    # per-instance. So, we ought to instantiate the form and get the\n    # fields from the instance, thus we need to accept the kwargs for\n    # instantiation as well as the explicitly defined strategies\n\n    unbound_form = form(**form_kwargs)\n    fields_by_name = {}\n    for name, field in unbound_form.fields.items():\n        if isinstance(field, df.MultiValueField):\n            # PS: So this is a little strange, but MultiValueFields must\n            # have their form data encoded in a particular way for the\n            # values to actually be picked up by the widget instances'\n            # ``value_from_datadict``.\n            # E.g. if a MultiValueField named 'mv_field' has 3\n            # sub-fields then the ``value_from_datadict`` will look for\n            # 'mv_field_0', 'mv_field_1', and 'mv_field_2'. Here I'm\n            # decomposing the individual sub-fields into the names that\n            # the form validation process expects\n            for i, _field in enumerate(field.fields):\n                fields_by_name[f\"{name}_{i}\"] = _field\n        else:\n            fields_by_name[name] = field\n\n    for name, value in sorted(field_strategies.items()):\n        if value is ...:\n            field_strategies[name] = from_field(fields_by_name[name])\n\n    for name, field in sorted(fields_by_name.items()):\n        if name not in field_strategies and not field.disabled:\n            field_strategies[name] = from_field(field)\n\n    # files are handled a bit specially in forms. A Form accepts two arguments:\n    # `data` and `files`. The former is for normal fields, and the latter is for\n    # file fields.\n    # see https://docs.djangoproject.com/en/5.1/ref/forms/api/#binding-uploaded-files.\n    data_strategies: dict[str, Any] = {}\n    file_strategies: dict[str, Any] = {}\n    for name, field in field_strategies.items():\n        form_field = fields_by_name[name]\n        dictionary = (\n            file_strategies if isinstance(form_field, df.FileField) else data_strategies\n        )\n        dictionary[name] = field\n\n    return _forms_impl(\n        st.builds(\n            partial(form, **form_kwargs),  # type: ignore\n            data=st.fixed_dictionaries(data_strategies),\n            files=st.fixed_dictionaries(file_strategies),\n        )\n    )\n\n\n@st.composite\ndef _forms_impl(draw, strat):\n    \"\"\"Handle the nasty part of drawing a value for from_form()\"\"\"\n    try:\n        return draw(strat)\n    except ValidationError:\n        reject()\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/dpcontracts.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\nThis module provides tools for working with the :pypi:`dpcontracts` library,\nbecause `combining contracts and property-based testing works really well\n<https://hillelwayne.com/talks/beyond-unit-tests/>`_.\n\nIt requires ``dpcontracts >= 0.4``.\n\"\"\"\n\nfrom dpcontracts import PreconditionError\n\nfrom hypothesis import reject\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.reflection import proxies\n\n\ndef fulfill(contract_func):\n    \"\"\"Decorate ``contract_func`` to reject calls which violate preconditions,\n    and retry them with different arguments.\n\n    This is a convenience function for testing internal code that uses\n    :pypi:`dpcontracts`, to automatically filter out arguments that would be\n    rejected by the public interface before triggering a contract error.\n\n    This can be used as ``builds(fulfill(func), ...)`` or in the body of the\n    test e.g. ``assert fulfill(func)(*args)``.\n    \"\"\"\n    if not hasattr(contract_func, \"__contract_wrapped_func__\"):\n        raise InvalidArgument(\n            f\"{contract_func.__name__} has no dpcontracts preconditions\"\n        )\n\n    @proxies(contract_func)\n    def inner(*args, **kwargs):\n        try:\n            return contract_func(*args, **kwargs)\n        except PreconditionError:\n            reject()\n\n    return inner\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/ghostwriter.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\nWriting tests with Hypothesis frees you from the tedium of deciding on and\nwriting out specific inputs to test.  Now, the ``hypothesis.extra.ghostwriter``\nmodule can write your test functions for you too!\n\nThe idea is to provide **an easy way to start** property-based testing,\n**and a seamless transition** to more complex test code - because ghostwritten\ntests are source code that you could have written for yourself.\n\nSo just pick a function you'd like tested, and feed it to one of the functions\nbelow.  They follow imports, use but do not require type annotations, and\ngenerally do their best to write you a useful test.  You can also use\n:ref:`our command-line interface <hypothesis-cli>`::\n\n    $ hypothesis write --help\n    Usage: hypothesis write [OPTIONS] FUNC...\n\n      `hypothesis write` writes property-based tests for you!\n\n      Type annotations are helpful but not required for our advanced\n      introspection and templating logic.  Try running the examples below to see\n      how it works:\n\n          hypothesis write gzip\n          hypothesis write numpy.matmul\n          hypothesis write pandas.from_dummies\n          hypothesis write re.compile --except re.error\n          hypothesis write --equivalent ast.literal_eval eval\n          hypothesis write --roundtrip json.dumps json.loads\n          hypothesis write --style=unittest --idempotent sorted\n          hypothesis write --binary-op operator.add\n\n    Options:\n      --roundtrip                 start by testing write/read or encode/decode!\n      --equivalent                very useful when optimising or refactoring code\n      --errors-equivalent         --equivalent, but also allows consistent errors\n      --idempotent                check that f(x) == f(f(x))\n      --binary-op                 associativity, commutativity, identity element\n      --style [pytest|unittest]   pytest-style function, or unittest-style method?\n      -e, --except OBJ_NAME       dotted name of exception(s) to ignore\n      --annotate / --no-annotate  force ghostwritten tests to be type-annotated\n                                  (or not).  By default, match the code to test.\n      -h, --help                  Show this message and exit.\n\n.. tip::\n\n    Using a light theme?  Hypothesis respects `NO_COLOR <https://no-color.org/>`__\n    and ``DJANGO_COLORS=light``.\n\n.. note::\n\n    The ghostwriter requires :pypi:`black`, but the generated code only\n    requires Hypothesis itself.\n\n.. note::\n\n    Legal questions?  While the ghostwriter fragments and logic is under the\n    MPL-2.0 license like the rest of Hypothesis, the *output* from the ghostwriter\n    is made available under the `Creative Commons Zero (CC0)\n    <https://creativecommons.org/public-domain/cc0/>`__\n    public domain dedication, so you can use it without any restrictions.\n\"\"\"\n\nimport ast\nimport builtins\nimport contextlib\nimport enum\nimport inspect\nimport os\nimport re\nimport sys\nimport types\nimport warnings\nfrom collections import OrderedDict, defaultdict\nfrom collections.abc import Callable, Iterable, Mapping\nfrom itertools import permutations, zip_longest\nfrom keyword import iskeyword as _iskeyword\nfrom string import ascii_lowercase\nfrom textwrap import dedent, indent\nfrom types import EllipsisType\nfrom typing import (\n    Any,\n    ForwardRef,\n    NamedTuple,\n    TypeVar,\n    get_args,\n    get_origin,\n)\n\nimport black\n\nfrom hypothesis import Verbosity, find, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument, SmallSearchSpaceWarning\nfrom hypothesis.internal.compat import get_type_hints\nfrom hypothesis.internal.reflection import get_signature, is_mock\nfrom hypothesis.internal.validation import check_type\nfrom hypothesis.provisional import domains\nfrom hypothesis.strategies._internal.collections import ListStrategy\nfrom hypothesis.strategies._internal.core import BuildsStrategy\nfrom hypothesis.strategies._internal.deferred import DeferredStrategy\nfrom hypothesis.strategies._internal.flatmapped import FlatMapStrategy\nfrom hypothesis.strategies._internal.lazy import LazyStrategy, unwrap_strategies\nfrom hypothesis.strategies._internal.strategies import (\n    FilteredStrategy,\n    MappedStrategy,\n    OneOfStrategy,\n    SampledFromStrategy,\n)\nfrom hypothesis.strategies._internal.types import _global_type_lookup, is_generic_type\n\nIMPORT_SECTION = \"\"\"\n# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\n{imports}\n\"\"\"\n\nTEMPLATE = \"\"\"\n@given({given_args})\ndef test_{test_kind}_{func_name}({arg_names}){return_annotation}:\n{test_body}\n\"\"\"\n\nSUPPRESS_BLOCK = \"\"\"\ntry:\n{test_body}\nexcept {exceptions}:\n    reject()\n\"\"\".strip()\n\nExcept = type[Exception] | tuple[type[Exception], ...]\nImportSet = set[str | tuple[str, str]]\n_quietly_settings = settings(\n    database=None,\n    deadline=None,\n    derandomize=True,\n    verbosity=Verbosity.quiet,\n)\n\n\ndef _dedupe_exceptions(exc: tuple[type[Exception], ...]) -> tuple[type[Exception], ...]:\n    # This is reminiscent of de-duplication logic I wrote for flake8-bugbear,\n    # but with access to the actual objects we can just check for subclasses.\n    # This lets us print e.g. `Exception` instead of `(Exception, OSError)`.\n    uniques = list(exc)\n    for a, b in permutations(exc, 2):\n        if a in uniques and issubclass(a, b):\n            uniques.remove(a)\n    return tuple(sorted(uniques, key=lambda e: e.__name__))\n\n\ndef _check_except(except_: Except) -> tuple[type[Exception], ...]:\n    if isinstance(except_, tuple):\n        for i, e in enumerate(except_):\n            if not isinstance(e, type) or not issubclass(e, Exception):\n                raise InvalidArgument(\n                    f\"Expected an Exception but got except_[{i}]={e!r}\"\n                    f\" (type={_get_qualname(type(e))})\"\n                )\n        return except_\n    if not isinstance(except_, type) or not issubclass(except_, Exception):\n        raise InvalidArgument(\n            \"Expected an Exception or tuple of exceptions, but got except_=\"\n            f\"{except_!r} (type={_get_qualname(type(except_))})\"\n        )\n    return (except_,)\n\n\ndef _exception_string(except_: tuple[type[Exception], ...]) -> tuple[ImportSet, str]:\n    if not except_:\n        return set(), \"\"\n    exceptions = []\n    imports: ImportSet = set()\n    for ex in _dedupe_exceptions(except_):\n        if ex.__qualname__ in dir(builtins):\n            exceptions.append(ex.__qualname__)\n        else:\n            imports.add(ex.__module__)\n            exceptions.append(_get_qualname(ex, include_module=True))\n    return imports, (\n        \"(\" + \", \".join(exceptions) + \")\" if len(exceptions) > 1 else exceptions[0]\n    )\n\n\ndef _check_style(style: str) -> None:\n    if style not in (\"pytest\", \"unittest\"):\n        raise InvalidArgument(f\"Valid styles are 'pytest' or 'unittest', got {style!r}\")\n\n\ndef _exceptions_from_docstring(doc: str) -> tuple[type[Exception], ...]:\n    \"\"\"Return a tuple of exceptions that the docstring says may be raised.\n\n    Note that we ignore non-builtin exception types for simplicity, as this is\n    used directly in _write_call() and passing import sets around would be really\n    really annoying.\n    \"\"\"\n    # TODO: it would be great to handle Google- and Numpy-style docstrings\n    #       (e.g. by using the Napoleon Sphinx extension)\n    assert isinstance(doc, str), doc\n    raises = []\n    for excname in re.compile(r\"\\:raises\\s+(\\w+)\\:\", re.MULTILINE).findall(doc):\n        exc_type = getattr(builtins, excname, None)\n        if isinstance(exc_type, type) and issubclass(exc_type, Exception):\n            raises.append(exc_type)\n    return tuple(_dedupe_exceptions(tuple(raises)))\n\n\ndef _type_from_doc_fragment(token: str) -> type | None:\n    # Special cases for \"integer\" and for numpy array-like and dtype\n    if token == \"integer\":\n        return int\n    if \"numpy\" in sys.modules:\n        if re.fullmatch(r\"[Aa]rray[-_ ]?like\", token):\n            return sys.modules[\"numpy\"].ndarray\n        elif token == \"dtype\":\n            return sys.modules[\"numpy\"].dtype\n    # Natural-language syntax, e.g. \"sequence of integers\"\n    coll_match = re.fullmatch(r\"(\\w+) of (\\w+)\", token)\n    if coll_match is not None:\n        coll_token, elem_token = coll_match.groups()\n        elems = _type_from_doc_fragment(elem_token)\n        if elems is None and elem_token.endswith(\"s\"):\n            elems = _type_from_doc_fragment(elem_token[:-1])\n        if elems is not None and coll_token in (\"list\", \"sequence\", \"collection\"):\n            return list[elems]  # type: ignore\n        # This might be e.g. \"array-like of float\"; arrays is better than nothing\n        # even if we can't conveniently pass a generic type around.\n        return _type_from_doc_fragment(coll_token)\n    # Check either builtins, or the module for a dotted name\n    if \".\" not in token:\n        return getattr(builtins, token, None)\n    mod, name = token.rsplit(\".\", maxsplit=1)\n    return getattr(sys.modules.get(mod, None), name, None)\n\n\ndef _strip_typevars(type_):\n    with contextlib.suppress(Exception):\n        if {type(a) for a in get_args(type_)} == {TypeVar}:\n            return get_origin(type_)\n    return type_\n\n\ndef _strategy_for(param: inspect.Parameter, docstring: str) -> st.SearchStrategy:\n    # Example types in docstrings:\n    # - `:type a: sequence of integers`\n    # - `b (list, tuple, or None): ...`\n    # - `c : {\"foo\", \"bar\", or None}`\n    for pattern in (\n        rf\"^\\s*\\:type\\s+{param.name}\\:\\s+(.+)\",  # RST-style\n        rf\"^\\s*{param.name} \\((.+)\\):\",  # Google-style\n        rf\"^\\s*{param.name} \\: (.+)\",  # Numpy-style\n    ):\n        match = re.search(pattern, docstring, flags=re.MULTILINE)\n        if match is None:\n            continue\n        doc_type = match.group(1)\n        doc_type = doc_type.removesuffix(\", optional\").strip(\"}{\")\n        elements = []\n        types = []\n        for token in re.split(r\",? +or +| *, *\", doc_type):\n            for prefix in (\"default \", \"python \"):\n                # e.g. `str or None, default \"auto\"` or `python int or numpy.int64`\n                token = token.removeprefix(prefix)\n            if not token:\n                continue\n            try:\n                # Elements of `{\"inner\", \"outer\"}` etc.\n                elements.append(ast.literal_eval(token))\n                continue\n            except (ValueError, SyntaxError):\n                t = _type_from_doc_fragment(token)\n                if isinstance(t, type) or is_generic_type(t):\n                    assert t is not None\n                    types.append(_strip_typevars(t))\n        if (\n            param.default is not inspect.Parameter.empty\n            and param.default not in elements\n            and not isinstance(\n                param.default, tuple(t for t in types if isinstance(t, type))\n            )\n        ):\n            with contextlib.suppress(SyntaxError):\n                compile(repr(st.just(param.default)), \"<string>\", \"eval\")\n                elements.insert(0, param.default)\n        if elements or types:\n            return (st.sampled_from(elements) if elements else st.nothing()) | (\n                st.one_of(*map(st.from_type, types)) if types else st.nothing()\n            )\n\n    # If our default value is an Enum or a boolean, we assume that any value\n    # of that type is acceptable.  Otherwise, we only generate the default.\n    if isinstance(param.default, bool):\n        return st.booleans()\n    if isinstance(param.default, enum.Enum):\n        return st.sampled_from(type(param.default))\n    if param.default is not inspect.Parameter.empty:\n        # Using `st.from_type(type(param.default))` would  introduce spurious\n        # failures in cases like the `flags` argument to regex functions.\n        # Better in to keep it simple, and let the user elaborate if desired.\n        return st.just(param.default)\n    return _guess_strategy_by_argname(name=param.name.lower())\n\n\n# fmt: off\nBOOL_NAMES = (\n    \"keepdims\", \"verbose\", \"debug\", \"force\", \"train\", \"training\", \"trainable\", \"bias\",\n    \"shuffle\", \"show\", \"load\", \"pretrained\", \"save\", \"overwrite\", \"normalize\",\n    \"reverse\", \"success\", \"enabled\", \"strict\", \"copy\", \"quiet\", \"required\", \"inplace\",\n    \"recursive\", \"enable\", \"active\", \"create\", \"validate\", \"refresh\", \"use_bias\",\n)\nPOSITIVE_INTEGER_NAMES = (\n    \"width\", \"size\", \"length\", \"limit\", \"idx\", \"stride\", \"epoch\", \"epochs\", \"depth\",\n    \"pid\", \"steps\", \"iteration\", \"iterations\", \"vocab_size\", \"ttl\", \"count\",\n)\nFLOAT_NAMES = (\n    \"real\", \"imag\", \"alpha\", \"theta\", \"beta\", \"sigma\", \"gamma\", \"angle\", \"reward\",\n    \"tau\", \"temperature\",\n)\nSTRING_NAMES = (\n    \"text\", \"txt\", \"password\", \"label\", \"prefix\", \"suffix\", \"desc\", \"description\",\n    \"str\", \"pattern\", \"subject\", \"reason\", \"comment\", \"prompt\", \"sentence\", \"sep\",\n)\n# fmt: on\n\n\ndef _guess_strategy_by_argname(name: str) -> st.SearchStrategy:\n    \"\"\"\n    If all else fails, we try guessing a strategy based on common argument names.\n\n    We wouldn't do this in builds() where strict correctness is required, but for\n    the ghostwriter we accept \"good guesses\" since the user would otherwise have\n    to change the strategy anyway - from `nothing()` - if we refused to guess.\n\n    A \"good guess\" is _usually correct_, and _a reasonable mistake_ if not.\n    The logic below is therefore based on a manual reading of the builtins and\n    some standard-library docs, plus the analysis of about three hundred million\n    arguments in https://github.com/HypothesisWorks/hypothesis/issues/3311\n    \"\"\"\n    # Special-cased names\n    if name in (\"function\", \"func\", \"f\"):\n        return st.functions()\n    if name in (\"pred\", \"predicate\"):\n        return st.functions(returns=st.booleans(), pure=True)\n    if name in (\"iterable\",):\n        return st.iterables(st.integers()) | st.iterables(st.text())\n    if name in (\"list\", \"lst\", \"ls\"):\n        return st.lists(st.nothing())\n    if name in (\"object\",):\n        return st.builds(object)\n    if \"uuid\" in name:\n        return st.uuids().map(str)\n\n    # Names which imply the value is a boolean\n    if name.startswith(\"is_\") or name in BOOL_NAMES:\n        return st.booleans()\n\n    # Names which imply that the value is a number, perhaps in a particular range\n    if name in (\"amount\", \"threshold\", \"number\", \"num\"):\n        return st.integers() | st.floats()\n\n    if name in (\"port\",):\n        return st.integers(0, 2**16 - 1)\n    if (\n        name.endswith(\"_size\")\n        or (name.endswith(\"size\") and \"_\" not in name)\n        or re.fullmatch(r\"n(um)?_[a-z_]*s\", name)\n        or name in POSITIVE_INTEGER_NAMES\n    ):\n        return st.integers(min_value=0)\n    if name in (\"offset\", \"seed\", \"dim\", \"total\", \"priority\"):\n        return st.integers()\n\n    if name in (\"learning_rate\", \"dropout\", \"dropout_rate\", \"epsilon\", \"eps\", \"prob\"):\n        return st.floats(0, 1)\n    if name in (\"lat\", \"latitude\"):\n        return st.floats(-90, 90)\n    if name in (\"lon\", \"longitude\"):\n        return st.floats(-180, 180)\n    if name in (\"radius\", \"tol\", \"tolerance\", \"rate\"):\n        return st.floats(min_value=0)\n    if name in FLOAT_NAMES:\n        return st.floats()\n\n    # Names which imply that the value is a string\n    if name in (\"host\", \"hostname\"):\n        return domains()\n    if name in (\"email\",):\n        return st.emails()\n    if name in (\"word\", \"slug\", \"api_key\"):\n        return st.from_regex(r\"\\w+\", fullmatch=True)\n    if name in (\"char\", \"character\"):\n        return st.characters()\n\n    if (\n        \"file\" in name\n        or \"path\" in name\n        or name.endswith(\"_dir\")\n        or name in (\"fname\", \"dir\", \"dirname\", \"directory\", \"folder\")\n    ):\n        # Common names for filesystem paths: these are usually strings, but we\n        # don't want to make strings more convenient than pathlib.Path.\n        return st.nothing()\n\n    if (\n        name.endswith((\"_name\", \"label\"))\n        or (name.endswith(\"name\") and \"_\" not in name)\n        or (\"string\" in name and \"as\" not in name)\n        or name in STRING_NAMES\n    ):\n        return st.text()\n\n    # Last clever idea: maybe we're looking a plural, and know the singular:\n    if re.fullmatch(r\"\\w*[^s]s\", name):\n        elems = _guess_strategy_by_argname(name[:-1])\n        if not elems.is_empty:\n            return st.lists(elems)\n\n    # And if all that failed, we'll return nothing() - the user will have to\n    # fill this in by hand, and we'll leave a comment to that effect later.\n    return st.nothing()\n\n\ndef _get_params_builtin_fn(func: Callable) -> list[inspect.Parameter]:\n    if (\n        isinstance(func, (types.BuiltinFunctionType, types.BuiltinMethodType))\n        and hasattr(func, \"__doc__\")\n        and isinstance(func.__doc__, str)\n    ):\n        # inspect.signature doesn't work on all builtin functions or methods.\n        # In such cases, we can try to reconstruct simple signatures from the docstring.\n        match = re.match(rf\"^{func.__name__}\\((.+?)\\)\", func.__doc__)\n        if match is None:\n            return []\n        args = match.group(1).replace(\"[\", \"\").replace(\"]\", \"\")\n        params = []\n        # Even if the signature doesn't contain a /, we assume that arguments\n        # are positional-only until shown otherwise - the / is often omitted.\n        kind: inspect._ParameterKind = inspect.Parameter.POSITIONAL_ONLY\n        for arg in args.split(\", \"):\n            arg, *_ = arg.partition(\"=\")\n            arg = arg.strip()\n            if arg == \"/\":\n                kind = inspect.Parameter.POSITIONAL_OR_KEYWORD\n                continue\n            if arg.startswith(\"*\") or arg == \"...\":\n                kind = inspect.Parameter.KEYWORD_ONLY\n                continue  # we omit *varargs, if there are any\n            if _iskeyword(arg.lstrip(\"*\")) or not arg.lstrip(\"*\").isidentifier():\n                break  # skip all subsequent params if this name is invalid\n            params.append(inspect.Parameter(name=arg, kind=kind))\n        return params\n    return []\n\n\ndef _get_params_ufunc(func: Callable) -> list[inspect.Parameter]:\n    if _is_probably_ufunc(func):\n        # `inspect.signature` results vary for ufunc objects, but we can work out\n        # what the required parameters would look like if it was reliable.\n        # Note that we use args named a, b, c... to match the `operator` module,\n        # rather than x1, x2, x3... like the Numpy docs.  Because they're pos-only\n        # this doesn't make a runtime difference, and it's much nicer for use-cases\n        # like `equivalent(numpy.add, operator.add)`.\n        return [\n            inspect.Parameter(name=name, kind=inspect.Parameter.POSITIONAL_ONLY)\n            for name in ascii_lowercase[: func.nin]  # type: ignore\n        ]\n    return []\n\n\ndef _get_params(func: Callable) -> dict[str, inspect.Parameter]:\n    \"\"\"Get non-vararg parameters of `func` as an ordered dict.\"\"\"\n    try:\n        params = list(get_signature(func).parameters.values())\n    except Exception:\n        if params := _get_params_ufunc(func):\n            pass\n        elif params := _get_params_builtin_fn(func):\n            pass\n        else:\n            # If we haven't managed to recover a signature through the tricks above,\n            # we're out of ideas and should just re-raise the exception.\n            raise\n    else:\n        P = inspect.Parameter\n        placeholder = [(\"args\", P.VAR_POSITIONAL), (\"kwargs\", P.VAR_KEYWORD)]\n        if ufunc_params := _get_params_ufunc(func):\n            # If func is a ufunc, prefer _get_params_ufunc over get_signature,\n            # as the latter includes keyword arguments we aren't well-equipped\n            # to ghostwrite.\n            params = ufunc_params\n        elif [(p.name, p.kind) for p in params] == placeholder:\n            # If the params we got look like an uninformative placeholder, try fallbacks.\n            params = _get_params_builtin_fn(func) or params\n    return _params_to_dict(params)\n\n\ndef _params_to_dict(\n    params: Iterable[inspect.Parameter],\n) -> dict[str, inspect.Parameter]:\n    var_param_kinds = (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD)\n    return OrderedDict((p.name, p) for p in params if p.kind not in var_param_kinds)\n\n\n@contextlib.contextmanager\ndef _with_any_registered():\n    # If the user has registered their own strategy for Any, leave it alone\n    if Any in _global_type_lookup:\n        yield\n    # We usually want to force from_type(Any) to raise an error because we don't\n    # have enough information to accurately resolve user intent, but in this case\n    # we can treat it as a synonym for object - this is probably wrong, but you'll\n    # get at least _some_ output to edit later.  We then reset everything in order\n    # to avoid polluting the resolution logic in case you run tests later.\n    else:\n        try:\n            _global_type_lookup[Any] = st.builds(object)\n            yield\n        finally:\n            del _global_type_lookup[Any]\n            st.from_type.__clear_cache()\n\n\ndef _get_strategies(\n    *funcs: Callable, pass_result_to_next_func: bool = False\n) -> dict[str, st.SearchStrategy]:\n    \"\"\"Return a dict of strategies for the union of arguments to `funcs`.\n\n    If `pass_result_to_next_func` is True, assume that the result of each function\n    is passed to the next, and therefore skip the first argument of all but the\n    first function.\n\n    This dict is used to construct our call to the `@given(...)` decorator.\n    \"\"\"\n    assert funcs, \"Must pass at least one function\"\n    given_strategies: dict[str, st.SearchStrategy] = {}\n    for i, f in enumerate(funcs):\n        params = _get_params(f)\n        if pass_result_to_next_func and i >= 1:\n            del params[next(iter(params))]\n        hints = get_type_hints(f)\n        docstring = getattr(f, \"__doc__\", None) or \"\"\n        builder_args = {\n            k: ... if k in hints else _strategy_for(v, docstring)\n            for k, v in params.items()\n        }\n        with _with_any_registered():\n            strat = st.builds(f, **builder_args).wrapped_strategy  # type: ignore\n\n        if strat.args:\n            raise NotImplementedError(\"Expected to pass everything as kwargs\")\n\n        for k, v in strat.kwargs.items():\n            if _valid_syntax_repr(v)[1] == \"nothing()\" and k in hints:\n                # e.g. from_type(Hashable) is OK but the unwrapped repr is not\n                v = LazyStrategy(st.from_type, (hints[k],), {})\n            if k in given_strategies:\n                given_strategies[k] |= v\n            else:\n                given_strategies[k] = v\n\n    # If there is only one function, we pass arguments to @given in the order of\n    # that function's signature.  Otherwise, we use alphabetical order.\n    if len(funcs) == 1:\n        return {name: given_strategies[name] for name in _get_params(f)}\n    return dict(sorted(given_strategies.items()))\n\n\ndef _assert_eq(style: str, a: str, b: str) -> str:\n    if style == \"unittest\":\n        return f\"self.assertEqual({a}, {b})\"\n    assert style == \"pytest\"\n    if a.isidentifier() and b.isidentifier():\n        return f\"assert {a} == {b}, ({a}, {b})\"\n    return f\"assert {a} == {b}\"\n\n\ndef _imports_for_object(obj):\n    \"\"\"Return the imports for `obj`, which may be empty for e.g. lambdas\"\"\"\n    if type(obj) is getattr(types, \"UnionType\", object()):\n        return {mod for mod, _ in set().union(*map(_imports_for_object, obj.__args__))}\n    if isinstance(obj, (re.Pattern, re.Match)):\n        return {\"re\"}\n    if isinstance(obj, st.SearchStrategy):\n        return _imports_for_strategy(obj)\n    if isinstance(obj, getattr(sys.modules.get(\"numpy\"), \"dtype\", ())):\n        return {(\"numpy\", \"dtype\")}\n    try:\n        if is_generic_type(obj):\n            if isinstance(obj, TypeVar):\n                return {(obj.__module__, obj.__name__)}\n            with contextlib.suppress(Exception):\n                return set().union(*map(_imports_for_object, obj.__args__))\n        if (not callable(obj)) or obj.__name__ == \"<lambda>\":\n            return set()\n        name = _get_qualname(obj).split(\".\")[0]\n        return {(_get_module(obj), name)}\n    except Exception:\n        return set()\n\n\ndef _imports_for_strategy(strategy):\n    # If we have a lazy from_type strategy, because unwrapping it gives us an\n    # error or invalid syntax, import that type and we're done.\n    if isinstance(strategy, LazyStrategy):\n        imports = {\n            imp\n            for arg in set(strategy._LazyStrategy__args)\n            | set(strategy._LazyStrategy__kwargs.values())\n            for imp in _imports_for_object(_strip_typevars(arg))\n        }\n        if re.match(r\"from_(type|regex)\\(\", repr(strategy)):\n            return imports\n        elif _get_module(strategy.function).startswith(\"hypothesis.extra.\"):\n            module = _get_module(strategy.function).replace(\"._array_helpers\", \".numpy\")\n            return {(module, strategy.function.__name__)} | imports\n\n    imports = set()\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", SmallSearchSpaceWarning)\n        strategy = unwrap_strategies(strategy)\n\n    # Get imports for s.map(f), s.filter(f), s.flatmap(f), including both s and f\n    if isinstance(strategy, MappedStrategy):\n        imports |= _imports_for_strategy(strategy.mapped_strategy)\n        imports |= _imports_for_object(strategy.pack)\n    if isinstance(strategy, FilteredStrategy):\n        imports |= _imports_for_strategy(strategy.filtered_strategy)\n        for f in strategy.flat_conditions:\n            imports |= _imports_for_object(f)\n    if isinstance(strategy, FlatMapStrategy):\n        imports |= _imports_for_strategy(strategy.base)\n        imports |= _imports_for_object(strategy.expand)\n\n    # recurse through one_of to handle e.g. from_type(Optional[Foo])\n    if isinstance(strategy, OneOfStrategy):\n        for s in strategy.element_strategies:\n            imports |= _imports_for_strategy(s)\n\n    # get imports for the target of builds(), and recurse into the argument strategies\n    if isinstance(strategy, BuildsStrategy):\n        imports |= _imports_for_object(strategy.target)\n        for s in strategy.args:\n            imports |= _imports_for_strategy(s)\n        for s in strategy.kwargs.values():\n            imports |= _imports_for_strategy(s)\n\n    if isinstance(strategy, SampledFromStrategy):\n        for obj in strategy.elements:\n            imports |= _imports_for_object(obj)\n\n    if isinstance(strategy, ListStrategy):\n        imports |= _imports_for_strategy(strategy.element_strategy)\n\n    return imports\n\n\ndef _valid_syntax_repr(strategy):\n    # For binary_op, we pass a variable name - so pass it right back again.\n    if isinstance(strategy, str):\n        return set(), strategy\n    # Flatten and de-duplicate any one_of strategies, whether that's from resolving\n    # a Union type or combining inputs to multiple functions.\n    try:\n        if isinstance(strategy, DeferredStrategy):\n            strategy = strategy.wrapped_strategy\n        if isinstance(strategy, OneOfStrategy):\n            seen = set()\n            elems = []\n            with warnings.catch_warnings():\n                warnings.simplefilter(\"ignore\", SmallSearchSpaceWarning)\n                strategy.element_strategies  # might warn on first access\n            for s in strategy.element_strategies:\n                if isinstance(s, SampledFromStrategy) and s.elements == (os.environ,):\n                    continue\n                if repr(s) not in seen:\n                    elems.append(s)\n                    seen.add(repr(s))\n            strategy = st.one_of(elems or st.nothing())\n        # hardcode some special cases for nicer reprs\n        if strategy == st.text().wrapped_strategy:\n            return set(), \"text()\"\n        if strategy == st.from_type(type):\n            return set(), \"from_type(type)\"\n        # Remove any typevars; we don't exploit them so they're just clutter here\n        if (\n            isinstance(strategy, LazyStrategy)\n            and strategy.function.__name__ == st.from_type.__name__\n            and strategy._LazyStrategy__representation is None\n        ):\n            strategy._LazyStrategy__args = tuple(\n                _strip_typevars(a) for a in strategy._LazyStrategy__args\n            )\n        # Return a syntactically-valid strategy repr, including fixing some\n        # strategy reprs and replacing invalid syntax reprs with `\"nothing()\"`.\n        # String-replace to hide the special case in from_type() for Decimal('snan')\n        r = (\n            repr(strategy)\n            .replace(\".filter(_can_hash)\", \"\")\n            .replace(\"hypothesis.strategies.\", \"\")\n        )\n        # Replace <unknown> with ... in confusing lambdas\n        r = re.sub(r\"(lambda.*?: )(<unknown>)([,)])\", r\"\\1...\\3\", r)\n        compile(r, \"<string>\", \"eval\")\n        # Finally, try to work out the imports we need for builds(), .map(),\n        # .filter(), and .flatmap() to work without NameError\n        imports = {i for i in _imports_for_strategy(strategy) if i[1] in r}\n        return imports, r\n    except (SyntaxError, RecursionError, InvalidArgument):\n        return set(), \"nothing()\"\n\n\n# When we ghostwrite for a module, we want to treat that as the __module__ for\n# each function, rather than whichever internal file it was actually defined in.\nKNOWN_FUNCTION_LOCATIONS: dict[object, str] = {}\n\n\ndef _get_module_helper(obj):\n    # Get the __module__ attribute of the object, and return the first ancestor module\n    # which contains the object; falling back to the literal __module__ if none do.\n    # The goal is to show location from which obj should usually be accessed, rather\n    # than what we assume is an internal submodule which defined it.\n    module_name = obj.__module__\n\n    # if \"collections.abc\" is used don't use the deprecated aliases in \"collections\"\n    if module_name == \"collections.abc\":\n        return module_name\n\n    dots = [i for i, c in enumerate(module_name) if c == \".\"] + [None]\n    for idx in dots:\n        for candidate in (module_name[:idx].lstrip(\"_\"), module_name[:idx]):\n            if getattr(sys.modules.get(candidate), obj.__name__, None) is obj:\n                KNOWN_FUNCTION_LOCATIONS[obj] = candidate\n                return candidate\n    return module_name\n\n\ndef _get_module(obj):\n    if obj in KNOWN_FUNCTION_LOCATIONS:\n        return KNOWN_FUNCTION_LOCATIONS[obj]\n    try:\n        return _get_module_helper(obj)\n    except AttributeError:\n        if not _is_probably_ufunc(obj):\n            raise\n    for module_name in sorted(sys.modules, key=lambda n: tuple(n.split(\".\"))):\n        if obj is getattr(sys.modules[module_name], obj.__name__, None):\n            KNOWN_FUNCTION_LOCATIONS[obj] = module_name\n            return module_name\n    raise RuntimeError(f\"Could not find module for ufunc {obj.__name__} ({obj!r}\")\n\n\ndef _get_qualname(obj: Any, *, include_module: bool = False) -> str:\n    # Replacing angle-brackets for objects defined in `.<locals>.`\n    qname = getattr(obj, \"__qualname__\", obj.__name__)\n    qname = qname.replace(\"<\", \"_\").replace(\">\", \"_\").replace(\" \", \"\")\n    if include_module:\n        return _get_module(obj) + \".\" + qname\n    return qname\n\n\ndef _write_call(\n    func: Callable, *pass_variables: str, except_: Except = Exception, assign: str = \"\"\n) -> str:\n    \"\"\"Write a call to `func` with explicit and implicit arguments.\n\n    >>> _write_call(sorted, \"my_seq\", \"func\")\n    \"builtins.sorted(my_seq, key=func, reverse=reverse)\"\n\n    >>> write_call(f, assign=\"var1\")\n    \"var1 = f()\"\n\n    The fancy part is that we'll check the docstring for any known exceptions\n    which `func` might raise, and catch-and-reject on them... *unless* they're\n    subtypes of `except_`, which will be handled in an outer try-except block.\n    \"\"\"\n    args = \", \".join(\n        (\n            (v or p.name)\n            if p.kind is inspect.Parameter.POSITIONAL_ONLY\n            else f\"{p.name}={v or p.name}\"\n        )\n        for v, p in zip_longest(pass_variables, _get_params(func).values())\n    )\n    call = f\"{_get_qualname(func, include_module=True)}({args})\"\n    if assign:\n        call = f\"{assign} = {call}\"\n    raises = _exceptions_from_docstring(getattr(func, \"__doc__\", \"\") or \"\")\n    exnames = [ex.__name__ for ex in raises if not issubclass(ex, except_)]\n    if not exnames:\n        return call\n    return SUPPRESS_BLOCK.format(\n        test_body=indent(call, prefix=\"    \"),\n        exceptions=\"(\" + \", \".join(exnames) + \")\" if len(exnames) > 1 else exnames[0],\n    )\n\n\ndef _st_strategy_names(s: str) -> str:\n    \"\"\"Replace strategy name() with st.name().\n\n    Uses a tricky re.sub() to avoid problems with frozensets() matching\n    sets() too.\n    \"\"\"\n    names = \"|\".join(sorted(st.__all__, key=len, reverse=True))\n    return re.sub(pattern=rf\"\\b(?:{names})\\b[^= ]\", repl=r\"st.\\g<0>\", string=s)\n\n\ndef _make_test_body(\n    *funcs: Callable,\n    ghost: str,\n    test_body: str,\n    except_: tuple[type[Exception], ...],\n    assertions: str = \"\",\n    style: str,\n    given_strategies: Mapping[str, str | st.SearchStrategy] | None = None,\n    imports: ImportSet | None = None,\n    annotate: bool,\n) -> tuple[ImportSet, str]:\n    # A set of modules to import - we might add to this later.  The import code\n    # is written later, so we can have one import section for multiple magic()\n    # test functions.\n    imports = (imports or set()) | {_get_module(f) for f in funcs}\n\n    # Get strategies for all the arguments to each function we're testing.\n    with _with_any_registered():\n        given_strategies = given_strategies or _get_strategies(\n            *funcs, pass_result_to_next_func=ghost in (\"idempotent\", \"roundtrip\")\n        )\n        reprs = [((k, *_valid_syntax_repr(v))) for k, v in given_strategies.items()]\n        imports = imports.union(*(imp for _, imp, _ in reprs))\n        given_args = \", \".join(f\"{k}={v}\" for k, _, v in reprs)\n    given_args = _st_strategy_names(given_args)\n\n    if except_:\n        # Convert to strings, either builtin names or qualified names.\n        imp, exc_string = _exception_string(except_)\n        imports.update(imp)\n        # And finally indent the existing test body into a try-except block\n        # which catches these exceptions and calls `hypothesis.reject()`.\n        test_body = SUPPRESS_BLOCK.format(\n            test_body=indent(test_body, prefix=\"    \"),\n            exceptions=exc_string,\n        )\n\n    if assertions:\n        test_body = f\"{test_body}\\n{assertions}\"\n\n    # Indent our test code to form the body of a function or method.\n    argnames = [\"self\"] if style == \"unittest\" else []\n    if annotate:\n        argnames.extend(_annotate_args(given_strategies, funcs, imports))\n    else:\n        argnames.extend(given_strategies)\n\n    body = TEMPLATE.format(\n        given_args=given_args,\n        test_kind=ghost,\n        func_name=\"_\".join(_get_qualname(f).replace(\".\", \"_\") for f in funcs),\n        arg_names=\", \".join(argnames),\n        return_annotation=\" -> None\" if annotate else \"\",\n        test_body=indent(test_body, prefix=\"    \"),\n    )\n\n    # For unittest-style, indent method further into a class body\n    if style == \"unittest\":\n        imports.add(\"unittest\")\n        body = \"class Test{}{}(unittest.TestCase):\\n{}\".format(\n            ghost.title(),\n            \"\".join(_get_qualname(f).replace(\".\", \"\").title() for f in funcs),\n            indent(body, \"    \"),\n        )\n\n    return imports, body\n\n\ndef _annotate_args(\n    argnames: Iterable[str], funcs: Iterable[Callable], imports: ImportSet\n) -> Iterable[str]:\n    arg_parameters: defaultdict[str, set[Any]] = defaultdict(set)\n    for func in funcs:\n        try:\n            params = tuple(get_signature(func, eval_str=True).parameters.values())\n        except Exception:\n            # don't add parameters if the annotations could not be evaluated\n            pass\n        else:\n            for key, param in _params_to_dict(params).items():\n                if param.annotation != inspect.Parameter.empty:\n                    arg_parameters[key].add(param.annotation)\n\n    for argname in argnames:\n        parameters = arg_parameters.get(argname)\n        annotation = _parameters_to_annotation_name(parameters, imports)\n        if annotation is None:\n            yield argname\n        else:\n            yield f\"{argname}: {annotation}\"\n\n\nclass _AnnotationData(NamedTuple):\n    type_name: str\n    imports: set[str]\n\n\ndef _parameters_to_annotation_name(\n    parameters: Iterable[Any] | None, imports: ImportSet\n) -> str | None:\n    if parameters is None:\n        return None\n    annotations = tuple(\n        annotation\n        for annotation in map(_parameter_to_annotation, parameters)\n        if annotation is not None\n    )\n    if not annotations:\n        return None\n    if len(annotations) == 1:\n        type_name, new_imports = annotations[0]\n        imports.update(new_imports)\n        return type_name\n    joined = _join_generics((\"typing.Union\", {\"typing\"}), annotations)\n    if joined is None:\n        return None\n    imports.update(joined.imports)\n    return joined.type_name\n\n\ndef _join_generics(\n    origin_type_data: tuple[str, set[str]] | None,\n    annotations: Iterable[_AnnotationData | None],\n) -> _AnnotationData | None:\n    if origin_type_data is None:\n        return None\n\n    # because typing.Optional is converted to a Union, it also contains None\n    # since typing.Optional only accepts one type variable, we need to remove it\n    if origin_type_data is not None and origin_type_data[0] == \"typing.Optional\":\n        annotations = (\n            annotation\n            for annotation in annotations\n            if annotation is None or annotation.type_name != \"None\"\n        )\n\n    origin_type, imports = origin_type_data\n    joined = _join_argument_annotations(annotations)\n    if joined is None or not joined[0]:\n        return None\n\n    arg_types, new_imports = joined\n    imports.update(new_imports)\n    return _AnnotationData(\"{}[{}]\".format(origin_type, \", \".join(arg_types)), imports)\n\n\ndef _join_argument_annotations(\n    annotations: Iterable[_AnnotationData | None],\n) -> tuple[list[str], set[str]] | None:\n    imports: set[str] = set()\n    arg_types: list[str] = []\n\n    for annotation in annotations:\n        if annotation is None:\n            return None\n        arg_types.append(annotation.type_name)\n        imports.update(annotation.imports)\n\n    return arg_types, imports\n\n\ndef _parameter_to_annotation(parameter: Any) -> _AnnotationData | None:\n    # if a ForwardRef could not be resolved\n    if isinstance(parameter, str):\n        return None\n\n    if isinstance(parameter, ForwardRef):\n        if sys.version_info[:2] < (3, 14):\n            forwarded_value = parameter.__forward_value__\n            if forwarded_value is None:\n                return None\n        else:\n            # ForwardRef.__forward_value__ was removed in 3.14 in favor of\n            # ForwardRef.evaluate(). See also PEP 649, PEP 749, and\n            # typing.evaluate_forward_ref.\n            #\n            # .evaluate() with Format.VALUE (the default) throws if the name\n            # could not be resolved.\n            # https://docs.python.org/3.14/library/annotationlib.html#annotationlib.ForwardRef.evaluate\n            try:\n                forwarded_value = parameter.evaluate()\n            except Exception:\n                return None\n        return _parameter_to_annotation(forwarded_value)\n\n    # the arguments of Callable are in a list\n    if isinstance(parameter, list):\n        joined = _join_argument_annotations(\n            _parameter_to_annotation(param) for param in parameter\n        )\n        if joined is None:\n            return None\n        arg_type_names, new_imports = joined\n        return _AnnotationData(\"[{}]\".format(\", \".join(arg_type_names)), new_imports)\n\n    if isinstance(parameter, type):\n        if parameter.__module__ == \"builtins\":\n            return _AnnotationData(\n                \"None\" if parameter.__name__ == \"NoneType\" else parameter.__name__,\n                set(),\n            )\n\n        type_name = _get_qualname(parameter, include_module=True)\n\n        # the types.UnionType does not support type arguments and needs to be translated\n        if type_name == \"types.UnionType\":\n            return _AnnotationData(\"typing.Union\", {\"typing\"})\n    else:\n        if hasattr(parameter, \"__module__\") and hasattr(parameter, \"__name__\"):\n            type_name = _get_qualname(parameter, include_module=True)\n        else:\n            type_name = str(parameter)\n\n    if type_name.startswith(\"hypothesis.strategies.\"):\n        return _AnnotationData(type_name.replace(\"hypothesis.strategies\", \"st\"), set())\n\n    origin_type = get_origin(parameter)\n\n    # if not generic or no generic arguments\n    if origin_type is None or origin_type == parameter:\n        return _AnnotationData(type_name, set(type_name.rsplit(\".\", maxsplit=1)[:-1]))\n\n    arg_types = get_args(parameter)\n    if {type(a) for a in arg_types} == {TypeVar}:\n        arg_types = ()\n\n    # typing types get translated to classes that don't support generics\n    origin_annotation: _AnnotationData | None\n    if type_name.startswith(\"typing.\"):\n        try:\n            new_type_name = type_name[: type_name.index(\"[\")]\n        except ValueError:\n            new_type_name = type_name\n        origin_annotation = _AnnotationData(new_type_name, {\"typing\"})\n    else:\n        origin_annotation = _parameter_to_annotation(origin_type)\n\n    if arg_types:\n        return _join_generics(\n            origin_annotation,\n            (_parameter_to_annotation(arg_type) for arg_type in arg_types),\n        )\n    return origin_annotation\n\n\ndef _are_annotations_used(*functions: Callable) -> bool:\n    for function in functions:\n        try:\n            params = get_signature(function).parameters.values()\n        except Exception:\n            pass\n        else:\n            if any(param.annotation != inspect.Parameter.empty for param in params):\n                return True\n    return False\n\n\ndef _make_test(imports: ImportSet, body: str) -> str:\n    # Discarding \"builtins.\" and \"__main__\" probably isn't particularly useful\n    # for user code, but important for making a good impression in demos.\n    body = body.replace(\"builtins.\", \"\").replace(\"__main__.\", \"\")\n    imports |= {(\"hypothesis\", \"given\"), (\"hypothesis\", \"strategies as st\")}\n    if \"        reject()\\n\" in body:\n        imports.add((\"hypothesis\", \"reject\"))\n\n    do_not_import = {\"builtins\", \"__main__\", \"hypothesis.strategies\"}\n    direct = {f\"import {i}\" for i in imports - do_not_import if isinstance(i, str)}\n    from_imports = defaultdict(set)\n    for module, name in {i for i in imports if isinstance(i, tuple)}:\n        if not (module.startswith(\"hypothesis.strategies\") and name in st.__all__):\n            from_imports[module].add(name)\n    from_ = {\n        \"from {} import {}\".format(module, \", \".join(sorted(names)))\n        for module, names in from_imports.items()\n        if isinstance(module, str) and module not in do_not_import\n    }\n    header = IMPORT_SECTION.format(imports=\"\\n\".join(sorted(direct) + sorted(from_)))\n    nothings = body.count(\"st.nothing()\")\n    if nothings == 1:\n        header += \"# TODO: replace st.nothing() with an appropriate strategy\\n\\n\"\n    elif nothings >= 1:\n        header += \"# TODO: replace st.nothing() with appropriate strategies\\n\\n\"\n    return black.format_str(header + body, mode=black.Mode())\n\n\ndef _is_probably_ufunc(obj):\n    # See https://numpy.org/doc/stable/reference/ufuncs.html - there doesn't seem\n    # to be an upstream function to detect this, so we just guess.\n    has_attributes = [\n        \"nin\",\n        \"nout\",\n        \"nargs\",\n        \"ntypes\",\n        \"types\",\n        \"identity\",\n        \"signature\",\n    ]\n    return callable(obj) and all(hasattr(obj, name) for name in has_attributes)\n\n\n# If we have a pair of functions where one name matches the regex and the second\n# is the result of formatting the template with matched groups, our magic()\n# ghostwriter will write a roundtrip test for them.  Additional patterns welcome.\nROUNDTRIP_PAIRS = (\n    # Defined prefix, shared postfix.  The easy cases.\n    (r\"write(.+)\", \"read{}\"),\n    (r\"save(.+)\", \"load{}\"),\n    (r\"dump(.+)\", \"load{}\"),\n    (r\"to(.+)\", \"from{}\"),\n    # Known stem, maybe matching prefixes, maybe matching postfixes.\n    (r\"(.*)en(.+)\", \"{}de{}\"),\n    # Shared postfix, prefix only on \"inverse\" function\n    (r\"(.+)\", \"de{}\"),\n    (r\"(?!safe)(.+)\", \"un{}\"),  # safe_load / unsafe_load isn't a roundtrip\n    # a2b_postfix and b2a_postfix.  Not a fan of this pattern, but it's pretty\n    # common in code imitating an C API - see e.g. the stdlib binascii module.\n    (r\"(.+)2(.+?)(_.+)?\", \"{1}2{0}{2}\"),\n    # Common in e.g. the colorsys module\n    (r\"(.+)_to_(.+)\", \"{1}_to_{0}\"),\n    # Sockets patterns\n    (r\"(inet|if)_(.+)to(.+)\", \"{0}_{2}to{1}\"),\n    (r\"(\\w)to(\\w)(.+)\", \"{1}to{0}{2}\"),\n    (r\"send(.+)\", \"recv{}\"),\n    (r\"send(.+)\", \"receive{}\"),\n)\n\n\ndef _get_testable_functions(thing: object) -> dict[str, Callable]:\n    by_name = {}\n    if callable(thing):\n        funcs: list[Any | None] = [thing]\n    elif isinstance(thing, types.ModuleType):\n        if hasattr(thing, \"__all__\"):\n            funcs = [getattr(thing, name, None) for name in thing.__all__]\n        elif hasattr(thing, \"__package__\"):\n            pkg = thing.__package__\n            funcs = [\n                v\n                for k, v in vars(thing).items()\n                if callable(v)\n                and not is_mock(v)\n                and ((not pkg) or getattr(v, \"__module__\", pkg).startswith(pkg))\n                and not k.startswith(\"_\")\n            ]\n            if pkg and any(getattr(f, \"__module__\", pkg) == pkg for f in funcs):\n                funcs = [f for f in funcs if getattr(f, \"__module__\", pkg) == pkg]\n    else:\n        raise InvalidArgument(f\"Can't test non-module non-callable {thing!r}\")\n\n    for f in list(funcs):\n        if inspect.isclass(f):\n            funcs += [\n                v.__get__(f)\n                for k, v in vars(f).items()\n                if hasattr(v, \"__func__\") and not is_mock(v) and not k.startswith(\"_\")\n            ]\n    for f in funcs:\n        try:\n            if (\n                (not is_mock(f))\n                and callable(f)\n                and _get_params(f)\n                and not isinstance(f, enum.EnumMeta)\n            ):\n                if getattr(thing, \"__name__\", None):\n                    if inspect.isclass(thing):\n                        KNOWN_FUNCTION_LOCATIONS[f] = _get_module_helper(thing)\n                    elif isinstance(thing, types.ModuleType):\n                        KNOWN_FUNCTION_LOCATIONS[f] = thing.__name__\n                try:\n                    _get_params(f)\n                    by_name[_get_qualname(f, include_module=True)] = f\n                except Exception:\n                    # usually inspect.signature on C code such as socket.inet_aton,\n                    # or Pandas 'CallableDynamicDoc' object has no attr. '__name__'\n                    pass\n        except (TypeError, ValueError):\n            pass\n    return by_name\n\n\ndef magic(\n    *modules_or_functions: Callable | types.ModuleType,\n    except_: Except = (),\n    style: str = \"pytest\",\n    annotate: bool | None = None,\n) -> str:\n    \"\"\"Guess which ghostwriters to use, for a module or collection of functions.\n\n    As for all ghostwriters, the ``except_`` argument should be an\n    :class:`python:Exception` or tuple of exceptions, and ``style`` may be either\n    ``\"pytest\"`` to write test functions or ``\"unittest\"`` to write test methods\n    and :class:`~python:unittest.TestCase`.\n\n    After finding the public functions attached to any modules, the ``magic``\n    ghostwriter looks for pairs of functions to pass to :func:`~roundtrip`,\n    then checks for :func:`~binary_operation` and :func:`~ufunc` functions,\n    and any others are passed to :func:`~fuzz`.\n\n    For example, try :command:`hypothesis write gzip` on the command line!\n    \"\"\"\n    except_ = _check_except(except_)\n    _check_style(style)\n    if not modules_or_functions:\n        raise InvalidArgument(\"Must pass at least one function or module to test.\")\n\n    parts = []\n    by_name = {}\n    imports = set()\n\n    for thing in modules_or_functions:\n        by_name.update(found := _get_testable_functions(thing))\n        if (not found) and isinstance(thing, types.ModuleType):\n            msg = f\"# Found no testable functions in {thing.__name__} (from {thing.__file__!r})\"\n            mods: list = []\n            for k in sorted(sys.modules, key=len):\n                if (\n                    k.startswith(f\"{thing.__name__}.\")\n                    and \"._\" not in k.removeprefix(thing.__name__)\n                    and not k.startswith(tuple(f\"{m}.\" for m in mods))\n                    and _get_testable_functions(sys.modules[k])\n                ):\n                    mods.append(k)\n            if mods:\n                msg += (\n                    f\"\\n# Try writing tests for submodules, e.g. by using:\\n\"\n                    f\"#     hypothesis write {' '.join(sorted(mods))}\"\n                )\n            parts.append(msg)\n\n    if not by_name:\n        return \"\\n\\n\".join(parts)\n\n    if annotate is None:\n        annotate = _are_annotations_used(*by_name.values())\n\n    def make_(how, *args, **kwargs):\n        imp, body = how(*args, **kwargs, except_=except_, style=style)\n        imports.update(imp)\n        parts.append(body)\n\n    # Look for pairs of functions that roundtrip, based on known naming patterns.\n    for writename, readname in ROUNDTRIP_PAIRS:\n        for name in sorted(by_name):\n            match = re.fullmatch(writename, name.split(\".\")[-1])\n            if match:\n                inverse_name = readname.format(*match.groups())\n                for other in sorted(\n                    n for n in by_name if n.split(\".\")[-1] == inverse_name\n                ):\n                    make_(\n                        _make_roundtrip_body,\n                        (by_name.pop(name), by_name.pop(other)),\n                        annotate=annotate,\n                    )\n                    break\n                else:\n                    try:\n                        other_func = getattr(\n                            sys.modules[_get_module(by_name[name])],\n                            inverse_name,\n                        )\n                        _get_params(other_func)  # we want to skip if this fails\n                    except Exception:\n                        pass\n                    else:\n                        make_(\n                            _make_roundtrip_body,\n                            (by_name.pop(name), other_func),\n                            annotate=annotate,\n                        )\n\n    # Look for equivalent functions: same name, all required arguments of any can\n    # be found in all signatures, and if all have return-type annotations they match.\n    names = defaultdict(list)\n    for _, f in sorted(by_name.items()):\n        names[_get_qualname(f)].append(f)\n    for group in names.values():\n        if len(group) >= 2 and len({frozenset(_get_params(f)) for f in group}) == 1:\n            sentinel = object()\n            returns = {get_type_hints(f).get(\"return\", sentinel) for f in group}\n            if len(returns - {sentinel}) <= 1:\n                make_(_make_equiv_body, group, annotate=annotate)\n                for f in group:\n                    by_name.pop(_get_qualname(f, include_module=True))\n\n    # Look for binary operators - functions with two identically-typed arguments,\n    # and the same return type.  The latter restriction might be lifted later.\n    for name, func in sorted(by_name.items()):\n        hints = get_type_hints(func)\n        hints.pop(\"return\", None)\n        params = _get_params(func)\n        if (len(hints) == len(params) == 2) or (\n            _get_module(func) == \"operator\"\n            and \"item\" not in func.__name__\n            and tuple(params) in [(\"a\", \"b\"), (\"x\", \"y\")]\n        ):\n            a, b = hints.values() or [Any, Any]\n            arg1, arg2 = params\n            if a == b and len(arg1) == len(arg2) <= 3:\n                # https://en.wikipedia.org/wiki/Distributive_property#Other_examples\n                known = {\n                    \"mul\": \"add\",\n                    \"matmul\": \"add\",\n                    \"or_\": \"and_\",\n                    \"and_\": \"or_\",\n                }.get(func.__name__, \"\")\n                distributes_over = getattr(sys.modules[_get_module(func)], known, None)\n                make_(\n                    _make_binop_body,\n                    func,\n                    commutative=func.__name__ != \"matmul\",\n                    distributes_over=distributes_over,\n                    annotate=annotate,\n                )\n                del by_name[name]\n\n    # Look for Numpy ufuncs or gufuncs, and write array-oriented tests for them.\n    if \"numpy\" in sys.modules:\n        for name, func in sorted(by_name.items()):\n            if _is_probably_ufunc(func):\n                make_(_make_ufunc_body, func, annotate=annotate)\n                del by_name[name]\n\n    # For all remaining callables, just write a fuzz-test.  In principle we could\n    # guess at equivalence or idempotence; but it doesn't seem accurate enough to\n    # be worth the trouble when it's so easy for the user to specify themselves.\n    for _, f in sorted(by_name.items()):\n        make_(\n            _make_test_body,\n            f,\n            test_body=_write_call(f, except_=except_),\n            ghost=\"fuzz\",\n            annotate=annotate,\n        )\n    return _make_test(imports, \"\\n\".join(parts))\n\n\ndef fuzz(\n    func: Callable,\n    *,\n    except_: Except = (),\n    style: str = \"pytest\",\n    annotate: bool | None = None,\n) -> str:\n    \"\"\"Write source code for a property-based test of ``func``.\n\n    The resulting test checks that valid input only leads to expected exceptions.\n    For example:\n\n    .. code-block:: python\n\n        from re import compile, error\n\n        from hypothesis.extra import ghostwriter\n\n        ghostwriter.fuzz(compile, except_=error)\n\n    Gives:\n\n    .. code-block:: python\n\n        # This test code was written by the `hypothesis.extra.ghostwriter` module\n        # and is provided under the Creative Commons Zero public domain dedication.\n        import re\n\n        from hypothesis import given, reject, strategies as st\n\n        # TODO: replace st.nothing() with an appropriate strategy\n\n\n        @given(pattern=st.nothing(), flags=st.just(0))\n        def test_fuzz_compile(pattern, flags):\n            try:\n                re.compile(pattern=pattern, flags=flags)\n            except re.error:\n                reject()\n\n    Note that it includes all the required imports.\n    Because the ``pattern`` parameter doesn't have annotations or a default argument,\n    you'll need to specify a strategy - for example :func:`~hypothesis.strategies.text`\n    or :func:`~hypothesis.strategies.binary`.  After that, you have a test!\n    \"\"\"\n    if not callable(func):\n        raise InvalidArgument(f\"Got non-callable {func=}\")\n    except_ = _check_except(except_)\n    _check_style(style)\n\n    if annotate is None:\n        annotate = _are_annotations_used(func)\n\n    imports, body = _make_test_body(\n        func,\n        test_body=_write_call(func, except_=except_),\n        except_=except_,\n        ghost=\"fuzz\",\n        style=style,\n        annotate=annotate,\n    )\n    return _make_test(imports, body)\n\n\ndef idempotent(\n    func: Callable,\n    *,\n    except_: Except = (),\n    style: str = \"pytest\",\n    annotate: bool | None = None,\n) -> str:\n    \"\"\"Write source code for a property-based test of ``func``.\n\n    The resulting test checks that if you call ``func`` on it's own output,\n    the result does not change.  For example:\n\n    .. code-block:: python\n\n        from typing import Sequence\n\n        from hypothesis.extra import ghostwriter\n\n\n        def timsort(seq: Sequence[int]) -> Sequence[int]:\n            return sorted(seq)\n\n\n        ghostwriter.idempotent(timsort)\n\n    Gives:\n\n    .. code-block:: python\n\n        # This test code was written by the `hypothesis.extra.ghostwriter` module\n        # and is provided under the Creative Commons Zero public domain dedication.\n\n        from hypothesis import given, strategies as st\n\n\n        @given(seq=st.one_of(st.binary(), st.binary().map(bytearray), st.lists(st.integers())))\n        def test_idempotent_timsort(seq):\n            result = timsort(seq=seq)\n            repeat = timsort(seq=result)\n            assert result == repeat, (result, repeat)\n    \"\"\"\n    if not callable(func):\n        raise InvalidArgument(f\"Got non-callable {func=}\")\n    except_ = _check_except(except_)\n    _check_style(style)\n\n    if annotate is None:\n        annotate = _are_annotations_used(func)\n\n    imports, body = _make_test_body(\n        func,\n        test_body=\"result = {}\\nrepeat = {}\".format(\n            _write_call(func, except_=except_),\n            _write_call(func, \"result\", except_=except_),\n        ),\n        except_=except_,\n        assertions=_assert_eq(style, \"result\", \"repeat\"),\n        ghost=\"idempotent\",\n        style=style,\n        annotate=annotate,\n    )\n    return _make_test(imports, body)\n\n\ndef _make_roundtrip_body(funcs, except_, style, annotate):\n    first_param = next(iter(_get_params(funcs[0])))\n    test_lines = [\n        _write_call(funcs[0], assign=\"value0\", except_=except_),\n        *(\n            _write_call(f, f\"value{i}\", assign=f\"value{i + 1}\", except_=except_)\n            for i, f in enumerate(funcs[1:])\n        ),\n    ]\n    return _make_test_body(\n        *funcs,\n        test_body=\"\\n\".join(test_lines),\n        except_=except_,\n        assertions=_assert_eq(style, first_param, f\"value{len(funcs) - 1}\"),\n        ghost=\"roundtrip\",\n        style=style,\n        annotate=annotate,\n    )\n\n\ndef roundtrip(\n    *funcs: Callable,\n    except_: Except = (),\n    style: str = \"pytest\",\n    annotate: bool | None = None,\n) -> str:\n    \"\"\"Write source code for a property-based test of ``funcs``.\n\n    The resulting test checks that if you call the first function, pass the result\n    to the second (and so on), the final result is equal to the first input argument.\n\n    This is a *very* powerful property to test, especially when the config options\n    are varied along with the object to round-trip.  For example, try ghostwriting\n    a test for :func:`python:json.dumps` - would you have thought of all that?\n\n    .. code-block:: shell\n\n        hypothesis write --roundtrip json.dumps json.loads\n    \"\"\"\n    if not funcs:\n        raise InvalidArgument(\"Round-trip of zero functions is meaningless.\")\n    for i, f in enumerate(funcs):\n        if not callable(f):\n            raise InvalidArgument(f\"Got non-callable funcs[{i}]={f!r}\")\n    except_ = _check_except(except_)\n    _check_style(style)\n\n    if annotate is None:\n        annotate = _are_annotations_used(*funcs)\n\n    return _make_test(*_make_roundtrip_body(funcs, except_, style, annotate))\n\n\ndef _get_varnames(funcs):\n    var_names = [f\"result_{f.__name__}\" for f in funcs]\n    if len(set(var_names)) < len(var_names):\n        var_names = [f\"result_{f.__name__}_{_get_module(f)}\" for f in funcs]\n    if len(set(var_names)) < len(var_names):\n        var_names = [f\"result_{i}_{f.__name__}\" for i, f in enumerate(funcs)]\n    return var_names\n\n\ndef _make_equiv_body(funcs, except_, style, annotate):\n    var_names = _get_varnames(funcs)\n    test_lines = [\n        _write_call(f, assign=vname, except_=except_)\n        for vname, f in zip(var_names, funcs, strict=True)\n    ]\n    assertions = \"\\n\".join(\n        _assert_eq(style, var_names[0], vname) for vname in var_names[1:]\n    )\n\n    return _make_test_body(\n        *funcs,\n        test_body=\"\\n\".join(test_lines),\n        except_=except_,\n        assertions=assertions,\n        ghost=\"equivalent\",\n        style=style,\n        annotate=annotate,\n    )\n\n\nEQUIV_FIRST_BLOCK = \"\"\"\ntry:\n{}\n    exc_type = None\n    target(1, label=\"input was valid\")\n{}except Exception as exc:\n    exc_type = type(exc)\n\"\"\".strip()\n\nEQUIV_CHECK_BLOCK = \"\"\"\nif exc_type:\n    with {ctx}(exc_type):\n{check_raises}\nelse:\n{call}\n{compare}\n\"\"\".rstrip()\n\n\ndef _make_equiv_errors_body(funcs, except_, style, annotate):\n    var_names = _get_varnames(funcs)\n    first, *rest = funcs\n    first_call = _write_call(first, assign=var_names[0], except_=except_)\n    extra_imports, suppress = _exception_string(except_)\n    extra_imports.add((\"hypothesis\", \"target\"))\n    catch = f\"except {suppress}:\\n    reject()\\n\" if suppress else \"\"\n    test_lines = [EQUIV_FIRST_BLOCK.format(indent(first_call, prefix=\"    \"), catch)]\n\n    for vname, f in zip(var_names[1:], rest, strict=True):\n        if style == \"pytest\":\n            ctx = \"pytest.raises\"\n            extra_imports.add(\"pytest\")\n        else:\n            assert style == \"unittest\"\n            ctx = \"self.assertRaises\"\n        block = EQUIV_CHECK_BLOCK.format(\n            ctx=ctx,\n            check_raises=indent(_write_call(f, except_=()), \"        \"),\n            call=indent(_write_call(f, assign=vname, except_=()), \"    \"),\n            compare=indent(_assert_eq(style, var_names[0], vname), \"    \"),\n        )\n        test_lines.append(block)\n\n    imports, source_code = _make_test_body(\n        *funcs,\n        test_body=\"\\n\".join(test_lines),\n        except_=(),\n        ghost=\"equivalent\",\n        style=style,\n        annotate=annotate,\n    )\n    return imports | extra_imports, source_code\n\n\ndef equivalent(\n    *funcs: Callable,\n    allow_same_errors: bool = False,\n    except_: Except = (),\n    style: str = \"pytest\",\n    annotate: bool | None = None,\n) -> str:\n    \"\"\"Write source code for a property-based test of ``funcs``.\n\n    The resulting test checks that calling each of the functions returns\n    an equal value.  This can be used as a classic 'oracle', such as testing\n    a fast sorting algorithm against the :func:`python:sorted` builtin, or\n    for differential testing where none of the compared functions are fully\n    trusted but any difference indicates a bug (e.g. running a function on\n    different numbers of threads, or simply multiple times).\n\n    The functions should have reasonably similar signatures, as only the\n    common parameters will be passed the same arguments - any other parameters\n    will be allowed to vary.\n\n    If allow_same_errors is True, then the test will pass if calling each of\n    the functions returns an equal value, *or* if the first function raises an\n    exception and each of the others raises an exception of the same type.\n    This relaxed mode can be useful for code synthesis projects.\n    \"\"\"\n    if len(funcs) < 2:\n        raise InvalidArgument(\"Need at least two functions to compare.\")\n    for i, f in enumerate(funcs):\n        if not callable(f):\n            raise InvalidArgument(f\"Got non-callable funcs[{i}]={f!r}\")\n    check_type(bool, allow_same_errors, \"allow_same_errors\")\n    except_ = _check_except(except_)\n    _check_style(style)\n\n    if annotate is None:\n        annotate = _are_annotations_used(*funcs)\n\n    if allow_same_errors and not any(issubclass(Exception, ex) for ex in except_):\n        imports, source_code = _make_equiv_errors_body(funcs, except_, style, annotate)\n    else:\n        imports, source_code = _make_equiv_body(funcs, except_, style, annotate)\n    return _make_test(imports, source_code)\n\n\nX = TypeVar(\"X\")\nY = TypeVar(\"Y\")\n\n\ndef binary_operation(\n    func: Callable[[X, X], Y],\n    *,\n    associative: bool = True,\n    commutative: bool = True,\n    identity: X | EllipsisType | None = ...,\n    distributes_over: Callable[[X, X], X] | None = None,\n    except_: Except = (),\n    style: str = \"pytest\",\n    annotate: bool | None = None,\n) -> str:\n    \"\"\"Write property tests for the binary operation ``func``.\n\n    While :wikipedia:`binary operations <Binary_operation>` are not particularly\n    common, they have such nice properties to test that it seems a shame not to\n    demonstrate them with a ghostwriter.  For an operator ``f``, test that:\n\n    - if :wikipedia:`associative <Associative_property>`,\n      ``f(a, f(b, c)) == f(f(a, b), c)``\n    - if :wikipedia:`commutative <Commutative_property>`, ``f(a, b) == f(b, a)``\n    - if :wikipedia:`identity <Identity_element>` is not None, ``f(a, identity) == a``\n    - if :wikipedia:`distributes_over <Distributive_property>` is ``+``,\n      ``f(a, b) + f(a, c) == f(a, b+c)``\n\n    For example:\n\n    .. code-block:: python\n\n        ghostwriter.binary_operation(\n            operator.mul,\n            identity=1,\n            distributes_over=operator.add,\n            style=\"unittest\",\n        )\n    \"\"\"\n    if not callable(func):\n        raise InvalidArgument(f\"Got non-callable {func=}\")\n    except_ = _check_except(except_)\n    _check_style(style)\n    check_type(bool, associative, \"associative\")\n    check_type(bool, commutative, \"commutative\")\n    if distributes_over is not None and not callable(distributes_over):\n        raise InvalidArgument(\n            f\"{distributes_over=} must be an operation which \"\n            f\"distributes over {func.__name__}\"\n        )\n    if not any([associative, commutative, identity, distributes_over]):\n        raise InvalidArgument(\n            \"You must select at least one property of the binary operation to test.\"\n        )\n\n    if annotate is None:\n        annotate = _are_annotations_used(func)\n\n    imports, body = _make_binop_body(\n        func,\n        associative=associative,\n        commutative=commutative,\n        identity=identity,\n        distributes_over=distributes_over,\n        except_=except_,\n        style=style,\n        annotate=annotate,\n    )\n    return _make_test(imports, body)\n\n\ndef _make_binop_body(\n    func: Callable[[X, X], Y],\n    *,\n    associative: bool = True,\n    commutative: bool = True,\n    identity: X | EllipsisType | None = ...,\n    distributes_over: Callable[[X, X], X] | None = None,\n    except_: tuple[type[Exception], ...],\n    style: str,\n    annotate: bool,\n) -> tuple[ImportSet, str]:\n    strategies = _get_strategies(func)\n    operands, b = (strategies.pop(p) for p in list(_get_params(func))[:2])\n    if repr(operands) != repr(b):\n        operands |= b\n    operands_name = func.__name__ + \"_operands\"\n\n    all_imports = set()\n    parts = []\n\n    def maker(\n        sub_property: str,\n        args: str,\n        body: str,\n        right: str | None = None,\n    ) -> None:\n        if right is None:\n            assertions = \"\"\n        else:\n            body = f\"{body}\\n{right}\"\n            assertions = _assert_eq(style, \"left\", \"right\")\n        imports, body = _make_test_body(\n            func,\n            test_body=body,\n            ghost=sub_property + \"_binary_operation\",\n            except_=except_,\n            assertions=assertions,\n            style=style,\n            given_strategies={**strategies, **{n: operands_name for n in args}},\n            annotate=annotate,\n        )\n        all_imports.update(imports)\n        if style == \"unittest\":\n            endline = \"(unittest.TestCase):\\n\"\n            body = body[body.index(endline) + len(endline) + 1 :]\n        parts.append(body)\n\n    if associative:\n        maker(\n            \"associative\",\n            \"abc\",\n            _write_call(func, \"a\", _write_call(func, \"b\", \"c\"), assign=\"left\"),\n            _write_call(\n                func,\n                _write_call(func, \"a\", \"b\"),\n                \"c\",\n                assign=\"right\",\n            ),\n        )\n    if commutative:\n        maker(\n            \"commutative\",\n            \"ab\",\n            _write_call(func, \"a\", \"b\", assign=\"left\"),\n            _write_call(func, \"b\", \"a\", assign=\"right\"),\n        )\n    if identity is not None:\n        # Guess that the identity element is the minimal example from our operands\n        # strategy.  This is correct often enough to be worthwhile, and close enough\n        # that it's a good starting point to edit much of the rest.\n        if identity is ...:\n            try:\n                identity = find(operands, lambda x: True, settings=_quietly_settings)\n            except Exception:\n                identity = \"identity element here\"  # type: ignore\n        # If the repr of this element is invalid Python, stringify it - this\n        # can't be executed as-is, but at least makes it clear what should\n        # happen.  E.g. type(None) -> <class 'NoneType'> -> quoted.\n        try:\n            # We don't actually execute this code object; we're just compiling\n            # to check that the repr is syntactically valid.  HOWEVER, we're\n            # going to output that code string into test code which will be\n            # executed; so you still shouldn't ghostwrite for hostile code.\n            compile(repr(identity), \"<string>\", \"exec\")\n        except SyntaxError:\n            identity = repr(identity)  # type: ignore\n        identity_parts = [\n            f\"{identity = }\",\n            _assert_eq(\n                style,\n                \"a\",\n                _write_call(func, \"a\", \"identity\"),\n            ),\n            _assert_eq(\n                style,\n                \"a\",\n                _write_call(func, \"identity\", \"a\"),\n            ),\n        ]\n        maker(\"identity\", \"a\", \"\\n\".join(identity_parts))\n    if distributes_over:\n        do = distributes_over\n        dist_parts = [\n            _write_call(func, \"a\", _write_call(do, \"b\", \"c\"), assign=\"left\"),\n            _write_call(\n                do,\n                _write_call(func, \"a\", \"b\"),\n                _write_call(func, \"a\", \"c\"),\n                assign=\"ldist\",\n            ),\n            _assert_eq(style, \"ldist\", \"left\"),\n            \"\\n\",\n            _write_call(func, _write_call(do, \"a\", \"b\"), \"c\", assign=\"right\"),\n            _write_call(\n                do,\n                _write_call(func, \"a\", \"c\"),\n                _write_call(func, \"b\", \"c\"),\n                assign=\"rdist\",\n            ),\n            _assert_eq(style, \"rdist\", \"right\"),\n        ]\n        maker(do.__name__ + \"_distributes_over\", \"abc\", \"\\n\".join(dist_parts))\n\n    operands_imports, operands_repr = _valid_syntax_repr(operands)\n    all_imports.update(operands_imports)\n    operands_repr = _st_strategy_names(operands_repr)\n    classdef = \"\"\n    if style == \"unittest\":\n        classdef = f\"class TestBinaryOperation{func.__name__}(unittest.TestCase):\\n    \"\n    return (\n        all_imports,\n        classdef + f\"{operands_name} = {operands_repr}\\n\" + \"\\n\".join(parts),\n    )\n\n\ndef ufunc(\n    func: Callable,\n    *,\n    except_: Except = (),\n    style: str = \"pytest\",\n    annotate: bool | None = None,\n) -> str:\n    \"\"\"Write a property-based test for the :doc:`array ufunc <numpy:reference/ufuncs>` ``func``.\n\n    The resulting test checks that your ufunc or :doc:`gufunc\n    <numpy:reference/c-api/generalized-ufuncs>` has the expected broadcasting and dtype casting\n    behaviour.  You will probably want to add extra assertions, but as with the other\n    ghostwriters this gives you a great place to start.\n\n    .. code-block:: shell\n\n        hypothesis write numpy.matmul\n    \"\"\"\n    if not _is_probably_ufunc(func):\n        raise InvalidArgument(f\"{func=} does not seem to be a ufunc\")\n    except_ = _check_except(except_)\n    _check_style(style)\n\n    if annotate is None:\n        annotate = _are_annotations_used(func)\n\n    return _make_test(\n        *_make_ufunc_body(func, except_=except_, style=style, annotate=annotate)\n    )\n\n\ndef _make_ufunc_body(func, *, except_, style, annotate):\n    import hypothesis.extra.numpy as npst\n\n    if func.signature is None:\n        shapes = npst.mutually_broadcastable_shapes(num_shapes=func.nin)\n    else:\n        shapes = npst.mutually_broadcastable_shapes(signature=func.signature)\n    shapes.function.__module__ = npst.__name__\n\n    body = \"\"\"\n    input_shapes, expected_shape = shapes\n    input_dtypes, expected_dtype = types.split(\"->\")\n    array_strats = [\n        arrays(dtype=dtp, shape=shp, elements={{\"allow_nan\": True}})\n        for dtp, shp in zip(input_dtypes, input_shapes)\n    ]\n\n    {array_names} = data.draw(st.tuples(*array_strats))\n    result = {call}\n    \"\"\".format(\n        array_names=\", \".join(ascii_lowercase[: func.nin]),\n        call=_write_call(func, *ascii_lowercase[: func.nin], except_=except_),\n    )\n    assertions = \"\\n{shape_assert}\\n{type_assert}\".format(\n        shape_assert=_assert_eq(style, \"result.shape\", \"expected_shape\"),\n        type_assert=_assert_eq(style, \"result.dtype.char\", \"expected_dtype\"),\n    )\n\n    qname = _get_qualname(func, include_module=True)\n    obj_sigs = [\"O\" in sig for sig in func.types]\n    if all(obj_sigs) or not any(obj_sigs):\n        types = f\"sampled_from({qname}.types)\"\n    else:\n        types = f\"sampled_from([sig for sig in {qname}.types if 'O' not in sig])\"\n\n    return _make_test_body(\n        func,\n        test_body=dedent(body).strip(),\n        except_=except_,\n        assertions=assertions,\n        ghost=\"ufunc\" if func.signature is None else \"gufunc\",\n        style=style,\n        given_strategies={\"data\": st.data(), \"shapes\": shapes, \"types\": types},\n        imports={(\"hypothesis.extra.numpy\", \"arrays\")},\n        annotate=annotate,\n    )\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/lark.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\nThis extra can be used to generate strings matching any context-free grammar,\nusing the `Lark parser library <https://github.com/lark-parser/lark>`_.\n\nIt currently only supports Lark's native EBNF syntax, but we plan to extend\nthis to support other common syntaxes such as ANTLR and :rfc:`5234` ABNF.\nLark already `supports loading grammars\n<https://lark-parser.readthedocs.io/en/stable/tools.html#importing-grammars-from-nearley-js>`_\nfrom `nearley.js <https://nearley.js.org/>`_, so you may not have to write\nyour own at all.\n\"\"\"\n\nfrom inspect import signature\n\nimport lark\nfrom lark.grammar import NonTerminal, Rule, Symbol, Terminal\nfrom lark.lark import Lark\nfrom lark.lexer import TerminalDef\n\nfrom hypothesis import strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.conjecture.utils import calc_label_from_name\nfrom hypothesis.internal.validation import check_type\nfrom hypothesis.strategies._internal.regex import IncompatibleWithAlphabet\nfrom hypothesis.strategies._internal.utils import cacheable, defines_strategy\n\n__all__ = [\"from_lark\"]\n\n\ndef get_terminal_names(\n    terminals: list[TerminalDef], rules: list[Rule], ignore_names: list[str]\n) -> set[str]:\n    \"\"\"Get names of all terminals in the grammar.\n\n    The arguments are the results of calling ``Lark.grammar.compile()``,\n    so you would think that the ``terminals`` and ``ignore_names`` would\n    have it all... but they omit terminals created with ``@declare``,\n    which appear only in the expansion(s) of nonterminals.\n    \"\"\"\n    names = {t.name for t in terminals} | set(ignore_names)\n    for rule in rules:\n        names |= {t.name for t in rule.expansion if isinstance(t, Terminal)}\n    return names\n\n\nclass LarkStrategy(st.SearchStrategy):\n    \"\"\"Low-level strategy implementation wrapping a Lark grammar.\n\n    See ``from_lark`` for details.\n    \"\"\"\n\n    def __init__(\n        self,\n        grammar: Lark,\n        start: str | None,\n        explicit: dict[str, st.SearchStrategy[str]],\n        alphabet: st.SearchStrategy[str],\n    ) -> None:\n        super().__init__()\n        assert isinstance(grammar, lark.lark.Lark)\n        start: list[str] = grammar.options.start if start is None else [start]\n\n        # This is a total hack, but working around the changes is a nicer user\n        # experience than breaking for anyone who doesn't instantly update their\n        # installation of Lark alongside Hypothesis.\n        compile_args = signature(grammar.grammar.compile).parameters\n        if \"terminals_to_keep\" in compile_args:\n            terminals, rules, ignore_names = grammar.grammar.compile(start, ())\n        elif \"start\" in compile_args:  # pragma: no cover\n            # Support lark <= 0.10.0, without the terminals_to_keep argument.\n            terminals, rules, ignore_names = grammar.grammar.compile(start)  # type: ignore\n        else:  # pragma: no cover\n            # This branch is to support lark <= 0.7.1, without the start argument.\n            terminals, rules, ignore_names = grammar.grammar.compile()  # type: ignore\n\n        self.names_to_symbols: dict[str, Symbol] = {}\n\n        for r in rules:\n            self.names_to_symbols[r.origin.name] = r.origin\n\n        disallowed = set()\n        self.terminal_strategies: dict[str, st.SearchStrategy[str]] = {}\n        for t in terminals:\n            self.names_to_symbols[t.name] = Terminal(t.name)\n            s = st.from_regex(t.pattern.to_regexp(), fullmatch=True, alphabet=alphabet)\n            try:\n                s.validate()\n            except IncompatibleWithAlphabet:\n                disallowed.add(t.name)\n            else:\n                self.terminal_strategies[t.name] = s\n\n        self.ignored_symbols = tuple(self.names_to_symbols[n] for n in ignore_names)\n\n        all_terminals = get_terminal_names(terminals, rules, ignore_names)\n        if unknown_explicit := sorted(set(explicit) - all_terminals):\n            raise InvalidArgument(\n                \"The following arguments were passed as explicit_strategies, but \"\n                f\"there is no {unknown_explicit} terminal production in this grammar.\"\n            )\n        if missing_declared := sorted(\n            all_terminals - {t.name for t in terminals} - set(explicit)\n        ):\n            raise InvalidArgument(\n                f\"Undefined terminal{'s' * (len(missing_declared) > 1)} \"\n                f\"{sorted(missing_declared)!r}. Generation does not currently \"\n                \"support use of %declare unless you pass `explicit`, a dict of \"\n                f\"names-to-strategies, such as `{{{missing_declared[0]!r}: \"\n                'st.just(\"\")}}`'\n            )\n        self.terminal_strategies.update(explicit)\n\n        # can in fact contain any symbol, despite its name.\n        nonterminals: dict[str, list[tuple[Symbol, ...]]] = {}\n\n        for rule in rules:\n            if disallowed.isdisjoint(r.name for r in rule.expansion):\n                nonterminals.setdefault(rule.origin.name, []).append(\n                    tuple(rule.expansion)\n                )\n\n        allowed_rules = {*self.terminal_strategies, *nonterminals}\n        while dict(nonterminals) != (\n            nonterminals := {\n                k: clean\n                for k, v in nonterminals.items()\n                if (clean := [x for x in v if all(r.name in allowed_rules for r in x)])\n            }\n        ):\n            allowed_rules = {*self.terminal_strategies, *nonterminals}\n\n        if set(start).isdisjoint(allowed_rules):\n            raise InvalidArgument(\n                f\"No start rule {tuple(start)} is allowed by {alphabet=}\"\n            )\n        self.start = st.sampled_from(\n            [self.names_to_symbols[s] for s in start if s in allowed_rules]\n        )\n\n        self.nonterminal_strategies = {\n            k: st.sampled_from(sorted(v, key=len)) for k, v in nonterminals.items()\n        }\n\n        self.__rule_labels: dict[str, int] = {}\n\n    def do_draw(self, data: ConjectureData) -> str:\n        state: list[str] = []\n        start = data.draw(self.start)\n        self.draw_symbol(data, start, state)\n        return \"\".join(state)\n\n    def rule_label(self, name: str) -> int:\n        try:\n            return self.__rule_labels[name]\n        except KeyError:\n            return self.__rule_labels.setdefault(\n                name, calc_label_from_name(f\"LARK:{name}\")\n            )\n\n    def draw_symbol(\n        self,\n        data: ConjectureData,\n        symbol: Symbol,\n        draw_state: list[str],\n    ) -> None:\n        if isinstance(symbol, Terminal):\n            strategy = self.terminal_strategies[symbol.name]\n            draw_state.append(data.draw(strategy))\n        else:\n            assert isinstance(symbol, NonTerminal)\n            data.start_span(self.rule_label(symbol.name))\n            expansion = data.draw(self.nonterminal_strategies[symbol.name])\n            for e in expansion:\n                self.draw_symbol(data, e, draw_state)\n                self.gen_ignore(data, draw_state)\n            data.stop_span()\n\n    def gen_ignore(self, data: ConjectureData, draw_state: list[str]) -> None:\n        if self.ignored_symbols and data.draw_boolean(1 / 4):\n            emit = data.draw(st.sampled_from(self.ignored_symbols))\n            self.draw_symbol(data, emit, draw_state)\n\n    def calc_has_reusable_values(self, recur):\n        return True\n\n\ndef check_explicit(name):\n    def inner(value):\n        check_type(str, value, \"value drawn from \" + name)\n        return value\n\n    return inner\n\n\n@cacheable\n@defines_strategy(force_reusable_values=True)\ndef from_lark(\n    grammar: lark.lark.Lark,\n    *,\n    start: str | None = None,\n    explicit: dict[str, st.SearchStrategy[str]] | None = None,\n    alphabet: st.SearchStrategy[str] = st.characters(codec=\"utf-8\"),\n) -> st.SearchStrategy[str]:\n    \"\"\"A strategy for strings accepted by the given context-free grammar.\n\n    ``grammar`` must be a ``Lark`` object, which wraps an EBNF specification.\n    The Lark EBNF grammar reference can be found\n    `here <https://lark-parser.readthedocs.io/en/latest/grammar.html>`_.\n\n    ``from_lark`` will automatically generate strings matching the\n    nonterminal ``start`` symbol in the grammar, which was supplied as an\n    argument to the Lark class.  To generate strings matching a different\n    symbol, including terminals, you can override this by passing the\n    ``start`` argument to ``from_lark``.  Note that Lark may remove unreachable\n    productions when the grammar is compiled, so you should probably pass the\n    same value for ``start`` to both.\n\n    Currently ``from_lark`` does not support grammars that need custom lexing.\n    Any lexers will be ignored, and any undefined terminals from the use of\n    ``%declare`` will result in generation errors.  To define strategies for\n    such terminals, pass a dictionary mapping their name to a corresponding\n    strategy as the ``explicit`` argument.\n\n    The :pypi:`hypothesmith` project includes a strategy for Python source,\n    based on a grammar and careful post-processing.\n    \"\"\"\n    check_type(lark.lark.Lark, grammar, \"grammar\")\n    if explicit is None:\n        explicit = {}\n    else:\n        check_type(dict, explicit, \"explicit\")\n        explicit = {\n            k: v.map(check_explicit(f\"explicit[{k!r}]={v!r}\"))\n            for k, v in explicit.items()\n        }\n    return LarkStrategy(grammar, start, explicit, alphabet)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/numpy.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport importlib\nimport math\nimport types\nfrom collections.abc import Mapping, Sequence\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    Literal,\n    TypeVar,\n    Union,\n    cast,\n    get_args,\n    get_origin,\n    overload,\n)\n\nimport numpy as np\n\nfrom hypothesis import strategies as st\nfrom hypothesis.errors import HypothesisException, InvalidArgument\nfrom hypothesis.extra._array_helpers import (\n    _BIE,\n    NDIM_MAX,\n    BasicIndex,\n    BasicIndexStrategy,\n    BroadcastableShapes,\n    Shape,\n    _BIENoEllipsis,\n    _BIENoEllipsisNoNewaxis,\n    _BIENoNewaxis,\n    array_shapes,\n    broadcastable_shapes,\n    check_argument,\n    check_valid_dims,\n    mutually_broadcastable_shapes as _mutually_broadcastable_shapes,\n    order_check,\n    valid_tuple_axes as _valid_tuple_axes,\n)\nfrom hypothesis.internal.conjecture import utils as cu\nfrom hypothesis.internal.coverage import check_function\nfrom hypothesis.internal.reflection import proxies\nfrom hypothesis.internal.validation import check_type\nfrom hypothesis.strategies._internal.lazy import unwrap_strategies\nfrom hypothesis.strategies._internal.numbers import Real\nfrom hypothesis.strategies._internal.strategies import (\n    Ex,\n    MappedStrategy,\n    T,\n    check_strategy,\n)\nfrom hypothesis.strategies._internal.utils import defines_strategy\nfrom hypothesis.utils.deprecation import note_deprecation\n\n\ndef _try_import(mod_name: str, attr_name: str) -> Any:\n    assert \".\" not in attr_name\n    try:\n        mod = importlib.import_module(mod_name)\n        return getattr(mod, attr_name, None)\n    except ImportError:\n        return None\n\n\nif TYPE_CHECKING:\n    from numpy.typing import DTypeLike, NDArray\nelse:\n    NDArray = _try_import(\"numpy.typing\", \"NDArray\")\n\nArrayLike = _try_import(\"numpy.typing\", \"ArrayLike\")\n_NestedSequence = _try_import(\"numpy._typing._nested_sequence\", \"_NestedSequence\")\n_SupportsArray = _try_import(\"numpy._typing._array_like\", \"_SupportsArray\")\n\n__all__ = [\n    \"BroadcastableShapes\",\n    \"array_dtypes\",\n    \"array_shapes\",\n    \"arrays\",\n    \"basic_indices\",\n    \"boolean_dtypes\",\n    \"broadcastable_shapes\",\n    \"byte_string_dtypes\",\n    \"complex_number_dtypes\",\n    \"datetime64_dtypes\",\n    \"floating_dtypes\",\n    \"from_dtype\",\n    \"integer_array_indices\",\n    \"integer_dtypes\",\n    \"mutually_broadcastable_shapes\",\n    \"nested_dtypes\",\n    \"scalar_dtypes\",\n    \"timedelta64_dtypes\",\n    \"unicode_string_dtypes\",\n    \"unsigned_integer_dtypes\",\n    \"valid_tuple_axes\",\n]\n\nTIME_RESOLUTIONS = (\"Y\", \"M\", \"D\", \"h\", \"m\", \"s\", \"ms\", \"us\", \"ns\", \"ps\", \"fs\", \"as\")\n\n# See https://github.com/HypothesisWorks/hypothesis/pull/3394 and linked discussion.\nNP_FIXED_UNICODE = tuple(int(x) for x in np.__version__.split(\".\")[:2]) >= (1, 19)\n\n\n@defines_strategy(force_reusable_values=True)\ndef from_dtype(\n    dtype: np.dtype,\n    *,\n    alphabet: st.SearchStrategy[str] | None = None,\n    min_size: int = 0,\n    max_size: int | None = None,\n    min_value: int | float | None = None,\n    max_value: int | float | None = None,\n    allow_nan: bool | None = None,\n    allow_infinity: bool | None = None,\n    allow_subnormal: bool | None = None,\n    exclude_min: bool | None = None,\n    exclude_max: bool | None = None,\n    min_magnitude: Real = 0,\n    max_magnitude: Real | None = None,\n) -> st.SearchStrategy[Any]:\n    \"\"\"Creates a strategy which can generate any value of the given dtype.\n\n    Compatible parameters are passed to the inferred strategy function while\n    inapplicable ones are ignored.\n    This allows you, for example, to customise the min and max values,\n    control the length or contents of strings, or exclude non-finite\n    numbers. This is particularly useful when kwargs are passed through from\n    :func:`arrays` which allow a variety of numeric dtypes, as it seamlessly\n    handles the ``width`` or representable bounds for you.\n    \"\"\"\n    check_type(np.dtype, dtype, \"dtype\")\n    kwargs = {k: v for k, v in locals().items() if k != \"dtype\" and v is not None}\n\n    # Compound datatypes, eg 'f4,f4,f4'\n    if dtype.names is not None and dtype.fields is not None:\n        # mapping np.void.type over a strategy is nonsense, so return now.\n        subs = [from_dtype(dtype.fields[name][0], **kwargs) for name in dtype.names]\n        return st.tuples(*subs)\n\n    # Subarray datatypes, eg '(2, 3)i4'\n    if dtype.subdtype is not None:\n        subtype, shape = dtype.subdtype\n        return arrays(subtype, shape, elements=kwargs)\n\n    def compat_kw(*args, **kw):\n        \"\"\"Update default args to the strategy with user-supplied keyword args.\"\"\"\n        assert {\"min_value\", \"max_value\", \"max_size\"}.issuperset(kw)\n        for key in set(kwargs).intersection(kw):\n            msg = f\"dtype {dtype!r} requires {key}={kwargs[key]!r} to be %s {kw[key]!r}\"\n            if kw[key] is not None:\n                if key.startswith(\"min_\") and kw[key] > kwargs[key]:\n                    raise InvalidArgument(msg % (\"at least\",))\n                elif key.startswith(\"max_\") and kw[key] < kwargs[key]:\n                    raise InvalidArgument(msg % (\"at most\",))\n        kw.update({k: v for k, v in kwargs.items() if k in args or k in kw})\n        return kw\n\n    # Scalar datatypes\n    if dtype.kind == \"b\":\n        result: st.SearchStrategy[Any] = st.booleans()\n    elif dtype.kind == \"f\":\n        result = st.floats(\n            width=cast(Literal[16, 32, 64], min(8 * dtype.itemsize, 64)),\n            **compat_kw(\n                \"min_value\",\n                \"max_value\",\n                \"allow_nan\",\n                \"allow_infinity\",\n                \"allow_subnormal\",\n                \"exclude_min\",\n                \"exclude_max\",\n            ),\n        )\n    elif dtype.kind == \"c\":\n        result = st.complex_numbers(\n            width=cast(\n                Literal[32, 64, 128], min(8 * dtype.itemsize, 128)\n            ),  # convert from bytes to bits\n            **compat_kw(\n                \"min_magnitude\",\n                \"max_magnitude\",\n                \"allow_nan\",\n                \"allow_infinity\",\n                \"allow_subnormal\",\n            ),\n        )\n    elif dtype.kind in (\"S\", \"a\"):\n        # Numpy strings are null-terminated; only allow round-trippable values.\n        # `itemsize == 0` means 'fixed length determined at array creation'\n        max_size = dtype.itemsize or None\n        result = st.binary(**compat_kw(\"min_size\", max_size=max_size)).filter(\n            lambda b: b[-1:] != b\"\\0\"\n        )\n    elif dtype.kind == \"u\":\n        kw = compat_kw(min_value=0, max_value=2 ** (8 * dtype.itemsize) - 1)\n        result = st.integers(**kw)\n    elif dtype.kind == \"i\":\n        overflow = 2 ** (8 * dtype.itemsize - 1)\n        result = st.integers(**compat_kw(min_value=-overflow, max_value=overflow - 1))\n    elif dtype.kind == \"U\":\n        # Encoded in UTF-32 (four bytes/codepoint) and null-terminated\n        max_size = (dtype.itemsize or 0) // 4 or None\n        if NP_FIXED_UNICODE and \"alphabet\" not in kwargs:\n            kwargs[\"alphabet\"] = st.characters()\n        result = st.text(**compat_kw(\"alphabet\", \"min_size\", max_size=max_size)).filter(\n            lambda b: b[-1:] != \"\\0\"\n        )\n    elif dtype.kind in (\"m\", \"M\"):\n        if \"[\" in dtype.str:\n            res = st.just(dtype.str.split(\"[\")[-1][:-1])\n        else:\n            # Note that this case isn't valid to pass to arrays(), but we support\n            # it here because we'd have to guard against equivalents in arrays()\n            # regardless and drawing scalars is a valid use-case.\n            res = st.sampled_from(TIME_RESOLUTIONS)\n        if allow_nan is not False:\n            elems = st.integers(-(2**63), 2**63 - 1) | st.just(\"NaT\")\n        else:  # NEP-7 defines the NaT value as integer -(2**63)\n            elems = st.integers(-(2**63) + 1, 2**63 - 1)\n        result = st.builds(dtype.type, elems, res)\n    elif dtype.kind == \"O\":\n        return st.from_type(object)\n    else:\n        raise InvalidArgument(f\"No strategy inference for {dtype}\")\n    return result.map(dtype.type)\n\n\nclass ArrayStrategy(st.SearchStrategy):\n    def __init__(self, element_strategy, shape, dtype, fill, unique):\n        super().__init__()\n        self.shape = tuple(shape)\n        self.fill = fill\n        self.array_size = int(np.prod(shape))\n        self.dtype = dtype\n        self.element_strategy = element_strategy\n        self.unique = unique\n        self._check_elements = dtype.kind not in (\"O\", \"V\")\n\n    def __repr__(self):\n        return (\n            f\"ArrayStrategy({self.element_strategy!r}, shape={self.shape}, \"\n            f\"dtype={self.dtype!r}, fill={self.fill!r}, unique={self.unique!r})\"\n        )\n\n    def set_element(self, val, result, idx, *, fill=False):\n        # `val` is either an arbitrary object (for dtype=\"O\"), or otherwise an\n        # instance of a numpy dtype. This means we can *usually* expect e.g.\n        # val.dtype to be present, but can only guarantee it if\n        # `self.dtype != \"O\"`.\n\n        try:\n            result[idx] = val\n        except TypeError as err:\n            raise InvalidArgument(\n                f\"Could not add element={val!r} of \"\n                f\"{getattr(val, 'dtype', type(val))} to array of \"\n                f\"{result.dtype!r} - possible mismatch of time units in dtypes?\"\n            ) from err\n\n        try:\n            elem_changed = self._check_elements and val != result[idx] and val == val\n        except Exception as err:  # pragma: no cover\n            # This branch only exists to help debug weird behaviour in Numpy,\n            # such as the string problems we had a while back.\n            raise HypothesisException(\n                f\"Internal error when checking element={val!r} of \"\n                f\"{getattr(val, 'dtype', type(val))!r} to array of \"\n                f\"{result.dtype!r}\"\n            ) from err\n\n        if elem_changed:\n            strategy = self.fill if fill else self.element_strategy\n            if self.dtype.kind == \"f\":  # pragma: no cover\n                # This logic doesn't trigger in our coverage tests under Numpy 1.24+,\n                # with built-in checks for overflow, but we keep it for good error\n                # messages and compatibility with older versions of Numpy.\n                try:\n                    is_subnormal = 0 < abs(val) < np.finfo(self.dtype).tiny\n                except Exception:\n                    # val may be a non-float that does not support the\n                    # operations __lt__ and __abs__\n                    is_subnormal = False\n                if is_subnormal:\n                    raise InvalidArgument(\n                        f\"Generated subnormal float {val} from strategy \"\n                        f\"{strategy} resulted in {result[idx]!r}, probably \"\n                        \"as a result of NumPy being built with flush-to-zero \"\n                        \"compiler options. Consider passing \"\n                        \"allow_subnormal=False.\"\n                    )\n            raise InvalidArgument(\n                f\"Generated array element {val!r} from {strategy!r} cannot be \"\n                f\"represented as dtype {self.dtype!r} - instead it becomes \"\n                f\"{result[idx]!r} (type {type(result[idx])!r}).  Consider using \"\n                \"a more precise strategy, for example passing the `width` argument \"\n                \"to `floats()`.\"\n            )\n\n    def do_draw(self, data):\n        if 0 in self.shape:\n            return np.zeros(dtype=self.dtype, shape=self.shape)\n\n        # Because Numpy allocates memory for strings at array creation, if we have\n        # an unsized string dtype we'll fill an object array and then cast it back.\n        unsized_string_dtype = (\n            self.dtype.kind in (\"S\", \"a\", \"U\") and self.dtype.itemsize == 0\n        )\n\n        # This could legitimately be a np.empty, but the performance gains for\n        # that would be so marginal that there's really not much point risking\n        # undefined behaviour shenanigans.\n        result = np.zeros(\n            shape=self.array_size, dtype=object if unsized_string_dtype else self.dtype\n        )\n\n        if self.fill.is_empty:\n            # We have no fill value (either because the user explicitly\n            # disabled it or because the default behaviour was used and our\n            # elements strategy does not produce reusable values), so we must\n            # generate a fully dense array with a freshly drawn value for each\n            # entry.\n            if self.unique:\n                elems = st.lists(\n                    self.element_strategy,\n                    min_size=self.array_size,\n                    max_size=self.array_size,\n                    unique=True,\n                )\n                for i, v in enumerate(data.draw(elems)):\n                    self.set_element(v, result, i)\n            else:\n                for i in range(len(result)):\n                    self.set_element(data.draw(self.element_strategy), result, i)\n        else:\n            # We draw numpy arrays as \"sparse with an offset\". We draw a\n            # collection of index assignments within the array and assign\n            # fresh values from our elements strategy to those indices. If at\n            # the end we have not assigned every element then we draw a single\n            # value from our fill strategy and use that to populate the\n            # remaining positions with that strategy.\n\n            elements = cu.many(\n                data,\n                min_size=0,\n                max_size=self.array_size,\n                # sqrt isn't chosen for any particularly principled reason. It\n                # just grows reasonably quickly but sublinearly, and for small\n                # arrays it represents a decent fraction of the array size.\n                average_size=min(\n                    0.9 * self.array_size,  # ensure small arrays sometimes use fill\n                    max(10, math.sqrt(self.array_size)),  # ...but *only* sometimes\n                ),\n            )\n\n            needs_fill = np.full(self.array_size, True)\n            seen = set()\n\n            while elements.more():\n                i = data.draw_integer(0, self.array_size - 1)\n                if not needs_fill[i]:\n                    elements.reject()\n                    continue\n                self.set_element(data.draw(self.element_strategy), result, i)\n                if self.unique:\n                    if result[i] in seen:\n                        elements.reject()\n                        continue\n                    seen.add(result[i])\n\n                needs_fill[i] = False\n            if needs_fill.any():\n                # We didn't fill all of the indices in the early loop, so we\n                # put a fill value into the rest.\n\n                # We have to do this hilarious little song and dance to work\n                # around numpy's special handling of iterable values. If the\n                # value here were e.g. a tuple then neither array creation\n                # nor putmask would do the right thing. But by creating an\n                # array of size one and then assigning the fill value as a\n                # single element, we both get an array with the right value in\n                # it and putmask will do the right thing by repeating the\n                # values of the array across the mask.\n                one_element = np.zeros(\n                    shape=1, dtype=object if unsized_string_dtype else self.dtype\n                )\n                self.set_element(data.draw(self.fill), one_element, 0, fill=True)\n                if unsized_string_dtype:\n                    one_element = one_element.astype(self.dtype)\n                fill_value = one_element[0]\n                if self.unique:\n                    try:\n                        is_nan = np.isnan(fill_value)\n                    except TypeError:\n                        is_nan = False\n\n                    if not is_nan:\n                        raise InvalidArgument(\n                            f\"Cannot fill unique array with non-NaN value {fill_value!r}\"\n                        )\n\n                np.putmask(result, needs_fill, one_element)\n\n        if unsized_string_dtype:\n            out = result.astype(self.dtype)\n            mismatch = out != result\n            if mismatch.any():\n                raise InvalidArgument(\n                    f\"Array elements {result[mismatch]!r} cannot be represented \"\n                    f\"as dtype {self.dtype!r} - instead they become \"\n                    f\"{out[mismatch]!r}.  Use a more precise strategy, e.g. without \"\n                    \"trailing null bytes, as this will be an error future versions.\"\n                )\n            result = out\n\n        result = result.reshape(self.shape).copy()\n\n        assert result.base is None\n\n        return result\n\n\ndef fill_for(elements, unique, fill, name=\"\"):\n    if fill is None:\n        if unique or not elements.has_reusable_values:\n            fill = st.nothing()\n        else:\n            fill = elements\n    else:\n        check_strategy(fill, f\"{name}.fill\" if name else \"fill\")\n    return fill\n\n\nD = TypeVar(\"D\", bound=\"DTypeLike\")\nG = TypeVar(\"G\", bound=\"np.generic\")\n\n\n@overload\ndef arrays(\n    dtype: Union[\"np.dtype[G]\", st.SearchStrategy[\"np.dtype[G]\"]],\n    shape: int | st.SearchStrategy[int] | Shape | st.SearchStrategy[Shape],\n    *,\n    elements: st.SearchStrategy[Any] | Mapping[str, Any] | None = None,\n    fill: st.SearchStrategy[Any] | None = None,\n    unique: bool = False,\n) -> \"st.SearchStrategy[NDArray[G]]\": ...\n\n\n@overload\ndef arrays(\n    dtype: D | st.SearchStrategy[D],\n    shape: int | st.SearchStrategy[int] | Shape | st.SearchStrategy[Shape],\n    *,\n    elements: st.SearchStrategy[Any] | Mapping[str, Any] | None = None,\n    fill: st.SearchStrategy[Any] | None = None,\n    unique: bool = False,\n) -> \"st.SearchStrategy[NDArray[Any]]\": ...\n\n\n@defines_strategy(force_reusable_values=True)\ndef arrays(\n    dtype: D | st.SearchStrategy[D],\n    shape: int | st.SearchStrategy[int] | Shape | st.SearchStrategy[Shape],\n    *,\n    elements: st.SearchStrategy[Any] | Mapping[str, Any] | None = None,\n    fill: st.SearchStrategy[Any] | None = None,\n    unique: bool = False,\n) -> \"st.SearchStrategy[NDArray[Any]]\":\n    r\"\"\"Returns a strategy for generating :class:`numpy:numpy.ndarray`\\ s.\n\n    * ``dtype`` may be any valid input to :class:`~numpy:numpy.dtype`\n      (this includes :class:`~numpy:numpy.dtype` objects), or a strategy that\n      generates such values.\n    * ``shape`` may be an integer >= 0, a tuple of such integers, or a\n      strategy that generates such values.\n    * ``elements`` is a strategy for generating values to put in the array.\n      If it is None a suitable value will be inferred based on the dtype,\n      which may give any legal value (including eg NaN for floats).\n      If a mapping, it will be passed as ``**kwargs`` to ``from_dtype()``\n    * ``fill`` is a strategy that may be used to generate a single background\n      value for the array. If None, a suitable default will be inferred\n      based on the other arguments. If set to\n      :func:`~hypothesis.strategies.nothing` then filling\n      behaviour will be disabled entirely and every element will be generated\n      independently.\n    * ``unique`` specifies if the elements of the array should all be\n      distinct from one another. Note that in this case multiple NaN values\n      may still be allowed. If fill is also set, the only valid values for\n      it to return are NaN values (anything for which :obj:`numpy:numpy.isnan`\n      returns True. So e.g. for complex numbers ``nan+1j`` is also a valid fill).\n      Note that if ``unique`` is set to ``True`` the generated values must be\n      hashable.\n\n    Arrays of specified ``dtype`` and ``shape`` are generated for example\n    like this:\n\n    .. code-block:: pycon\n\n      >>> import numpy as np\n      >>> arrays(np.int8, (2, 3)).example()\n      array([[-8,  6,  3],\n             [-6,  4,  6]], dtype=int8)\n      >>> arrays(np.float, 3, elements=st.floats(0, 1)).example()\n      array([ 0.88974794,  0.77387938,  0.1977879 ])\n\n    Array values are generated in two parts:\n\n    1. Some subset of the coordinates of the array are populated with a value\n       drawn from the elements strategy (or its inferred form).\n    2. If any coordinates were not assigned in the previous step, a single\n       value is drawn from the ``fill`` strategy and is assigned to all remaining\n       places.\n\n    You can set :func:`fill=nothing() <hypothesis.strategies.nothing>` to\n    disable this behaviour and draw a value for every element.\n\n    If ``fill=None``, then it will attempt to infer the correct behaviour\n    automatically. If ``unique`` is ``True``, no filling will occur by default.\n    Otherwise, if it looks safe to reuse the values of elements across\n    multiple coordinates (this will be the case for any inferred strategy, and\n    for most of the builtins, but is not the case for mutable values or\n    strategies built with flatmap, map, composite, etc) then it will use the\n    elements strategy as the fill, else it will default to having no fill.\n\n    Having a fill helps Hypothesis craft high quality examples, but its\n    main importance is when the array generated is large: Hypothesis is\n    primarily designed around testing small examples. If you have arrays with\n    hundreds or more elements, having a fill value is essential if you want\n    your tests to run in reasonable time.\n    \"\"\"\n    # Our dtype argument might be a union, e.g. `np.float64 | np.complex64`; we handle\n    # that by turning it into a strategy up-front.\n    if type(dtype) in (getattr(types, \"UnionType\", object()), Union):\n        dtype = st.one_of(*(from_dtype(np.dtype(d)) for d in dtype.__args__))  # type: ignore\n\n    # We support passing strategies as arguments for convenience, or at least\n    # for legacy reasons, but don't want to pay the perf cost of a composite\n    # strategy (i.e. repeated argument handling and validation) when it's not\n    # needed.  So we get the best of both worlds by recursing with flatmap,\n    # but only when it's actually needed.\n    if isinstance(dtype, st.SearchStrategy):\n        return dtype.flatmap(\n            lambda d: arrays(d, shape, elements=elements, fill=fill, unique=unique)\n        )\n    if isinstance(shape, st.SearchStrategy):\n        return shape.flatmap(\n            lambda s: arrays(dtype, s, elements=elements, fill=fill, unique=unique)\n        )\n    # From here on, we're only dealing with values and it's relatively simple.\n    dtype = np.dtype(dtype)  # type: ignore[arg-type]\n    assert isinstance(dtype, np.dtype)  # help mypy out a bit...\n    if elements is None or isinstance(elements, Mapping):\n        if dtype.kind in (\"m\", \"M\") and \"[\" not in dtype.str:\n            # For datetime and timedelta dtypes, we have a tricky situation -\n            # because they *may or may not* specify a unit as part of the dtype.\n            # If not, we flatmap over the various resolutions so that array\n            # elements have consistent units but units may vary between arrays.\n            return (\n                st.sampled_from(TIME_RESOLUTIONS)\n                .map((dtype.str + \"[{}]\").format)\n                .flatmap(lambda d: arrays(d, shape=shape, fill=fill, unique=unique))\n            )\n        elements = from_dtype(dtype, **(elements or {}))\n    check_strategy(elements, \"elements\")\n    # If there's a redundant cast to the requested dtype, remove it.  This unlocks\n    # optimizations such as fast unique sampled_from, and saves some time directly too.\n    unwrapped = unwrap_strategies(elements)\n    if isinstance(unwrapped, MappedStrategy) and unwrapped.pack == dtype.type:\n        elements = unwrapped.mapped_strategy\n        if getattr(unwrapped, \"force_has_reusable_values\", False):\n            elements.force_has_reusable_values = True  # type: ignore\n    if isinstance(shape, int):\n        shape = (shape,)\n    shape = tuple(shape)\n    check_argument(\n        all(isinstance(s, int) for s in shape),\n        \"Array shape must be integer in each dimension, provided shape was {}\",\n        shape,\n    )\n    fill = fill_for(elements=elements, unique=unique, fill=fill)\n    return ArrayStrategy(elements, shape, dtype, fill, unique)\n\n\n@defines_strategy()\ndef scalar_dtypes() -> st.SearchStrategy[np.dtype]:\n    \"\"\"Return a strategy that can return any non-flexible scalar dtype.\"\"\"\n    return st.one_of(\n        boolean_dtypes(),\n        integer_dtypes(),\n        unsigned_integer_dtypes(),\n        floating_dtypes(),\n        complex_number_dtypes(),\n        datetime64_dtypes(),\n        timedelta64_dtypes(),\n    )\n\n\ndef defines_dtype_strategy(strat: T) -> T:\n    @defines_strategy()\n    @proxies(strat)\n    def inner(*args, **kwargs):\n        return strat(*args, **kwargs).map(np.dtype)\n\n    return inner\n\n\n@defines_dtype_strategy\ndef boolean_dtypes() -> st.SearchStrategy[\"np.dtype[np.bool_]\"]:\n    \"\"\"Return a strategy for boolean dtypes.\"\"\"\n    return st.just(\"?\")  # type: ignore[arg-type]\n\n\ndef dtype_factory(kind, sizes, valid_sizes, endianness):\n    # Utility function, shared logic for most integer and string types\n    valid_endian = (\"?\", \"<\", \"=\", \">\")\n    check_argument(\n        endianness in valid_endian,\n        \"Unknown endianness: was {}, must be in {}\",\n        endianness,\n        valid_endian,\n    )\n    if valid_sizes is not None:\n        if isinstance(sizes, int):\n            sizes = (sizes,)\n        check_argument(sizes, \"Dtype must have at least one possible size.\")\n        check_argument(\n            all(s in valid_sizes for s in sizes),\n            \"Invalid sizes: was {} must be an item or sequence in {}\",\n            sizes,\n            valid_sizes,\n        )\n        if all(isinstance(s, int) for s in sizes):\n            sizes = sorted({s // 8 for s in sizes})\n    strat = st.sampled_from(sizes)\n    if \"{}\" not in kind:\n        kind += \"{}\"\n    if endianness == \"?\":\n        return strat.map((\"<\" + kind).format) | strat.map((\">\" + kind).format)\n    return strat.map((endianness + kind).format)\n\n\n@overload\ndef unsigned_integer_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[8],\n) -> st.SearchStrategy[\"np.dtype[np.uint8]\"]: ...\n\n\n@overload\ndef unsigned_integer_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[16],\n) -> st.SearchStrategy[\"np.dtype[np.uint16]\"]: ...\n\n\n@overload\ndef unsigned_integer_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[32],\n) -> st.SearchStrategy[\"np.dtype[np.uint32]\"]: ...\n\n\n@overload\ndef unsigned_integer_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[64],\n) -> st.SearchStrategy[\"np.dtype[np.uint64]\"]: ...\n\n\n@overload\ndef unsigned_integer_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Sequence[Literal[8, 16, 32, 64]] = (8, 16, 32, 64),\n) -> st.SearchStrategy[\"np.dtype[np.unsignedinteger[Any]]\"]: ...\n\n\n@defines_dtype_strategy\ndef unsigned_integer_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[8, 16, 32, 64] | Sequence[Literal[8, 16, 32, 64]] = (\n        8,\n        16,\n        32,\n        64,\n    ),\n) -> st.SearchStrategy[\"np.dtype[np.unsignedinteger[Any]]\"]:\n    \"\"\"Return a strategy for unsigned integer dtypes.\n\n    endianness may be ``<`` for little-endian, ``>`` for big-endian,\n    ``=`` for native byte order, or ``?`` to allow either byte order.\n    This argument only applies to dtypes of more than one byte.\n\n    sizes must be a collection of integer sizes in bits.  The default\n    (8, 16, 32, 64) covers the full range of sizes.\n    \"\"\"\n    return dtype_factory(\"u\", sizes, (8, 16, 32, 64), endianness)\n\n\n@overload\ndef integer_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[8],\n) -> st.SearchStrategy[\"np.dtype[np.int8]\"]: ...\n\n\n@overload\ndef integer_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[16],\n) -> st.SearchStrategy[\"np.dtype[np.int16]\"]: ...\n\n\n@overload\ndef integer_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[32],\n) -> st.SearchStrategy[\"np.dtype[np.int32]\"]: ...\n\n\n@overload\ndef integer_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[64],\n) -> st.SearchStrategy[\"np.dtype[np.int64]\"]: ...\n\n\n@overload\ndef integer_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Sequence[Literal[8, 16, 32, 64]] = (8, 16, 32, 64),\n) -> st.SearchStrategy[\"np.dtype[np.signedinteger[Any]]\"]: ...\n\n\n@defines_dtype_strategy\ndef integer_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[8, 16, 32, 64] | Sequence[Literal[8, 16, 32, 64]] = (\n        8,\n        16,\n        32,\n        64,\n    ),\n) -> st.SearchStrategy[\"np.dtype[np.signedinteger[Any]]\"]:\n    \"\"\"Return a strategy for signed integer dtypes.\n\n    endianness and sizes are treated as for\n    :func:`unsigned_integer_dtypes`.\n    \"\"\"\n    return dtype_factory(\"i\", sizes, (8, 16, 32, 64), endianness)\n\n\n@overload\ndef floating_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[16],\n) -> st.SearchStrategy[\"np.dtype[np.float16]\"]: ...\n\n\n@overload\ndef floating_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[32],\n) -> st.SearchStrategy[\"np.dtype[np.float32]\"]: ...\n\n\n@overload\ndef floating_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[64],\n) -> st.SearchStrategy[\"np.dtype[np.float64]\"]: ...\n\n\n@overload\ndef floating_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[128],\n) -> st.SearchStrategy[\"np.dtype[np.float128]\"]: ...\n\n\n@overload\ndef floating_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Sequence[Literal[16, 32, 64, 96, 128]] = (16, 32, 64),\n) -> st.SearchStrategy[\"np.dtype[np.floating[Any]]\"]: ...\n\n\n@defines_dtype_strategy\ndef floating_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[16, 32, 64, 96, 128] | Sequence[Literal[16, 32, 64, 96, 128]] = (\n        16,\n        32,\n        64,\n    ),\n) -> st.SearchStrategy[\"np.dtype[np.floating[Any]]\"]:\n    \"\"\"Return a strategy for floating-point dtypes.\n\n    sizes is the size in bits of floating-point number.  Some machines support\n    96- or 128-bit floats, but these are not generated by default.\n\n    Larger floats (96 and 128 bit real parts) are not supported on all\n    platforms and therefore disabled by default.  To generate these dtypes,\n    include these values in the sizes argument.\n    \"\"\"\n    return dtype_factory(\"f\", sizes, (16, 32, 64, 96, 128), endianness)\n\n\n@overload\ndef complex_number_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[64],\n) -> st.SearchStrategy[\"np.dtype[np.complex64]\"]: ...\n\n\n@overload\ndef complex_number_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[128],\n) -> st.SearchStrategy[\"np.dtype[np.complex128]\"]: ...\n\n\n@overload\ndef complex_number_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[256],\n) -> st.SearchStrategy[\"np.dtype[np.complex256]\"]: ...\n\n\n@overload\ndef complex_number_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Sequence[Literal[64, 128, 192, 256]] = (64, 128),\n) -> st.SearchStrategy[\"np.dtype[np.complexfloating[Any, Any]]\"]: ...\n\n\n@defines_dtype_strategy\ndef complex_number_dtypes(\n    *,\n    endianness: str = \"?\",\n    sizes: Literal[64, 128, 192, 256] | Sequence[Literal[64, 128, 192, 256]] = (\n        64,\n        128,\n    ),\n) -> st.SearchStrategy[\"np.dtype[np.complexfloating[Any, Any]]\"]:\n    \"\"\"Return a strategy for complex-number dtypes.\n\n    sizes is the total size in bits of a complex number, which consists\n    of two floats.  Complex halves (a 16-bit real part) are not supported\n    by numpy and will not be generated by this strategy.\n    \"\"\"\n    return dtype_factory(\"c\", sizes, (64, 128, 192, 256), endianness)\n\n\n@check_function\ndef validate_time_slice(max_period, min_period):\n    check_argument(\n        max_period in TIME_RESOLUTIONS,\n        \"max_period {} must be a valid resolution in {}\",\n        max_period,\n        TIME_RESOLUTIONS,\n    )\n    check_argument(\n        min_period in TIME_RESOLUTIONS,\n        \"min_period {} must be a valid resolution in {}\",\n        min_period,\n        TIME_RESOLUTIONS,\n    )\n    start = TIME_RESOLUTIONS.index(max_period)\n    end = TIME_RESOLUTIONS.index(min_period) + 1\n    check_argument(\n        start < end,\n        \"max_period {} must be earlier in sequence {} than min_period {}\",\n        max_period,\n        TIME_RESOLUTIONS,\n        min_period,\n    )\n    return TIME_RESOLUTIONS[start:end]\n\n\n@defines_dtype_strategy\ndef datetime64_dtypes(\n    *, max_period: str = \"Y\", min_period: str = \"ns\", endianness: str = \"?\"\n) -> st.SearchStrategy[\"np.dtype[np.datetime64]\"]:\n    \"\"\"Return a strategy for datetime64 dtypes, with various precisions from\n    year to attosecond.\"\"\"\n    return dtype_factory(\n        \"datetime64[{}]\",\n        validate_time_slice(max_period, min_period),\n        TIME_RESOLUTIONS,\n        endianness,\n    )\n\n\n@defines_dtype_strategy\ndef timedelta64_dtypes(\n    *, max_period: str = \"Y\", min_period: str = \"ns\", endianness: str = \"?\"\n) -> st.SearchStrategy[\"np.dtype[np.timedelta64]\"]:\n    \"\"\"Return a strategy for timedelta64 dtypes, with various precisions from\n    year to attosecond.\"\"\"\n    return dtype_factory(\n        \"timedelta64[{}]\",\n        validate_time_slice(max_period, min_period),\n        TIME_RESOLUTIONS,\n        endianness,\n    )\n\n\n@defines_dtype_strategy\ndef byte_string_dtypes(\n    *, endianness: str = \"?\", min_len: int = 1, max_len: int = 16\n) -> st.SearchStrategy[\"np.dtype[np.bytes_]\"]:\n    \"\"\"Return a strategy for generating bytestring dtypes, of various lengths\n    and byteorder.\n\n    While Hypothesis' string strategies can generate empty strings, string\n    dtypes with length 0 indicate that size is still to be determined, so\n    the minimum length for string dtypes is 1.\n    \"\"\"\n    order_check(\"len\", 1, min_len, max_len)\n    return dtype_factory(\"S\", list(range(min_len, max_len + 1)), None, endianness)\n\n\n@defines_dtype_strategy\ndef unicode_string_dtypes(\n    *, endianness: str = \"?\", min_len: int = 1, max_len: int = 16\n) -> st.SearchStrategy[\"np.dtype[np.str_]\"]:\n    \"\"\"Return a strategy for generating unicode string dtypes, of various\n    lengths and byteorder.\n\n    While Hypothesis' string strategies can generate empty strings, string\n    dtypes with length 0 indicate that size is still to be determined, so\n    the minimum length for string dtypes is 1.\n    \"\"\"\n    order_check(\"len\", 1, min_len, max_len)\n    return dtype_factory(\"U\", list(range(min_len, max_len + 1)), None, endianness)\n\n\ndef _no_title_is_name_of_a_titled_field(ls):\n    seen = set()\n    for title_and_name, *_ in ls:\n        if isinstance(title_and_name, tuple):\n            if seen.intersection(title_and_name):  # pragma: no cover\n                # Our per-element filters below make this as rare as possible,\n                # so it's not always covered.\n                return False\n            seen.update(title_and_name)\n    return True\n\n\n@defines_dtype_strategy\ndef array_dtypes(\n    subtype_strategy: st.SearchStrategy[np.dtype] = scalar_dtypes(),\n    *,\n    min_size: int = 1,\n    max_size: int = 5,\n    allow_subarrays: bool = False,\n) -> st.SearchStrategy[np.dtype]:\n    \"\"\"Return a strategy for generating array (compound) dtypes, with members\n    drawn from the given subtype strategy.\"\"\"\n    order_check(\"size\", 0, min_size, max_size)\n    # The empty string is replaced by f{idx}; see #1963 for details.  Much easier to\n    # insist that field names be unique and just boost f{idx} strings manually.\n    field_names = st.integers(0, 127).map(\"f{}\".format) | st.text(min_size=1)\n    name_titles = st.one_of(\n        field_names,\n        st.tuples(field_names, field_names).filter(lambda ns: ns[0] != ns[1]),\n    )\n    elements: st.SearchStrategy[tuple] = st.tuples(name_titles, subtype_strategy)\n    if allow_subarrays:\n        elements |= st.tuples(\n            name_titles, subtype_strategy, array_shapes(max_dims=2, max_side=2)\n        )\n    return st.lists(  # type: ignore[return-value]\n        elements=elements,\n        min_size=min_size,\n        max_size=max_size,\n        unique_by=(\n            # Deduplicate by both name and title for efficiency before filtering.\n            # (Field names must be unique, as must titles, and no intersections)\n            lambda d: d[0] if isinstance(d[0], str) else d[0][0],\n            lambda d: d[0] if isinstance(d[0], str) else d[0][1],\n        ),\n    ).filter(_no_title_is_name_of_a_titled_field)\n\n\n@defines_strategy()\ndef nested_dtypes(\n    subtype_strategy: st.SearchStrategy[np.dtype] = scalar_dtypes(),\n    *,\n    max_leaves: int = 10,\n    max_itemsize: int | None = None,\n) -> st.SearchStrategy[np.dtype]:\n    \"\"\"Return the most-general dtype strategy.\n\n    Elements drawn from this strategy may be simple (from the\n    subtype_strategy), or several such values drawn from\n    :func:`array_dtypes` with ``allow_subarrays=True``. Subdtypes in an\n    array dtype may be nested to any depth, subject to the max_leaves\n    argument.\n    \"\"\"\n    return st.recursive(\n        subtype_strategy,\n        lambda x: array_dtypes(x, allow_subarrays=True),\n        max_leaves=max_leaves,\n    ).filter(lambda d: max_itemsize is None or d.itemsize <= max_itemsize)\n\n\n@proxies(_valid_tuple_axes)\ndef valid_tuple_axes(*args, **kwargs):\n    return _valid_tuple_axes(*args, **kwargs)\n\n\nvalid_tuple_axes.__doc__ = f\"\"\"\n    Return a strategy for generating permissible tuple-values for the\n    ``axis`` argument for a numpy sequential function (e.g.\n    :func:`numpy:numpy.sum`), given an array of the specified\n    dimensionality.\n\n    {_valid_tuple_axes.__doc__}\n    \"\"\"\n\n\n@proxies(_mutually_broadcastable_shapes)\ndef mutually_broadcastable_shapes(*args, **kwargs):\n    return _mutually_broadcastable_shapes(*args, **kwargs)\n\n\nmutually_broadcastable_shapes.__doc__ = f\"\"\"\n    {_mutually_broadcastable_shapes.__doc__}\n\n    **Use with Generalised Universal Function signatures**\n\n    A :doc:`universal function <numpy:reference/ufuncs>` (or ufunc for short) is a function\n    that operates on ndarrays in an element-by-element fashion, supporting array\n    broadcasting, type casting, and several other standard features.\n    A :doc:`generalised ufunc <numpy:reference/c-api/generalized-ufuncs>` operates on\n    sub-arrays rather than elements, based on the \"signature\" of the function.\n    Compare e.g. :obj:`numpy.add() <numpy:numpy.add>` (ufunc) to\n    :obj:`numpy.matmul() <numpy:numpy.matmul>` (gufunc).\n\n    To generate shapes for a gufunc, you can pass the ``signature`` argument instead of\n    ``num_shapes``.  This must be a gufunc signature string; which you can write by\n    hand or access as e.g. ``np.matmul.signature`` on generalised ufuncs.\n\n    In this case, the ``side`` arguments are applied to the 'core dimensions' as well,\n    ignoring any frozen dimensions.  ``base_shape``  and the ``dims`` arguments are\n    applied to the 'loop dimensions', and if necessary, the dimensionality of each\n    shape is silently capped to respect the 32-dimension limit.\n\n    The generated ``result_shape`` is the real result shape of applying the gufunc\n    to arrays of the generated ``input_shapes``, even where this is different to\n    broadcasting the loop dimensions.\n\n    gufunc-compatible shapes shrink their loop dimensions as above, towards omitting\n    optional core dimensions, and smaller-size core dimensions.\n\n    .. code-block:: pycon\n\n        >>> # np.matmul.signature == \"(m?,n),(n,p?)->(m?,p?)\"\n        >>> for _ in range(3):\n        ...     mutually_broadcastable_shapes(signature=np.matmul.signature).example()\n        BroadcastableShapes(input_shapes=((2,), (2,)), result_shape=())\n        BroadcastableShapes(input_shapes=((3, 4, 2), (1, 2)), result_shape=(3, 4))\n        BroadcastableShapes(input_shapes=((4, 2), (1, 2, 3)), result_shape=(4, 3))\n\n    \"\"\"\n\n\n@overload\ndef basic_indices(\n    shape: Shape,\n    *,\n    min_dims: int = 0,\n    max_dims: int | None = None,\n    allow_newaxis: Literal[False] = ...,\n    allow_ellipsis: Literal[False],\n) -> st.SearchStrategy[\n    _BIENoEllipsisNoNewaxis | tuple[_BIENoEllipsisNoNewaxis, ...]\n]: ...\n\n\n@overload\ndef basic_indices(\n    shape: Shape,\n    *,\n    min_dims: int = 0,\n    max_dims: int | None = None,\n    allow_newaxis: Literal[False] = ...,\n    allow_ellipsis: Literal[True] = ...,\n) -> st.SearchStrategy[_BIENoNewaxis | tuple[_BIENoNewaxis, ...]]: ...\n\n\n@overload\ndef basic_indices(\n    shape: Shape,\n    *,\n    min_dims: int = 0,\n    max_dims: int | None = None,\n    allow_newaxis: Literal[True],\n    allow_ellipsis: Literal[False],\n) -> st.SearchStrategy[_BIENoEllipsis | tuple[_BIENoEllipsis, ...]]: ...\n\n\n@overload\ndef basic_indices(\n    shape: Shape,\n    *,\n    min_dims: int = 0,\n    max_dims: int | None = None,\n    allow_newaxis: Literal[True],\n    allow_ellipsis: Literal[True] = ...,\n) -> st.SearchStrategy[_BIE | tuple[_BIE, ...]]: ...\n\n\n@defines_strategy()\ndef basic_indices(\n    shape: Shape,\n    *,\n    min_dims: int = 0,\n    max_dims: int | None = None,\n    allow_newaxis: bool = False,\n    allow_ellipsis: bool = True,\n) -> st.SearchStrategy[BasicIndex]:\n    \"\"\"Return a strategy for :doc:`basic indexes <numpy:reference/routines.indexing>` of\n    arrays with the specified shape, which may include dimensions of size zero.\n\n    It generates tuples containing some mix of integers, :obj:`python:slice`\n    objects, ``...`` (an ``Ellipsis``), and ``None``. When a length-one tuple\n    would be generated, this strategy may instead return the element which will\n    index the first axis, e.g. ``5`` instead of ``(5,)``.\n\n    * ``shape`` is the shape of the array that will be indexed, as a tuple of\n      positive integers. This must be at least two-dimensional for a tuple to be\n      a valid index; for one-dimensional arrays use\n      :func:`~hypothesis.strategies.slices` instead.\n    * ``min_dims`` is the minimum dimensionality of the resulting array from use\n      of the generated index. When ``min_dims == 0``, scalars and zero-dimensional\n      arrays are both allowed.\n    * ``max_dims`` is the maximum dimensionality of the resulting array,\n      defaulting to ``len(shape) if not allow_newaxis else\n      max(len(shape), min_dims) + 2``.\n    * ``allow_newaxis`` specifies whether ``None`` is allowed in the index.\n    * ``allow_ellipsis`` specifies whether ``...`` is allowed in the index.\n    \"\"\"\n    # Arguments to exclude scalars, zero-dim arrays, and dims of size zero were\n    # all considered and rejected.  We want users to explicitly consider those\n    # cases if they're dealing in general indexers, and while it's fiddly we can\n    # back-compatibly add them later (hence using kwonlyargs).\n    check_type(tuple, shape, \"shape\")\n    check_argument(\n        all(isinstance(x, int) and x >= 0 for x in shape),\n        f\"{shape=}, but all dimensions must be non-negative integers.\",\n    )\n    check_type(bool, allow_ellipsis, \"allow_ellipsis\")\n    check_type(bool, allow_newaxis, \"allow_newaxis\")\n    check_type(int, min_dims, \"min_dims\")\n    if min_dims > len(shape) and not allow_newaxis:\n        note_deprecation(\n            f\"min_dims={min_dims} is larger than len(shape)={len(shape)}, \"\n            \"but allow_newaxis=False makes it impossible for an indexing \"\n            \"operation to add dimensions.\",\n            since=\"2021-09-15\",\n            has_codemod=False,\n        )\n    check_valid_dims(min_dims, \"min_dims\")\n\n    if max_dims is None:\n        if allow_newaxis:\n            max_dims = min(max(len(shape), min_dims) + 2, NDIM_MAX)\n        else:\n            max_dims = min(len(shape), NDIM_MAX)\n    else:\n        check_type(int, max_dims, \"max_dims\")\n        if max_dims > len(shape) and not allow_newaxis:\n            note_deprecation(\n                f\"max_dims={max_dims} is larger than len(shape)={len(shape)}, \"\n                \"but allow_newaxis=False makes it impossible for an indexing \"\n                \"operation to add dimensions.\",\n                since=\"2021-09-15\",\n                has_codemod=False,\n            )\n    check_valid_dims(max_dims, \"max_dims\")\n\n    order_check(\"dims\", 0, min_dims, max_dims)\n\n    return BasicIndexStrategy(\n        shape,\n        min_dims=min_dims,\n        max_dims=max_dims,\n        allow_ellipsis=allow_ellipsis,\n        allow_newaxis=allow_newaxis,\n        allow_fewer_indices_than_dims=True,\n    )\n\n\nI = TypeVar(\"I\", bound=np.integer)\n\n\n@overload\ndef integer_array_indices(\n    shape: Shape,\n    *,\n    result_shape: st.SearchStrategy[Shape] = array_shapes(),\n) -> \"st.SearchStrategy[tuple[NDArray[np.signedinteger[Any]], ...]]\": ...\n\n\n@overload\ndef integer_array_indices(\n    shape: Shape,\n    *,\n    result_shape: st.SearchStrategy[Shape] = array_shapes(),\n    dtype: \"np.dtype[I]\",\n) -> \"st.SearchStrategy[tuple[NDArray[I], ...]]\": ...\n\n\n@defines_strategy()\ndef integer_array_indices(\n    shape: Shape,\n    *,\n    result_shape: st.SearchStrategy[Shape] = array_shapes(),\n    dtype: \"np.dtype[I] | np.dtype[np.signedinteger[Any] | np.bool[bool]]\" = np.dtype(\n        int\n    ),\n) -> \"st.SearchStrategy[tuple[NDArray[I], ...]]\":\n    \"\"\"Return a search strategy for tuples of integer-arrays that, when used\n    to index into an array of shape ``shape``, given an array whose shape\n    was drawn from ``result_shape``.\n\n    Examples from this strategy shrink towards the tuple of index-arrays::\n\n        len(shape) * (np.zeros(drawn_result_shape, dtype), )\n\n    * ``shape`` a tuple of integers that indicates the shape of the array,\n      whose indices are being generated.\n    * ``result_shape`` a strategy for generating tuples of integers, which\n      describe the shape of the resulting index arrays. The default is\n      :func:`~hypothesis.extra.numpy.array_shapes`.  The shape drawn from\n      this strategy determines the shape of the array that will be produced\n      when the corresponding example from ``integer_array_indices`` is used\n      as an index.\n    * ``dtype`` the integer data type of the generated index-arrays. Negative\n      integer indices can be generated if a signed integer type is specified.\n\n    Recall that an array can be indexed using a tuple of integer-arrays to\n    access its members in an arbitrary order, producing an array with an\n    arbitrary shape. For example:\n\n    .. code-block:: pycon\n\n        >>> from numpy import array\n        >>> x = array([-0, -1, -2, -3, -4])\n        >>> ind = (array([[4, 0], [0, 1]]),)  # a tuple containing a 2D integer-array\n        >>> x[ind]  # the resulting array is commensurate with the indexing array(s)\n        array([[-4,  0],\n               [0, -1]])\n\n    Note that this strategy does not accommodate all variations of so-called\n    'advanced indexing', as prescribed by NumPy's nomenclature.  Combinations\n    of basic and advanced indexes are too complex to usefully define in a\n    standard strategy; we leave application-specific strategies to the user.\n    Advanced-boolean indexing can be defined as ``arrays(shape=..., dtype=bool)``,\n    and is similarly left to the user.\n    \"\"\"\n    check_type(tuple, shape, \"shape\")\n    check_argument(\n        shape and all(isinstance(x, int) and x > 0 for x in shape),\n        f\"{shape=} must be a non-empty tuple of integers > 0\",\n    )\n    check_strategy(result_shape, \"result_shape\")\n    check_argument(\n        np.issubdtype(dtype, np.integer), f\"{dtype=} must be an integer dtype\"\n    )\n    signed = np.issubdtype(dtype, np.signedinteger)\n\n    def array_for(index_shape, size):\n        return arrays(\n            dtype=dtype,\n            shape=index_shape,\n            elements=st.integers(-size if signed else 0, size - 1),\n        )\n\n    return result_shape.flatmap(\n        lambda index_shape: st.tuples(*(array_for(index_shape, size) for size in shape))\n    )\n\n\ndef _unpack_dtype(dtype):\n    dtype_args = getattr(dtype, \"__args__\", ())\n    if dtype_args and type(dtype) not in (getattr(types, \"UnionType\", object()), Union):\n        assert len(dtype_args) == 1\n        if isinstance(dtype_args[0], TypeVar):\n            # numpy.dtype[+ScalarType]\n            assert dtype_args[0].__bound__ == np.generic\n            dtype = Any\n        else:\n            # plain dtype\n            dtype = dtype_args[0]\n    return dtype\n\n\ndef _dtype_from_args(args):\n    if len(args) <= 1:\n        # Zero args: ndarray, _SupportsArray\n        # One arg: ndarray[type], _SupportsArray[type]\n        dtype = _unpack_dtype(args[0]) if args else Any\n    else:\n        # Two args: ndarray[shape, type], NDArray[*]\n        assert len(args) == 2\n        dtype = _unpack_dtype(args[1])\n\n    if dtype is Any:\n        return scalar_dtypes()\n    elif type(dtype) in (getattr(types, \"UnionType\", object()), Union):\n        return dtype\n    return np.dtype(dtype)\n\n\ndef _from_type(thing: type[Ex]) -> st.SearchStrategy[Ex] | None:\n    \"\"\"Called by st.from_type to try to infer a strategy for thing using numpy.\n\n    If we can infer a numpy-specific strategy for thing, we return that; otherwise,\n    we return None.\n    \"\"\"\n\n    base_strats = st.one_of(\n        [\n            st.booleans(),\n            st.integers(),\n            st.floats(),\n            st.complex_numbers(),\n            st.text(),\n            st.binary(),\n        ]\n    )\n    # don't mix strings and non-ascii bytestrings (ex: ['', b'\\x80']). See\n    # https://github.com/numpy/numpy/issues/23899.\n    base_strats_ascii = st.one_of(\n        [\n            st.booleans(),\n            st.integers(),\n            st.floats(),\n            st.complex_numbers(),\n            st.text(),\n            st.binary().filter(bytes.isascii),\n        ]\n    )\n\n    if thing == np.dtype:\n        # Note: Parameterized dtypes and DTypeLike are not supported.\n        return st.one_of(\n            scalar_dtypes(),\n            byte_string_dtypes(),\n            unicode_string_dtypes(),\n            array_dtypes(),\n            nested_dtypes(),\n        )\n\n    if thing == ArrayLike:\n        # We override the default type resolution to ensure the \"coercible to\n        # array\" contract is honoured. See\n        # https://github.com/HypothesisWorks/hypothesis/pull/3670#issuecomment-1578140422.\n        # The actual type is (as of np 1.24), with\n        # scalars:=[bool, int, float, complex, str, bytes]:\n        # Union[\n        #     _SupportsArray,\n        #     _NestedSequence[_SupportsArray],\n        #     *scalars,\n        #     _NestedSequence[Union[*scalars]]\n        # ]\n        return st.one_of(\n            # *scalars\n            base_strats,\n            # The two recursive strategies below cover the following cases:\n            # - _SupportsArray (using plain ndarrays)\n            # - _NestedSequence[Union[*scalars]] (but excluding non-ascii binary)\n            # - _NestedSequence[_SupportsArray] (but with a single leaf element\n            # .  to avoid the issue of unequally sized leaves)\n            st.recursive(st.lists(base_strats_ascii), extend=st.tuples),\n            st.recursive(st.from_type(np.ndarray), extend=st.tuples),\n        )\n\n    if isinstance(thing, type) and issubclass(thing, np.generic):\n        dtype = np.dtype(thing)\n        return from_dtype(dtype) if dtype.kind not in \"OV\" else None\n\n    origin = get_origin(thing)\n    # if origin is not generic-like, get_origin returns None. Fall back to thing.\n    if origin is None:\n        origin = thing\n    args = get_args(thing)\n\n    if origin == _NestedSequence:\n        # We have to override the default resolution to ensure sequences are of\n        # equal length. Actually they are still not, if the arg specialization\n        # returns arbitrary-shaped sequences or arrays - hence the even more special\n        # resolution of ArrayLike, above.\n        assert len(args) <= 1\n        base_strat = st.from_type(args[0]) if args else base_strats\n        return st.one_of(\n            st.lists(base_strat),\n            st.recursive(st.tuples(), st.tuples),\n            st.recursive(st.tuples(base_strat), st.tuples),\n            st.recursive(st.tuples(base_strat, base_strat), st.tuples),\n        )\n\n    # note: get_origin(np.typing.NDArray[np.int64]) is np.ndarray in numpy < 2.5.0,\n    # but is np.typing.NDArray in numpy >= 2.5.0. Support both here.\n    if origin in [np.typing.NDArray, np.ndarray, _SupportsArray]:\n        dtype = _dtype_from_args(args)\n        return arrays(dtype, array_shapes(max_dims=2))  # type: ignore[return-value]\n\n    # We didn't find a type to resolve, continue\n    return None\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/pandas/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.extra.pandas.impl import (\n    column,\n    columns,\n    data_frames,\n    indexes,\n    range_indexes,\n    series,\n)\n\n__all__ = [\"column\", \"columns\", \"data_frames\", \"indexes\", \"range_indexes\", \"series\"]\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/pandas/impl.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections import OrderedDict, abc\nfrom collections.abc import Sequence\nfrom copy import copy\nfrom dataclasses import dataclass\nfrom datetime import datetime, timedelta\nfrom typing import Any, Generic, Union\n\nimport numpy as np\nimport pandas\n\nfrom hypothesis import strategies as st\nfrom hypothesis.control import reject\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra import numpy as npst\nfrom hypothesis.internal.conjecture import utils as cu\nfrom hypothesis.internal.coverage import check, check_function\nfrom hypothesis.internal.validation import (\n    check_type,\n    check_valid_interval,\n    check_valid_size,\n    try_convert,\n)\nfrom hypothesis.strategies._internal.strategies import Ex, check_strategy\nfrom hypothesis.strategies._internal.utils import cacheable, defines_strategy\nfrom hypothesis.utils.deprecation import note_deprecation\n\ntry:\n    from pandas.core.arrays.integer import IntegerDtype\nexcept ImportError:\n    IntegerDtype = ()\n\n\ndef dtype_for_elements_strategy(s):\n    return st.shared(\n        s.map(lambda x: pandas.Series([x]).dtype),\n        key=(\"hypothesis.extra.pandas.dtype_for_elements_strategy\", s),\n    )\n\n\ndef infer_dtype_if_necessary(dtype, values, elements, draw):\n    if dtype is None and not values:\n        return draw(dtype_for_elements_strategy(elements))\n    return dtype\n\n\n@check_function\ndef elements_and_dtype(elements, dtype, source=None):\n    if source is None:\n        prefix = \"\"\n    else:\n        prefix = f\"{source}.\"\n\n    if elements is not None:\n        check_strategy(elements, f\"{prefix}elements\")\n    else:\n        with check(\"dtype is not None\"):\n            if dtype is None:\n                raise InvalidArgument(\n                    f\"At least one of {prefix}elements or {prefix}dtype must be provided.\"\n                )\n\n    with check(\"isinstance(dtype, CategoricalDtype)\"):\n        if pandas.api.types.CategoricalDtype.is_dtype(dtype):\n            raise InvalidArgument(\n                f\"{prefix}dtype is categorical, which is currently unsupported\"\n            )\n\n    if isinstance(dtype, type) and issubclass(dtype, IntegerDtype):\n        raise InvalidArgument(\n            f\"Passed {dtype=} is a dtype class, please pass in an instance of this class.\"\n            \"Otherwise it would be treated as dtype=object\"\n        )\n\n    if isinstance(dtype, type) and np.dtype(dtype).kind == \"O\" and dtype is not object:\n        err_msg = f\"Passed {dtype=} is not a valid Pandas dtype.\"\n        if issubclass(dtype, datetime):\n            err_msg += ' To generate valid datetimes, pass `dtype=\"datetime64[ns]\"`'\n            raise InvalidArgument(err_msg)\n        elif issubclass(dtype, timedelta):\n            err_msg += ' To generate valid timedeltas, pass `dtype=\"timedelta64[ns]\"`'\n            raise InvalidArgument(err_msg)\n        note_deprecation(\n            f\"{err_msg}  We'll treat it as \"\n            \"dtype=object for now, but this will be an error in a future version.\",\n            since=\"2021-12-31\",\n            has_codemod=False,\n            stacklevel=1,\n        )\n\n    if isinstance(dtype, st.SearchStrategy):\n        raise InvalidArgument(\n            f\"Passed {dtype=} is a strategy, but we require a concrete dtype \"\n            \"here.  See https://stackoverflow.com/q/74355937 for workaround patterns.\"\n        )\n\n    _get_subclasses = getattr(IntegerDtype, \"__subclasses__\", list)\n    dtype = {t.name: t() for t in _get_subclasses()}.get(dtype, dtype)\n\n    is_na_dtype = False\n    if isinstance(dtype, IntegerDtype):\n        is_na_dtype = True\n        dtype = np.dtype(dtype.name.lower())\n    elif dtype is not None:\n        dtype = try_convert(np.dtype, dtype, \"dtype\")\n\n    if elements is None:\n        elements = npst.from_dtype(dtype)\n        if is_na_dtype:\n            elements = st.none() | elements\n    # as an optimization, avoid converting object dtypes, which will always\n    # remain unchanged.\n    elif dtype is not None and dtype.kind != \"O\":\n\n        def convert_element(value):\n            if is_na_dtype and value is None:\n                return None\n\n            try:\n                return np.array([value], dtype=dtype)[0]\n            except (TypeError, ValueError, OverflowError):\n                name = f\"draw({prefix}elements)\"\n                raise InvalidArgument(\n                    f\"Cannot convert {name}={value!r} of type \"\n                    f\"{type(value).__name__} to dtype {dtype.str}\"\n                ) from None\n\n        elements = elements.map(convert_element)\n    assert elements is not None\n\n    return elements, dtype\n\n\nclass ValueIndexStrategy(st.SearchStrategy):\n    def __init__(self, elements, dtype, min_size, max_size, unique, name):\n        super().__init__()\n        self.elements = elements\n        self.dtype = dtype\n        self.min_size = min_size\n        self.max_size = max_size\n        self.unique = unique\n        self.name = name\n\n    def do_draw(self, data):\n        result = []\n        seen = set()\n\n        iterator = cu.many(\n            data,\n            min_size=self.min_size,\n            max_size=self.max_size,\n            average_size=(self.min_size + self.max_size) / 2,\n        )\n\n        while iterator.more():\n            elt = data.draw(self.elements)\n\n            if self.unique:\n                if elt in seen:\n                    iterator.reject()\n                    continue\n                seen.add(elt)\n            result.append(elt)\n\n        dtype = infer_dtype_if_necessary(\n            dtype=self.dtype, values=result, elements=self.elements, draw=data.draw\n        )\n        return pandas.Index(\n            result, dtype=dtype, tupleize_cols=False, name=data.draw(self.name)\n        )\n\n\nDEFAULT_MAX_SIZE = 10\n\n\n@cacheable\n@defines_strategy()\ndef range_indexes(\n    min_size: int = 0,\n    max_size: int | None = None,\n    name: st.SearchStrategy[str | None] = st.none(),\n) -> st.SearchStrategy[pandas.RangeIndex]:\n    \"\"\"Provides a strategy which generates an :class:`~pandas.Index` whose\n    values are 0, 1, ..., n for some n.\n\n    Arguments:\n\n    * min_size is the smallest number of elements the index can have.\n    * max_size is the largest number of elements the index can have. If None\n      it will default to some suitable value based on min_size.\n    * name is the name of the index. If st.none(), the index will have no name.\n    \"\"\"\n    check_valid_size(min_size, \"min_size\")\n    check_valid_size(max_size, \"max_size\")\n    if max_size is None:\n        max_size = min([min_size + DEFAULT_MAX_SIZE, 2**63 - 1])\n    check_valid_interval(min_size, max_size, \"min_size\", \"max_size\")\n    check_strategy(name)\n\n    return st.builds(pandas.RangeIndex, st.integers(min_size, max_size), name=name)\n\n\n@cacheable\n@defines_strategy()\ndef indexes(\n    *,\n    elements: st.SearchStrategy[Ex] | None = None,\n    dtype: Any = None,\n    min_size: int = 0,\n    max_size: int | None = None,\n    unique: bool = True,\n    name: st.SearchStrategy[str | None] = st.none(),\n) -> st.SearchStrategy[pandas.Index]:\n    \"\"\"Provides a strategy for producing a :class:`pandas.Index`.\n\n    Arguments:\n\n    * elements is a strategy which will be used to generate the individual\n      values of the index. If None, it will be inferred from the dtype. Note:\n      even if the elements strategy produces tuples, the generated value\n      will not be a MultiIndex, but instead be a normal index whose elements\n      are tuples.\n    * dtype is the dtype of the resulting index. If None, it will be inferred\n      from the elements strategy. At least one of dtype or elements must be\n      provided.\n    * min_size is the minimum number of elements in the index.\n    * max_size is the maximum number of elements in the index. If None then it\n      will default to a suitable small size. If you want larger indexes you\n      should pass a max_size explicitly.\n    * unique specifies whether all of the elements in the resulting index\n      should be distinct.\n    * name is a strategy for strings or ``None``, which will be passed to\n      the :class:`pandas.Index` constructor.\n    \"\"\"\n    check_valid_size(min_size, \"min_size\")\n    check_valid_size(max_size, \"max_size\")\n    check_valid_interval(min_size, max_size, \"min_size\", \"max_size\")\n    check_type(bool, unique, \"unique\")\n\n    elements, dtype = elements_and_dtype(elements, dtype)\n\n    if max_size is None:\n        max_size = min_size + DEFAULT_MAX_SIZE\n    return ValueIndexStrategy(elements, dtype, min_size, max_size, unique, name)\n\n\n@defines_strategy()\ndef series(\n    *,\n    elements: st.SearchStrategy[Ex] | None = None,\n    dtype: Any = None,\n    # new-style unions hit https://github.com/sphinx-doc/sphinx/issues/11211 during\n    # doc builds. See related comment in django/_fields.py. Quote to prevent\n    # shed/pyupgrade from changing it.\n    index: (\n        st.SearchStrategy[\"Union[Sequence, pandas.Index]\"] | None  # noqa: UP007\n    ) = None,\n    fill: st.SearchStrategy[Ex] | None = None,\n    unique: bool = False,\n    name: st.SearchStrategy[str | None] = st.none(),\n) -> st.SearchStrategy[pandas.Series]:\n    \"\"\"Provides a strategy for producing a :class:`pandas.Series`.\n\n    Arguments:\n\n    * elements: a strategy that will be used to generate the individual\n      values in the series. If None, we will attempt to infer a suitable\n      default from the dtype.\n\n    * dtype: the dtype of the resulting series and may be any value\n      that can be passed to :class:`numpy.dtype`. If None, will use\n      pandas's standard behaviour to infer it from the type of the elements\n      values. Note that if the type of values that comes out of your\n      elements strategy varies, then so will the resulting dtype of the\n      series.\n\n    * index: If not None, a strategy for generating indexes for the\n      resulting Series. This can generate either :class:`pandas.Index`\n      objects or any sequence of values (which will be passed to the\n      Index constructor).\n\n      You will probably find it most convenient to use the\n      :func:`~hypothesis.extra.pandas.indexes` or\n      :func:`~hypothesis.extra.pandas.range_indexes` function to produce\n      values for this argument.\n\n    * name: is a strategy for strings or ``None``, which will be passed to\n      the :class:`pandas.Series` constructor.\n\n    Usage:\n\n    .. code-block:: pycon\n\n        >>> series(dtype=int).example()\n        0   -2001747478\n        1    1153062837\n    \"\"\"\n    if index is None:\n        index = range_indexes()\n    else:\n        check_strategy(index, \"index\")\n\n    elements, np_dtype = elements_and_dtype(elements, dtype)\n    index_strategy = index\n\n    # if it is converted to an object, use object for series type\n    if (\n        np_dtype is not None\n        and np_dtype.kind == \"O\"\n        and not isinstance(dtype, IntegerDtype)\n    ):\n        dtype = np_dtype\n\n    @st.composite\n    def result(draw):\n        index = draw(index_strategy)\n\n        if len(index) > 0:\n            if dtype is not None:\n                result_data = draw(\n                    npst.arrays(\n                        dtype=object,\n                        elements=elements,\n                        shape=len(index),\n                        fill=fill,\n                        unique=unique,\n                    )\n                ).tolist()\n            else:\n                result_data = list(\n                    draw(\n                        npst.arrays(\n                            dtype=object,\n                            elements=elements,\n                            shape=len(index),\n                            fill=fill,\n                            unique=unique,\n                        )\n                    ).tolist()\n                )\n            return pandas.Series(result_data, index=index, dtype=dtype, name=draw(name))\n        else:\n            return pandas.Series(\n                (),\n                index=index,\n                dtype=(\n                    dtype\n                    if dtype is not None\n                    else draw(dtype_for_elements_strategy(elements))\n                ),\n                name=draw(name),\n            )\n\n    return result()\n\n\n@dataclass(slots=True, frozen=False)\nclass column(Generic[Ex]):\n    \"\"\"Data object for describing a column in a DataFrame.\n\n    Arguments:\n\n    * name: the column name, or None to default to the column position. Must\n      be hashable, but can otherwise be any value supported as a pandas column\n      name.\n    * elements: the strategy for generating values in this column, or None\n      to infer it from the dtype.\n    * dtype: the dtype of the column, or None to infer it from the element\n      strategy. At least one of dtype or elements must be provided.\n    * fill: A default value for elements of the column. See\n      :func:`~hypothesis.extra.numpy.arrays` for a full explanation.\n    * unique: If all values in this column should be distinct.\n    \"\"\"\n\n    name: str | int | None = None\n    elements: st.SearchStrategy[Ex] | None = None\n    dtype: Any = None\n    fill: st.SearchStrategy[Ex] | None = None\n    unique: bool = False\n\n\ndef columns(\n    names_or_number: int | Sequence[str],\n    *,\n    dtype: Any = None,\n    elements: st.SearchStrategy[Ex] | None = None,\n    fill: st.SearchStrategy[Ex] | None = None,\n    unique: bool = False,\n) -> list[column[Ex]]:\n    \"\"\"A convenience function for producing a list of :class:`column` objects\n    of the same general shape.\n\n    The names_or_number argument is either a sequence of values, the\n    elements of which will be used as the name for individual column\n    objects, or a number, in which case that many unnamed columns will\n    be created. All other arguments are passed through verbatim to\n    create the columns.\n    \"\"\"\n    if isinstance(names_or_number, (int, float)):\n        names: list[int | str | None] = [None] * names_or_number\n    else:\n        names = list(names_or_number)\n    return [\n        column(name=n, dtype=dtype, elements=elements, fill=fill, unique=unique)\n        for n in names\n    ]\n\n\n@defines_strategy()\ndef data_frames(\n    columns: Sequence[column] | None = None,\n    *,\n    rows: st.SearchStrategy[dict | Sequence[Any]] | None = None,\n    index: st.SearchStrategy[Ex] | None = None,\n) -> st.SearchStrategy[pandas.DataFrame]:\n    \"\"\"Provides a strategy for producing a :class:`pandas.DataFrame`.\n\n    Arguments:\n\n    * columns: An iterable of :class:`column` objects describing the shape\n      of the generated DataFrame.\n\n    * rows: A strategy for generating a row object. Should generate\n      either dicts mapping column names to values or a sequence mapping\n      column position to the value in that position (note that unlike the\n      :class:`pandas.DataFrame` constructor, single values are not allowed\n      here. Passing e.g. an integer is an error, even if there is only one\n      column).\n\n      At least one of rows and columns must be provided. If both are\n      provided then the generated rows will be validated against the\n      columns and an error will be raised if they don't match.\n\n      Caveats on using rows:\n\n      * In general you should prefer using columns to rows, and only use\n        rows if the columns interface is insufficiently flexible to\n        describe what you need - you will get better performance and\n        example quality that way.\n      * If you provide rows and not columns, then the shape and dtype of\n        the resulting DataFrame may vary. e.g. if you have a mix of int\n        and float in the values for one column in your row entries, the\n        column will sometimes have an integral dtype and sometimes a float.\n\n    * index: If not None, a strategy for generating indexes for the\n      resulting DataFrame. This can generate either :class:`pandas.Index`\n      objects or any sequence of values (which will be passed to the\n      Index constructor).\n\n      You will probably find it most convenient to use the\n      :func:`~hypothesis.extra.pandas.indexes` or\n      :func:`~hypothesis.extra.pandas.range_indexes` function to produce\n      values for this argument.\n\n    Usage:\n\n    The expected usage pattern is that you use :class:`column` and\n    :func:`columns` to specify a fixed shape of the DataFrame you want as\n    follows. For example the following gives a two column data frame:\n\n    .. code-block:: pycon\n\n        >>> from hypothesis.extra.pandas import column, data_frames\n        >>> data_frames([\n        ... column('A', dtype=int), column('B', dtype=float)]).example()\n                    A              B\n        0  2021915903  1.793898e+232\n        1  1146643993            inf\n        2 -2096165693   1.000000e+07\n\n    If you want the values in different columns to interact in some way you\n    can use the rows argument. For example the following gives a two column\n    DataFrame where the value in the first column is always at most the value\n    in the second:\n\n    .. code-block:: pycon\n\n        >>> from hypothesis.extra.pandas import column, data_frames\n        >>> import hypothesis.strategies as st\n        >>> data_frames(\n        ...     rows=st.tuples(st.floats(allow_nan=False),\n        ...                    st.floats(allow_nan=False)).map(sorted)\n        ... ).example()\n                       0             1\n        0  -3.402823e+38  9.007199e+15\n        1 -1.562796e-298  5.000000e-01\n\n    You can also combine the two:\n\n    .. code-block:: pycon\n\n        >>> from hypothesis.extra.pandas import columns, data_frames\n        >>> import hypothesis.strategies as st\n        >>> data_frames(\n        ...     columns=columns([\"lo\", \"hi\"], dtype=float),\n        ...     rows=st.tuples(st.floats(allow_nan=False),\n        ...                    st.floats(allow_nan=False)).map(sorted)\n        ... ).example()\n                 lo            hi\n        0   9.314723e-49  4.353037e+45\n        1  -9.999900e-01  1.000000e+07\n        2 -2.152861e+134 -1.069317e-73\n\n    (Note that the column dtype must still be specified and will not be\n    inferred from the rows. This restriction may be lifted in future).\n\n    Combining rows and columns has the following behaviour:\n\n    * The column names and dtypes will be used.\n    * If the column is required to be unique, this will be enforced.\n    * Any values missing from the generated rows will be provided using the\n      column's fill.\n    * Any values in the row not present in the column specification (if\n      dicts are passed, if there are keys with no corresponding column name,\n      if sequences are passed if there are too many items) will result in\n      InvalidArgument being raised.\n    \"\"\"\n    if index is None:\n        index = range_indexes()\n    else:\n        check_strategy(index, \"index\")\n\n    index_strategy = index\n\n    if columns is None:\n        if rows is None:\n            raise InvalidArgument(\"At least one of rows and columns must be provided\")\n        else:\n\n            @st.composite\n            def rows_only(draw):\n                index = draw(index_strategy)\n\n                def row():\n                    result = draw(rows)\n                    check_type(abc.Iterable, result, \"draw(row)\")\n                    return result\n\n                if len(index) > 0:\n                    return pandas.DataFrame([row() for _ in index], index=index)\n                else:\n                    # If we haven't drawn any rows we need to draw one row and\n                    # then discard it so that we get a consistent shape for the\n                    # DataFrame.\n                    base = pandas.DataFrame([row()])\n                    return base.drop(0)\n\n            return rows_only()\n\n    assert columns is not None\n    cols = try_convert(tuple, columns, \"columns\")\n\n    rewritten_columns = []\n    column_names: set[str] = set()\n\n    for i, c in enumerate(cols):\n        check_type(column, c, f\"columns[{i}]\")\n\n        c = copy(c)\n        if c.name is None:\n            label = f\"columns[{i}]\"\n            c.name = i\n        else:\n            label = c.name\n            try:\n                hash(c.name)\n            except TypeError:\n                raise InvalidArgument(\n                    f\"Column names must be hashable, but columns[{i}].name was \"\n                    f\"{c.name!r} of type {type(c.name).__name__}, which cannot be hashed.\"\n                ) from None\n\n        if c.name in column_names:\n            raise InvalidArgument(f\"duplicate definition of column name {c.name!r}\")\n\n        column_names.add(c.name)\n        c.elements, _ = elements_and_dtype(c.elements, c.dtype, label)\n\n        if c.dtype is None and rows is not None:\n            raise InvalidArgument(\n                \"Must specify a dtype for all columns when combining rows with columns.\"\n            )\n\n        c.fill = npst.fill_for(\n            fill=c.fill, elements=c.elements, unique=c.unique, name=label\n        )\n        rewritten_columns.append(c)\n\n    if rows is None:\n\n        @st.composite\n        def just_draw_columns(draw):\n            index = draw(index_strategy)\n            local_index_strategy = st.just(index)\n\n            data = OrderedDict((c.name, None) for c in rewritten_columns)\n\n            # Depending on how the columns are going to be generated we group\n            # them differently to get better shrinking. For columns with fill\n            # enabled, the elements can be shrunk independently of the size,\n            # so we can just shrink by shrinking the index then shrinking the\n            # length and are generally much more free to move data around.\n\n            # For columns with no filling the problem is harder, and drawing\n            # them like that would result in rows being very far apart from\n            # each other in the choice sequence, which gets in the way\n            # of shrinking. So what we do is reorder and draw those columns\n            # row wise, so that the values of each row are next to each other.\n            # This makes life easier for the shrinker when deleting choices.\n\n            columns_without_fill = [c for c in rewritten_columns if c.fill.is_empty]\n            if columns_without_fill:\n                for c in columns_without_fill:\n                    data[c.name] = pandas.Series(\n                        np.zeros(shape=len(index), dtype=object),\n                        index=index,\n                        dtype=c.dtype,\n                    )\n                seen = {c.name: set() for c in columns_without_fill if c.unique}\n\n                for i in range(len(index)):\n                    for c in columns_without_fill:\n                        if c.unique:\n                            for _ in range(5):\n                                value = draw(c.elements)\n                                if value not in seen[c.name]:\n                                    seen[c.name].add(value)\n                                    break\n                            else:\n                                reject()\n                        else:\n                            value = draw(c.elements)\n\n                        try:\n                            data[c.name].iloc[i] = value\n                        except ValueError as err:  # pragma: no cover\n                            # This just works in Pandas 1.4 and later, but gives\n                            # a confusing error on previous versions.\n                            if c.dtype is None and not isinstance(\n                                value, (float, int, str, bool, datetime, timedelta)\n                            ):\n                                raise ValueError(\n                                    f\"Failed to add {value=} to column \"\n                                    f\"{c.name} with dtype=None.  Maybe passing \"\n                                    \"dtype=object would help?\"\n                                ) from err\n                            # Unclear how this could happen, but users find a way...\n                            raise\n\n            for c in rewritten_columns:\n                if not c.fill.is_empty:\n                    data[c.name] = draw(\n                        series(\n                            index=local_index_strategy,\n                            dtype=c.dtype,\n                            elements=c.elements,\n                            fill=c.fill,\n                            unique=c.unique,\n                        )\n                    )\n\n            return pandas.DataFrame(data, index=index)\n\n        return just_draw_columns()\n    else:\n\n        @st.composite\n        def assign_rows(draw):\n            index = draw(index_strategy)\n\n            result = pandas.DataFrame(\n                OrderedDict(\n                    (\n                        c.name,\n                        pandas.Series(\n                            np.zeros(dtype=c.dtype, shape=len(index)), dtype=c.dtype\n                        ),\n                    )\n                    for c in rewritten_columns\n                ),\n                index=index,\n            )\n\n            fills = {}\n\n            any_unique = any(c.unique for c in rewritten_columns)\n\n            if any_unique:\n                all_seen = [set() if c.unique else None for c in rewritten_columns]\n                while all_seen[-1] is None:\n                    all_seen.pop()\n\n            for row_index in range(len(index)):\n                for _ in range(5):\n                    original_row = draw(rows)\n                    row = original_row\n                    if isinstance(row, dict):\n                        as_list = [None] * len(rewritten_columns)\n                        for i, c in enumerate(rewritten_columns):\n                            try:\n                                as_list[i] = row[c.name]\n                            except KeyError:\n                                try:\n                                    as_list[i] = fills[i]\n                                except KeyError:\n                                    if c.fill.is_empty:\n                                        raise InvalidArgument(\n                                            f\"Empty fill strategy in {c!r} cannot \"\n                                            f\"complete row {original_row!r}\"\n                                        ) from None\n                                    fills[i] = draw(c.fill)\n                                    as_list[i] = fills[i]\n                        for k in row:\n                            if k not in column_names:\n                                raise InvalidArgument(\n                                    f\"Row {row!r} contains column {k!r} not in \"\n                                    f\"columns {[c.name for c in rewritten_columns]!r})\"\n                                )\n                        row = as_list\n                    if any_unique:\n                        has_duplicate = False\n                        for seen, value in zip(all_seen, row, strict=False):\n                            if seen is None:\n                                continue\n                            if value in seen:\n                                has_duplicate = True\n                                break\n                            seen.add(value)\n                        if has_duplicate:\n                            continue\n                    row = list(try_convert(tuple, row, \"draw(rows)\"))\n\n                    if len(row) > len(rewritten_columns):\n                        raise InvalidArgument(\n                            f\"Row {original_row!r} contains too many entries. Has \"\n                            f\"{len(row)} but expected at most {len(rewritten_columns)}\"\n                        )\n                    while len(row) < len(rewritten_columns):\n                        c = rewritten_columns[len(row)]\n                        if c.fill.is_empty:\n                            raise InvalidArgument(\n                                f\"Empty fill strategy in {c!r} cannot \"\n                                f\"complete row {original_row!r}\"\n                            )\n                        row.append(draw(c.fill))\n                    result.iloc[row_index] = row\n                    break\n                else:\n                    reject()\n            return result\n\n        return assign_rows()\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/pytestplugin.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\nStub for users who manually load our pytest plugin.\n\nThe plugin implementation is now located in a top-level module outside the main\nhypothesis tree, so that Pytest can load the plugin without thereby triggering\nthe import of Hypothesis itself (and thus loading our own plugins).\n\"\"\"\n\nfrom _hypothesis_pytestplugin import *  # noqa\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/pytz.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\nThis module provides :pypi:`pytz` timezones.\n\nIf you are unable to use the stdlib :mod:`zoneinfo` module, e.g. via the\n:func:`hypothesis.strategies.timezones` strategy, you can use this\nstrategy with :py:func:`hypothesis.strategies.datetimes` and\n:py:func:`hypothesis.strategies.times` to produce timezone-aware values.\n\n.. warning::\n\n    Since :mod:`zoneinfo` was added in Python 3.9, this extra\n    is deprecated.  We intend to remove it after libraries\n    such as Pandas and Django complete their own migrations.\n\"\"\"\n\nimport datetime as dt\n\nimport pytz\nfrom pytz.tzfile import StaticTzInfo  # type: ignore  # considered private by typeshed\n\nfrom hypothesis import strategies as st\nfrom hypothesis.strategies._internal.utils import cacheable, defines_strategy\n\n__all__ = [\"timezones\"]\n\n\n@cacheable\n@defines_strategy()\ndef timezones() -> st.SearchStrategy[dt.tzinfo]:\n    \"\"\"Any timezone in the Olsen database, as a pytz tzinfo object.\n\n    This strategy minimises to UTC, or the smallest possible fixed\n    offset, and is designed for use with :func:`hypothesis.strategies.datetimes`.\n\n    .. tip::\n        Prefer the :func:`hypothesis.strategies.timezones` strategy, which uses\n        the stdlib :mod:`zoneinfo` module and avoids `the many footguns in pytz\n        <https://blog.ganssle.io/articles/2018/03/pytz-fastest-footgun.html>`__.\n    \"\"\"\n    all_timezones = [pytz.timezone(tz) for tz in pytz.all_timezones]\n    # Some timezones have always had a constant offset from UTC.  This makes\n    # them simpler than timezones with daylight savings, and the smaller the\n    # absolute offset the simpler they are.  Of course, UTC is even simpler!\n    static: list = [pytz.UTC]\n    static += sorted(\n        (t for t in all_timezones if isinstance(t, StaticTzInfo)),\n        key=lambda tz: abs(tz.utcoffset(dt.datetime(2000, 1, 1))),\n    )\n    # Timezones which have changed UTC offset; best ordered by name.\n    dynamic = [tz for tz in all_timezones if tz not in static]\n    return st.sampled_from(static + dynamic)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/extra/redis.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport base64\nimport json\nfrom collections.abc import Iterable\nfrom contextlib import contextmanager\nfrom datetime import timedelta\nfrom typing import Any\n\nfrom redis import Redis\n\nfrom hypothesis.database import ExampleDatabase\nfrom hypothesis.internal.validation import check_type\n\n\nclass RedisExampleDatabase(ExampleDatabase):\n    \"\"\"Store Hypothesis examples as sets in the given :class:`~redis.Redis` datastore.\n\n    This is particularly useful for shared databases, as per the recipe\n    for a :class:`~hypothesis.database.MultiplexedDatabase`.\n\n    .. note::\n\n        If a test has not been run for ``expire_after``, those examples will be allowed\n        to expire.  The default time-to-live persists examples between weekly runs.\n    \"\"\"\n\n    def __init__(\n        self,\n        redis: Redis,\n        *,\n        expire_after: timedelta = timedelta(days=8),\n        key_prefix: bytes = b\"hypothesis-example:\",\n        listener_channel: str = \"hypothesis-changes\",\n    ):\n        super().__init__()\n        check_type(Redis, redis, \"redis\")\n        check_type(timedelta, expire_after, \"expire_after\")\n        check_type(bytes, key_prefix, \"key_prefix\")\n        check_type(str, listener_channel, \"listener_channel\")\n        self.redis = redis\n        self._expire_after = expire_after\n        self._prefix = key_prefix\n        self.listener_channel = listener_channel\n        self._pubsub: Any = None\n\n    def __repr__(self) -> str:\n        return (\n            f\"RedisExampleDatabase({self.redis!r}, expire_after={self._expire_after!r})\"\n        )\n\n    def __eq__(self, other: object) -> bool:\n        return (\n            isinstance(other, RedisExampleDatabase)\n            and self.redis == other.redis\n            and self._prefix == other._prefix\n            and self.listener_channel == other.listener_channel\n        )\n\n    @contextmanager\n    def _pipeline(\n        self,\n        *reset_expire_keys,\n        execute_and_publish=True,\n        event_type=None,\n        to_publish=None,\n    ):\n        # Context manager to batch updates and expiry reset, reducing TCP roundtrips\n        pipe = self.redis.pipeline()\n        yield pipe\n        for key in reset_expire_keys:\n            pipe.expire(self._prefix + key, self._expire_after)\n        if execute_and_publish:\n            changed = pipe.execute()\n            # pipe.execute returns the rows modified for each operation, which includes\n            # the operations performed during the yield, followed by the n operations\n            # from pipe.exire. Look at just the operations from during the yield.\n            changed = changed[: -len(reset_expire_keys)]\n            if any(count > 0 for count in changed):\n                assert to_publish is not None\n                assert event_type is not None\n                self._publish((event_type, to_publish))\n\n    def _publish(self, event):\n        event = (event[0], tuple(self._encode(v) for v in event[1]))\n        self.redis.publish(self.listener_channel, json.dumps(event))\n\n    def _encode(self, value: bytes) -> str:\n        return base64.b64encode(value).decode(\"ascii\")\n\n    def _decode(self, value: str) -> bytes:\n        return base64.b64decode(value)\n\n    def fetch(self, key: bytes) -> Iterable[bytes]:\n        with self._pipeline(key, execute_and_publish=False) as pipe:\n            pipe.smembers(self._prefix + key)\n        yield from pipe.execute()[0]\n\n    def save(self, key: bytes, value: bytes) -> None:\n        with self._pipeline(key, event_type=\"save\", to_publish=(key, value)) as pipe:\n            pipe.sadd(self._prefix + key, value)\n\n    def delete(self, key: bytes, value: bytes) -> None:\n        with self._pipeline(key, event_type=\"delete\", to_publish=(key, value)) as pipe:\n            pipe.srem(self._prefix + key, value)\n\n    def move(self, src: bytes, dest: bytes, value: bytes) -> None:\n        if src == dest:\n            self.save(dest, value)\n            return\n\n        with self._pipeline(src, dest, execute_and_publish=False) as pipe:\n            pipe.srem(self._prefix + src, value)\n            pipe.sadd(self._prefix + dest, value)\n\n        changed = pipe.execute()\n        if changed[0] > 0:\n            # did the value set of the first key change?\n            self._publish((\"delete\", (src, value)))\n        if changed[1] > 0:\n            # did the value set of the second key change?\n            self._publish((\"save\", (dest, value)))\n\n    def _handle_message(self, message: dict) -> None:\n        # other message types include \"subscribe\" and \"unsubscribe\". these are\n        # sent to the client, but not to the pubsub channel.\n        assert message[\"type\"] == \"message\"\n        data = json.loads(message[\"data\"])\n        event_type = data[0]\n        self._broadcast_change(\n            (event_type, tuple(self._decode(v) for v in data[1]))  # type: ignore\n        )\n\n    def _start_listening(self) -> None:\n        self._pubsub = self.redis.pubsub()\n        self._pubsub.subscribe(**{self.listener_channel: self._handle_message})\n\n    def _stop_listening(self) -> None:\n        self._pubsub.unsubscribe()\n        self._pubsub.close()\n        self._pubsub = None\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/cache.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport threading\nfrom collections import OrderedDict\nfrom dataclasses import dataclass\nfrom typing import Any, Generic, TypeVar\n\nfrom hypothesis.errors import InvalidArgument\n\nK = TypeVar(\"K\")\nV = TypeVar(\"V\")\n\n\n@dataclass(slots=True, frozen=False)\nclass Entry(Generic[K, V]):\n    key: K\n    value: V\n    score: int\n    pins: int = 0\n\n    @property\n    def sort_key(self) -> tuple[int, ...]:\n        if self.pins == 0:\n            # Unpinned entries are sorted by score.\n            return (0, self.score)\n        else:\n            # Pinned entries sort after unpinned ones. Beyond that, we don't\n            # worry about their relative order.\n            return (1,)\n\n\nclass GenericCache(Generic[K, V]):\n    \"\"\"Generic supertype for cache implementations.\n\n    Defines a dict-like mapping with a maximum size, where as well as mapping\n    to a value, each key also maps to a score. When a write would cause the\n    dict to exceed its maximum size, it first evicts the existing key with\n    the smallest score, then adds the new key to the map. If due to pinning\n    no key can be evicted, ValueError is raised.\n\n    A key has the following lifecycle:\n\n    1. key is written for the first time, the key is given the score\n       self.new_entry(key, value)\n    2. whenever an existing key is read or written, self.on_access(key, value,\n       score) is called. This returns a new score for the key.\n    3. After a key is evicted, self.on_evict(key, value, score) is called.\n\n    The cache will be in a valid state in all of these cases.\n\n    Implementations are expected to implement new_entry and optionally\n    on_access and on_evict to implement a specific scoring strategy.\n    \"\"\"\n\n    __slots__ = (\"_threadlocal\", \"max_size\")\n\n    def __init__(self, max_size: int):\n        if max_size <= 0:\n            raise InvalidArgument(\"Cache size must be at least one.\")\n\n        self.max_size = max_size\n\n        # Implementation: We store a binary heap of Entry objects in self.data,\n        # with the heap property requiring that a parent's score is <= that of\n        # its children. keys_to_index then maps keys to their index in the\n        # heap. We keep these two in sync automatically - the heap is never\n        # reordered without updating the index.\n        self._threadlocal = threading.local()\n\n    @property\n    def keys_to_indices(self) -> dict[K, int]:\n        try:\n            return self._threadlocal.keys_to_indices\n        except AttributeError:\n            self._threadlocal.keys_to_indices = {}\n            return self._threadlocal.keys_to_indices\n\n    @property\n    def data(self) -> list[Entry[K, V]]:\n        try:\n            return self._threadlocal.data\n        except AttributeError:\n            self._threadlocal.data = []\n            return self._threadlocal.data\n\n    def __len__(self) -> int:\n        assert len(self.keys_to_indices) == len(self.data)\n        return len(self.data)\n\n    def __contains__(self, key: K) -> bool:\n        return key in self.keys_to_indices\n\n    def __getitem__(self, key: K) -> V:\n        i = self.keys_to_indices[key]\n        result = self.data[i]\n        self.__entry_was_accessed(i)\n        return result.value\n\n    def __setitem__(self, key: K, value: V) -> None:\n        evicted = None\n        try:\n            i = self.keys_to_indices[key]\n        except KeyError:\n            entry = Entry(key, value, self.new_entry(key, value))\n            if len(self.data) >= self.max_size:\n                evicted = self.data[0]\n                if evicted.pins > 0:\n                    raise ValueError(\n                        \"Cannot increase size of cache where all keys have been pinned.\"\n                    ) from None\n                del self.keys_to_indices[evicted.key]\n                i = 0\n                self.data[0] = entry\n            else:\n                i = len(self.data)\n                self.data.append(entry)\n            self.keys_to_indices[key] = i\n            self.__balance(i)\n        else:\n            entry = self.data[i]\n            assert entry.key == key\n            entry.value = value\n            self.__entry_was_accessed(i)\n\n        if evicted is not None:\n            if self.data[0] is not entry:\n                assert evicted.sort_key <= self.data[0].sort_key\n            self.on_evict(evicted.key, evicted.value, evicted.score)\n\n    def __iter__(self):\n        return iter(self.keys_to_indices)\n\n    def pin(self, key: K, value: V) -> None:\n        \"\"\"Mark ``key`` as pinned (with the given value). That is, it may not\n        be evicted until ``unpin(key)`` has been called. The same key may be\n        pinned multiple times, possibly changing its value, and will not be\n        unpinned until the same number of calls to unpin have been made.\n        \"\"\"\n        self[key] = value\n\n        i = self.keys_to_indices[key]\n        entry = self.data[i]\n        entry.pins += 1\n        if entry.pins == 1:\n            self.__balance(i)\n\n    def unpin(self, key: K) -> None:\n        \"\"\"Undo one previous call to ``pin(key)``. The value stays the same.\n        Once all calls are undone this key may be evicted as normal.\"\"\"\n        i = self.keys_to_indices[key]\n        entry = self.data[i]\n        if entry.pins == 0:\n            raise ValueError(f\"Key {key!r} has not been pinned\")\n        entry.pins -= 1\n        if entry.pins == 0:\n            self.__balance(i)\n\n    def is_pinned(self, key: K) -> bool:\n        \"\"\"Returns True if the key is currently pinned.\"\"\"\n        i = self.keys_to_indices[key]\n        return self.data[i].pins > 0\n\n    def clear(self) -> None:\n        \"\"\"Remove all keys, regardless of their pinned status.\"\"\"\n        del self.data[:]\n        self.keys_to_indices.clear()\n\n    def __repr__(self) -> str:\n        return \"{\" + \", \".join(f\"{e.key!r}: {e.value!r}\" for e in self.data) + \"}\"\n\n    def new_entry(self, key: K, value: V) -> int:\n        \"\"\"Called when a key is written that does not currently appear in the\n        map.\n\n        Returns the score to associate with the key.\n        \"\"\"\n        raise NotImplementedError\n\n    def on_access(self, key: K, value: V, score: Any) -> Any:\n        \"\"\"Called every time a key that is already in the map is read or\n        written.\n\n        Returns the new score for the key.\n        \"\"\"\n        return score\n\n    def on_evict(self, key: K, value: V, score: Any) -> Any:\n        \"\"\"Called after a key has been evicted, with the score it had had at\n        the point of eviction.\"\"\"\n\n    def check_valid(self) -> None:\n        \"\"\"Debugging method for use in tests.\n\n        Asserts that all of the cache's invariants hold. When everything\n        is working correctly this should be an expensive no-op.\n        \"\"\"\n        assert len(self.keys_to_indices) == len(self.data)\n        for i, e in enumerate(self.data):\n            assert self.keys_to_indices[e.key] == i\n            for j in [i * 2 + 1, i * 2 + 2]:\n                if j < len(self.data):\n                    assert e.sort_key <= self.data[j].sort_key, self.data\n\n    def __entry_was_accessed(self, i: int) -> None:\n        entry = self.data[i]\n        new_score = self.on_access(entry.key, entry.value, entry.score)\n        if new_score != entry.score:\n            entry.score = new_score\n            # changing the score of a pinned entry cannot unbalance the heap, as\n            # we place all pinned entries after unpinned ones, regardless of score.\n            if entry.pins == 0:\n                self.__balance(i)\n\n    def __swap(self, i: int, j: int) -> None:\n        assert i < j\n        assert self.data[j].sort_key < self.data[i].sort_key\n        self.data[i], self.data[j] = self.data[j], self.data[i]\n        self.keys_to_indices[self.data[i].key] = i\n        self.keys_to_indices[self.data[j].key] = j\n\n    def __balance(self, i: int) -> None:\n        \"\"\"When we have made a modification to the heap such that\n        the heap property has been violated locally around i but previously\n        held for all other indexes (and no other values have been modified),\n        this fixes the heap so that the heap property holds everywhere.\"\"\"\n        # bubble up (if score is too low for current position)\n        while (parent := (i - 1) // 2) >= 0:\n            if self.__out_of_order(parent, i):\n                self.__swap(parent, i)\n                i = parent\n            else:\n                break\n        # or bubble down (if score is too high for current position)\n        while children := [j for j in (2 * i + 1, 2 * i + 2) if j < len(self.data)]:\n            smallest_child = min(children, key=lambda j: self.data[j].sort_key)\n            if self.__out_of_order(i, smallest_child):\n                self.__swap(i, smallest_child)\n                i = smallest_child\n            else:\n                break\n\n    def __out_of_order(self, i: int, j: int) -> bool:\n        \"\"\"Returns True if the indices i, j are in the wrong order.\n\n        i must be the parent of j.\n        \"\"\"\n        assert i == (j - 1) // 2\n        return self.data[j].sort_key < self.data[i].sort_key\n\n\nclass LRUReusedCache(GenericCache[K, V]):\n    \"\"\"The only concrete implementation of GenericCache we use outside of tests\n    currently.\n\n    Adopts a modified least-recently used eviction policy: It evicts the key\n    that has been used least recently, but it will always preferentially evict\n    keys that have never been accessed after insertion. Among keys that have been\n    accessed, it ignores the number of accesses.\n\n    This retains most of the benefits of an LRU cache, but adds an element of\n    scan-resistance to the process: If we end up scanning through a large\n    number of keys without reusing them, this does not evict the existing\n    entries in preference for the new ones.\n    \"\"\"\n\n    __slots__ = (\"__tick\",)\n\n    def __init__(self, max_size: int):\n        super().__init__(max_size)\n        self.__tick: int = 0\n\n    def tick(self) -> int:\n        self.__tick += 1\n        return self.__tick\n\n    def new_entry(self, key: K, value: V) -> Any:\n        return (1, self.tick())\n\n    def on_access(self, key: K, value: V, score: Any) -> Any:\n        return (2, self.tick())\n\n\nclass LRUCache(Generic[K, V]):\n    \"\"\"\n    This is a drop-in replacement for a GenericCache (despite the lack of inheritance)\n    in performance critical environments. It turns out that GenericCache's heap\n    balancing for arbitrary scores can be quite expensive compared to the doubly\n    linked list approach of lru_cache or OrderedDict.\n\n    This class is a pure LRU and does not provide any sort of affininty towards\n    the number of accesses beyond recency. If soft-pinning entries which have been\n    accessed at least once is important, use LRUReusedCache.\n    \"\"\"\n\n    # Here are some nice performance references for lru_cache vs OrderedDict:\n    # https://github.com/python/cpython/issues/72426#issuecomment-1093727671\n    # https://discuss.python.org/t/simplify-lru-cache/18192/6\n    #\n    # We use OrderedDict here because it is unclear to me we can provide the same\n    # api as GenericCache using @lru_cache without messing with lru_cache internals.\n    #\n    # Anecdotally, OrderedDict seems quite competitive with lru_cache, but perhaps\n    # that is localized to our access patterns.\n\n    def __init__(self, max_size: int) -> None:\n        assert max_size > 0\n        self.max_size = max_size\n        self._threadlocal = threading.local()\n\n    @property\n    def cache(self) -> OrderedDict[K, V]:\n        try:\n            return self._threadlocal.cache\n        except AttributeError:\n            self._threadlocal.cache = OrderedDict()\n            return self._threadlocal.cache\n\n    def __setitem__(self, key: K, value: V) -> None:\n        self.cache[key] = value\n        self.cache.move_to_end(key)\n\n        while len(self.cache) > self.max_size:\n            self.cache.popitem(last=False)\n\n    def __getitem__(self, key: K) -> V:\n        val = self.cache[key]\n        self.cache.move_to_end(key)\n        return val\n\n    def __iter__(self):\n        return iter(self.cache)\n\n    def __len__(self) -> int:\n        return len(self.cache)\n\n    def __contains__(self, key: K) -> bool:\n        return key in self.cache\n\n    # implement GenericCache interface, for tests\n    def check_valid(self) -> None:\n        pass\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/cathetus.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom math import fabs, inf, isinf, isnan, nan, sqrt\nfrom sys import float_info\n\n\ndef cathetus(h: float, a: float) -> float:\n    \"\"\"Given the lengths of the hypotenuse and a side of a right triangle,\n    return the length of the other side.\n\n    A companion to the C99 hypot() function.  Some care is needed to avoid\n    underflow in the case of small arguments, and overflow in the case of\n    large arguments as would occur for the naive implementation as\n    sqrt(h*h - a*a).  The behaviour with respect the non-finite arguments\n    (NaNs and infinities) is designed to be as consistent as possible with\n    the C99 hypot() specifications.\n\n    This function relies on the system ``sqrt`` function and so, like it,\n    may be inaccurate up to a relative error of (around) floating-point\n    epsilon.\n\n    Based on the C99 implementation https://gitlab.com/jjg/cathetus\n    \"\"\"\n    if isnan(h):\n        return nan\n\n    if isinf(h):\n        if isinf(a):\n            return nan\n        else:\n            # Deliberately includes the case when isnan(a), because the\n            # C99 standard mandates that hypot(inf, nan) == inf\n            return inf\n\n    h = fabs(h)\n    a = fabs(a)\n\n    if h < a:\n        return nan\n\n    # Thanks to floating-point precision issues when performing multiple\n    # operations on extremely large or small values, we may rarely calculate\n    # a side length that is longer than the hypotenuse.  This is clearly an\n    # error, so we clip to the hypotenuse as the best available estimate.\n    if h > sqrt(float_info.max):\n        if h > float_info.max / 2:\n            b = sqrt(h - a) * sqrt(h / 2 + a / 2) * sqrt(2)\n        else:\n            b = sqrt(h - a) * sqrt(h + a)\n    elif h < sqrt(float_info.min):\n        b = sqrt(h - a) * sqrt(h + a)\n    else:\n        b = sqrt((h - a) * (h + a))\n    return min(b, h)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/charmap.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport codecs\nimport gzip\nimport json\nimport os\nimport sys\nimport tempfile\nimport unicodedata\nfrom collections.abc import Collection, Iterable\nfrom functools import cache\nfrom pathlib import Path\nfrom typing import Literal, TypeAlias\n\nfrom hypothesis.configuration import storage_directory\nfrom hypothesis.control import _current_build_context\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.intervalsets import IntervalSet, IntervalsT\n\n# See https://en.wikipedia.org/wiki/Unicode_character_property#General_Category\nCategoryName: TypeAlias = Literal[\n    \"L\",  #  Letter\n    \"Lu\",  # Letter, uppercase\n    \"Ll\",  # Letter, lowercase\n    \"Lt\",  # Letter, titlecase\n    \"Lm\",  # Letter, modifier\n    \"Lo\",  # Letter, other\n    \"M\",  #  Mark\n    \"Mn\",  # Mark, nonspacing\n    \"Mc\",  # Mark, spacing combining\n    \"Me\",  # Mark, enclosing\n    \"N\",  #  Number\n    \"Nd\",  # Number, decimal digit\n    \"Nl\",  # Number, letter\n    \"No\",  # Number, other\n    \"P\",  #  Punctuation\n    \"Pc\",  # Punctuation, connector\n    \"Pd\",  # Punctuation, dash\n    \"Ps\",  # Punctuation, open\n    \"Pe\",  # Punctuation, close\n    \"Pi\",  # Punctuation, initial quote\n    \"Pf\",  # Punctuation, final quote\n    \"Po\",  # Punctuation, other\n    \"S\",  #  Symbol\n    \"Sm\",  # Symbol, math\n    \"Sc\",  # Symbol, currency\n    \"Sk\",  # Symbol, modifier\n    \"So\",  # Symbol, other\n    \"Z\",  #  Separator\n    \"Zs\",  # Separator, space\n    \"Zl\",  # Separator, line\n    \"Zp\",  # Separator, paragraph\n    \"C\",  #  Other\n    \"Cc\",  # Other, control\n    \"Cf\",  # Other, format\n    \"Cs\",  # Other, surrogate\n    \"Co\",  # Other, private use\n    \"Cn\",  # Other, not assigned\n]\nCategories: TypeAlias = Iterable[CategoryName]\nCategoriesTuple: TypeAlias = tuple[CategoryName, ...]\n\n\ndef charmap_file(fname: str = \"charmap\") -> Path:\n    return storage_directory(\n        \"unicode_data\", unicodedata.unidata_version, f\"{fname}.json.gz\"\n    )\n\n\n_charmap: dict[CategoryName, IntervalsT] | None = None\n\n\ndef charmap() -> dict[CategoryName, IntervalsT]:\n    \"\"\"Return a dict that maps a Unicode category, to a tuple of 2-tuples\n    covering the codepoint intervals for characters in that category.\n\n    >>> charmap()['Co']\n    ((57344, 63743), (983040, 1048573), (1048576, 1114109))\n    \"\"\"\n    global _charmap\n    # Best-effort caching in the face of missing files and/or unwritable\n    # filesystems is fairly simple: check if loaded, else try loading,\n    # else calculate and try writing the cache.\n    if _charmap is None:\n        f = charmap_file()\n        try:\n            with gzip.GzipFile(f, \"rb\") as d:\n                tmp_charmap = dict(json.load(d))\n\n        except Exception:\n            # This loop is reduced to using only local variables for performance;\n            # indexing and updating containers is a ~3x slowdown.  This doesn't fix\n            # https://github.com/HypothesisWorks/hypothesis/issues/2108 but it helps.\n            category = unicodedata.category  # Local variable -> ~20% speedup!\n            tmp_charmap = {}\n            last_cat = category(chr(0))\n            last_start = 0\n            for i in range(1, sys.maxunicode + 1):\n                cat = category(chr(i))\n                if cat != last_cat:\n                    tmp_charmap.setdefault(last_cat, []).append((last_start, i - 1))\n                    last_cat, last_start = cat, i\n            tmp_charmap.setdefault(last_cat, []).append((last_start, sys.maxunicode))\n\n            try:\n                # Write the Unicode table atomically\n                tmpdir = storage_directory(\"tmp\")\n                tmpdir.mkdir(exist_ok=True, parents=True)\n                fd, tmpfile = tempfile.mkstemp(dir=tmpdir)\n                os.close(fd)\n                # Explicitly set the mtime to get reproducible output\n                with gzip.GzipFile(tmpfile, \"wb\", mtime=1) as fp:\n                    result = json.dumps(sorted(tmp_charmap.items()))\n                    fp.write(result.encode())\n\n                os.renames(tmpfile, f)\n            except Exception:\n                pass\n\n        # convert between lists and tuples\n        _charmap = {\n            k: tuple(tuple(pair) for pair in pairs) for k, pairs in tmp_charmap.items()\n        }\n        # each value is a tuple of 2-tuples (that is, tuples of length 2)\n        # and both elements of that tuple are integers.\n        for vs in _charmap.values():\n            ints = list(sum(vs, ()))\n            assert all(isinstance(x, int) for x in ints)\n            assert ints == sorted(ints)\n            assert all(len(tup) == 2 for tup in vs)\n\n    assert _charmap is not None\n    return _charmap\n\n\n@cache\ndef intervals_from_codec(codec_name: str) -> IntervalSet:  # pragma: no cover\n    \"\"\"Return an IntervalSet of characters which are part of this codec.\"\"\"\n    assert codec_name == codecs.lookup(codec_name).name\n    fname = charmap_file(f\"codec-{codec_name}\")\n    try:\n        with gzip.GzipFile(fname) as gzf:\n            encodable_intervals = json.load(gzf)\n\n    except Exception:\n        # This loop is kinda slow, but hopefully we don't need to do it very often!\n        encodable_intervals = []\n        for i in range(sys.maxunicode + 1):\n            try:\n                chr(i).encode(codec_name)\n            except Exception:  # usually _but not always_ UnicodeEncodeError\n                pass\n            else:\n                encodable_intervals.append((i, i))\n\n    res = IntervalSet(encodable_intervals)\n    res = res.union(res)\n    try:\n        # Write the Unicode table atomically\n        tmpdir = storage_directory(\"tmp\")\n        tmpdir.mkdir(exist_ok=True, parents=True)\n        fd, tmpfile = tempfile.mkstemp(dir=tmpdir)\n        os.close(fd)\n        # Explicitly set the mtime to get reproducible output\n        with gzip.GzipFile(tmpfile, \"wb\", mtime=1) as f:\n            f.write(json.dumps(res.intervals).encode())\n        os.renames(tmpfile, fname)\n    except Exception:\n        pass\n    return res\n\n\n_categories: Categories | None = None\n\n\ndef categories() -> Categories:\n    \"\"\"Return a tuple of Unicode categories in a normalised order.\n\n    >>> categories() # doctest: +ELLIPSIS\n    ('Zl', 'Zp', 'Co', 'Me', 'Pc', ..., 'Cc', 'Cs')\n    \"\"\"\n    global _categories\n    if _categories is None:\n        cm = charmap()\n        categories = sorted(cm.keys(), key=lambda c: len(cm[c]))\n        categories.remove(\"Cc\")  # Other, Control\n        categories.remove(\"Cs\")  # Other, Surrogate\n        categories.append(\"Cc\")\n        categories.append(\"Cs\")\n        _categories = tuple(categories)\n    return _categories\n\n\ndef as_general_categories(cats: Categories, name: str = \"cats\") -> CategoriesTuple:\n    \"\"\"Return a tuple of Unicode categories in a normalised order.\n\n    This function expands one-letter designations of a major class to include\n    all subclasses:\n\n    >>> as_general_categories(['N'])\n    ('Nd', 'Nl', 'No')\n\n    See section 4.5 of the Unicode standard for more on classes:\n    https://www.unicode.org/versions/Unicode10.0.0/ch04.pdf\n\n    If the collection ``cats`` includes any elements that do not represent a\n    major class or a class with subclass, a deprecation warning is raised.\n    \"\"\"\n    major_classes = (\"L\", \"M\", \"N\", \"P\", \"S\", \"Z\", \"C\")\n    cs = categories()\n    out = set(cats)\n    for c in cats:\n        if c in major_classes:\n            out.discard(c)\n            out.update(x for x in cs if x.startswith(c))\n        elif c not in cs:\n            raise InvalidArgument(\n                f\"In {name}={cats!r}, {c!r} is not a valid Unicode category.\"\n            )\n    return tuple(c for c in cs if c in out)\n\n\ncategory_index_cache: dict[frozenset[CategoryName], IntervalsT] = {frozenset(): ()}\n\n\ndef _category_key(cats: Iterable[str] | None) -> CategoriesTuple:\n    \"\"\"Return a normalised tuple of all Unicode categories that are in\n    `include`, but not in `exclude`.\n\n    If include is None then default to including all categories.\n    Any item in include that is not a unicode character will be excluded.\n\n    >>> _category_key(exclude=['So'], include=['Lu', 'Me', 'Cs', 'So'])\n    ('Me', 'Lu', 'Cs')\n    \"\"\"\n    cs = categories()\n    if cats is None:\n        cats = set(cs)\n    return tuple(c for c in cs if c in cats)\n\n\ndef _query_for_key(key: Categories) -> IntervalsT:\n    \"\"\"Return a tuple of codepoint intervals covering characters that match one\n    or more categories in the tuple of categories `key`.\n\n    >>> _query_for_key(categories())\n    ((0, 1114111),)\n    >>> _query_for_key(('Zl', 'Zp', 'Co'))\n    ((8232, 8233), (57344, 63743), (983040, 1048573), (1048576, 1114109))\n    \"\"\"\n    key = tuple(key)\n    # ignore ordering on the cache key to increase potential cache hits.\n    cache_key = frozenset(key)\n    context = _current_build_context.value\n    if context is None or not context.data.provider.avoid_realization:\n        try:\n            return category_index_cache[cache_key]\n        except KeyError:\n            pass\n    elif not key:  # pragma: no cover  # only on alternative backends\n        return ()\n    assert key\n    if set(key) == set(categories()):\n        result = IntervalSet([(0, sys.maxunicode)])\n    else:\n        result = IntervalSet(_query_for_key(key[:-1])).union(\n            IntervalSet(charmap()[key[-1]])\n        )\n    assert isinstance(result, IntervalSet)\n    if context is None or not context.data.provider.avoid_realization:\n        category_index_cache[cache_key] = result.intervals\n    return result.intervals\n\n\nlimited_category_index_cache: dict[\n    tuple[CategoriesTuple, int, int, IntervalsT, IntervalsT], IntervalSet\n] = {}\n\n\ndef query(\n    *,\n    categories: Categories | None = None,\n    min_codepoint: int | None = None,\n    max_codepoint: int | None = None,\n    include_characters: Collection[str] = \"\",\n    exclude_characters: Collection[str] = \"\",\n) -> IntervalSet:\n    \"\"\"Return a tuple of intervals covering the codepoints for all characters\n    that meet the criteria.\n\n    >>> query()\n    ((0, 1114111),)\n    >>> query(min_codepoint=0, max_codepoint=128)\n    ((0, 128),)\n    >>> query(min_codepoint=0, max_codepoint=128, categories=['Lu'])\n    ((65, 90),)\n    >>> query(min_codepoint=0, max_codepoint=128, categories=['Lu'],\n    ...       include_characters='☃')\n    ((65, 90), (9731, 9731))\n    \"\"\"\n    if min_codepoint is None:\n        min_codepoint = 0\n    if max_codepoint is None:\n        max_codepoint = sys.maxunicode\n    catkey = _category_key(categories)\n    character_intervals = IntervalSet.from_string(\"\".join(include_characters))\n    exclude_intervals = IntervalSet.from_string(\"\".join(exclude_characters))\n    qkey = (\n        catkey,\n        min_codepoint,\n        max_codepoint,\n        character_intervals.intervals,\n        exclude_intervals.intervals,\n    )\n    context = _current_build_context.value\n    if context is None or not context.data.provider.avoid_realization:\n        try:\n            return limited_category_index_cache[qkey]\n        except KeyError:\n            pass\n    base = _query_for_key(catkey)\n    result = []\n    for u, v in base:\n        if v >= min_codepoint and u <= max_codepoint:\n            result.append((max(u, min_codepoint), min(v, max_codepoint)))\n    result = (IntervalSet(result) | character_intervals) - exclude_intervals\n    if context is None or not context.data.provider.avoid_realization:\n        limited_category_index_cache[qkey] = result\n    return result\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/compat.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport codecs\nimport copy\nimport dataclasses\nimport inspect\nimport itertools\nimport platform\nimport sys\nimport sysconfig\nimport typing\nfrom functools import partial\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    ForwardRef,\n    Optional,\n    TypedDict as TypedDict,\n    get_args,\n)\n\nif sys.version_info >= (3, 11):\n    BaseExceptionGroup = BaseExceptionGroup  # noqa: F821\n    ExceptionGroup = ExceptionGroup  # noqa: F821\nelse:  # pragma: no cover\n    from exceptiongroup import (\n        BaseExceptionGroup as BaseExceptionGroup,\n        ExceptionGroup as ExceptionGroup,\n    )\nif TYPE_CHECKING:\n    from typing_extensions import (\n        NotRequired as NotRequired,\n        TypedDict as TypedDict,\n        override as override,\n    )\n\n    from hypothesis.internal.conjecture.engine import ConjectureRunner\nelse:\n    # In order to use NotRequired, we need the version of TypedDict included in Python 3.11+.\n    if sys.version_info[:2] >= (3, 11):\n        from typing import NotRequired as NotRequired, TypedDict as TypedDict\n    else:  # pragma: no cover\n        try:\n            from typing_extensions import (\n                NotRequired as NotRequired,\n                TypedDict as TypedDict,\n            )\n        except ImportError:\n            # We can use the old TypedDict from Python 3.8+ at runtime.\n            class NotRequired:\n                \"\"\"A runtime placeholder for the NotRequired type, which is not available in Python <3.11.\"\"\"\n\n                def __class_getitem__(cls, item):\n                    return cls\n\n    try:\n        from typing import (\n            override as override,\n        )\n    except ImportError:  # pragma: no cover\n        try:\n            from typing_extensions import (\n                override as override,\n            )\n        except ImportError:\n            override = lambda f: f\n\nPYPY = platform.python_implementation() == \"PyPy\"\nGRAALPY = platform.python_implementation() == \"GraalVM\"\nWINDOWS = platform.system() == \"Windows\"\n# First defined in CPython 3.13, defaults to False\nFREE_THREADED_CPYTHON = bool(sysconfig.get_config_var(\"Py_GIL_DISABLED\"))\n\n\ndef add_note(exc, note):\n    try:\n        exc.add_note(note)\n    except AttributeError:  # pragma: no cover\n        if not hasattr(exc, \"__notes__\"):\n            try:\n                exc.__notes__ = []\n            except AttributeError:\n                return  # give up, might be e.g. a frozen dataclass\n        exc.__notes__.append(note)\n\n\ndef escape_unicode_characters(s: str) -> str:\n    return codecs.encode(s, \"unicode_escape\").decode(\"ascii\")\n\n\ndef int_from_bytes(data: bytes | bytearray) -> int:\n    return int.from_bytes(data, \"big\")\n\n\ndef int_to_bytes(i: int, size: int) -> bytes:\n    return i.to_bytes(size, \"big\")\n\n\ndef int_to_byte(i: int) -> bytes:\n    return bytes([i])\n\n\ndef is_typed_named_tuple(cls: type) -> bool:\n    \"\"\"Return True if cls is probably a subtype of `typing.NamedTuple`.\n\n    Unfortunately types created with `class T(NamedTuple):` actually\n    subclass `tuple` directly rather than NamedTuple.  This is annoying,\n    and means we just have to hope that nobody defines a different tuple\n    subclass with similar attributes.\n    \"\"\"\n    return (\n        issubclass(cls, tuple)\n        and hasattr(cls, \"_fields\")\n        and (hasattr(cls, \"_field_types\") or hasattr(cls, \"__annotations__\"))\n    )\n\n\ndef _hint_and_args(x):\n    return (x, *get_args(x))\n\n\ndef get_type_hints(thing: object) -> dict[str, Any]:\n    \"\"\"Like the typing version, but tries harder and never errors.\n\n    Tries harder: if the thing to inspect is a class but typing.get_type_hints\n    raises an error or returns no hints, then this function will try calling it\n    on the __init__ method. This second step often helps with user-defined\n    classes on older versions of Python. The third step we take is trying\n    to fetch types from the __signature__ property.\n    They override any other ones we found earlier.\n\n    Never errors: instead of raising TypeError for uninspectable objects, or\n    NameError for unresolvable forward references, just return an empty dict.\n    \"\"\"\n    if isinstance(thing, partial):\n        from hypothesis.internal.reflection import get_signature\n\n        bound = set(get_signature(thing.func).parameters).difference(\n            get_signature(thing).parameters\n        )\n        return {k: v for k, v in get_type_hints(thing.func).items() if k not in bound}\n\n    try:\n        hints = typing.get_type_hints(thing, include_extras=True)\n    except (AttributeError, TypeError, NameError):  # pragma: no cover\n        hints = {}\n\n    if inspect.isclass(thing):\n        try:\n            hints.update(typing.get_type_hints(thing.__init__, include_extras=True))\n        except (TypeError, NameError, AttributeError):\n            pass\n\n    try:\n        if hasattr(thing, \"__signature__\"):\n            # It is possible for the signature and annotations attributes to\n            # differ on an object due to renamed arguments.\n            from hypothesis.internal.reflection import get_signature\n            from hypothesis.strategies._internal.types import is_a_type\n\n            vkinds = (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD)\n            for p in get_signature(thing).parameters.values():\n                if (\n                    p.kind not in vkinds\n                    and is_a_type(p.annotation)\n                    and p.annotation is not p.empty\n                ):\n                    p_hint = p.annotation\n\n                    # Defer to `get_type_hints` if signature annotation is, or\n                    # contains, a forward reference that is otherwise resolved.\n                    if any(\n                        isinstance(sig_hint, ForwardRef)\n                        and not isinstance(hint, ForwardRef)\n                        for sig_hint, hint in zip(\n                            _hint_and_args(p.annotation),\n                            _hint_and_args(hints.get(p.name, Any)),\n                            strict=False,\n                        )\n                    ):\n                        p_hint = hints[p.name]\n                    if p.default is None:\n                        hints[p.name] = p_hint | None\n                    else:\n                        hints[p.name] = p_hint\n    except (AttributeError, TypeError, NameError):  # pragma: no cover\n        pass\n\n    return hints\n\n\n# Under Python 2, math.floor and math.ceil returned floats, which cannot\n# represent large integers - eg `float(2**53) == float(2**53 + 1)`.\n# We therefore implement them entirely in (long) integer operations.\n# We still use the same trick on Python 3, because Numpy values and other\n# custom __floor__ or __ceil__ methods may convert via floats.\n# See issue #1667, Numpy issue 9068.\ndef floor(x):\n    y = int(x)\n    if y != x and x < 0:\n        return y - 1\n    return y\n\n\ndef ceil(x):\n    y = int(x)\n    if y != x and x > 0:\n        return y + 1\n    return y\n\n\ndef extract_bits(x: int, /, width: int | None = None) -> list[int]:\n    assert x >= 0\n    result = []\n    while x:\n        result.append(x & 1)\n        x >>= 1\n    if width is not None:\n        result = (result + [0] * width)[:width]\n    result.reverse()\n    return result\n\n\n# int.bit_count was added in python 3.10\ntry:\n    bit_count = int.bit_count\nexcept AttributeError:  # pragma: no cover\n    bit_count = lambda self: sum(extract_bits(abs(self)))\n\n\ndef bad_django_TestCase(runner: Optional[\"ConjectureRunner\"]) -> bool:\n    if runner is None or \"django.test\" not in sys.modules:\n        return False\n    else:  # pragma: no cover\n        if not isinstance(runner, sys.modules[\"django.test\"].TransactionTestCase):\n            return False\n\n        from hypothesis.extra.django._impl import HypothesisTestCase\n\n        return not isinstance(runner, HypothesisTestCase)\n\n\n# see issue #3812\nif sys.version_info[:2] < (3, 12):\n\n    def _asdict_inner(obj, dict_factory):\n        if dataclasses._is_dataclass_instance(obj):\n            return dict_factory(\n                (f.name, _asdict_inner(getattr(obj, f.name), dict_factory))\n                for f in dataclasses.fields(obj)\n            )\n        elif isinstance(obj, tuple) and hasattr(obj, \"_fields\"):\n            return type(obj)(*[_asdict_inner(v, dict_factory) for v in obj])\n        elif isinstance(obj, (list, tuple)):\n            return type(obj)(_asdict_inner(v, dict_factory) for v in obj)\n        elif isinstance(obj, dict):\n            if hasattr(type(obj), \"default_factory\"):\n                result = type(obj)(obj.default_factory)\n                for k, v in obj.items():\n                    result[_asdict_inner(k, dict_factory)] = _asdict_inner(\n                        v, dict_factory\n                    )\n                return result\n            return type(obj)(\n                (_asdict_inner(k, dict_factory), _asdict_inner(v, dict_factory))\n                for k, v in obj.items()\n            )\n        else:\n            return copy.deepcopy(obj)\n\n    def dataclass_asdict(obj, *, dict_factory=dict):\n        \"\"\"\n        A vendored variant of dataclasses.asdict. Includes the bugfix for\n        defaultdicts (cpython/32056) for all versions. See also issues/3812.\n\n        This should be removed whenever we drop support for 3.11. We can use the\n        standard dataclasses.asdict after that point.\n        \"\"\"\n        if not dataclasses._is_dataclass_instance(obj):  # pragma: no cover\n            raise TypeError(\"asdict() should be called on dataclass instances\")\n        return _asdict_inner(obj, dict_factory)\n\nelse:  # pragma: no cover\n    dataclass_asdict = dataclasses.asdict\n\n\nif sys.version_info[:2] < (3, 13):\n    # batched was added in 3.12, strict flag in 3.13\n    # copied from 3.13 docs reference implementation\n\n    def batched(iterable, n, *, strict=False):\n        if n < 1:\n            raise ValueError(\"n must be at least one\")\n        iterator = iter(iterable)\n        while batch := tuple(itertools.islice(iterator, n)):\n            if strict and len(batch) != n:  # pragma: no cover\n                raise ValueError(\"batched(): incomplete batch\")\n            yield batch\n\nelse:  # pragma: no cover\n    batched = itertools.batched\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/choice.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nfrom collections.abc import Callable, Hashable, Iterable, Sequence\nfrom dataclasses import dataclass\nfrom typing import (\n    Literal,\n    TypeAlias,\n    TypedDict,\n    TypeVar,\n    cast,\n)\n\nfrom hypothesis.errors import ChoiceTooLarge\nfrom hypothesis.internal.conjecture.floats import float_to_lex, lex_to_float\nfrom hypothesis.internal.conjecture.utils import identity\nfrom hypothesis.internal.floats import float_to_int, make_float_clamper, sign_aware_lte\nfrom hypothesis.internal.intervalsets import IntervalSet\n\nT = TypeVar(\"T\")\n\n\nclass IntegerConstraints(TypedDict):\n    min_value: int | None\n    max_value: int | None\n    weights: dict[int, float] | None\n    shrink_towards: int\n\n\nclass FloatConstraints(TypedDict):\n    min_value: float\n    max_value: float\n    allow_nan: bool\n    smallest_nonzero_magnitude: float\n\n\nclass StringConstraints(TypedDict):\n    intervals: IntervalSet\n    min_size: int\n    max_size: int\n\n\nclass BytesConstraints(TypedDict):\n    min_size: int\n    max_size: int\n\n\nclass BooleanConstraints(TypedDict):\n    p: float\n\n\nChoiceT: TypeAlias = int | str | bool | float | bytes\nChoiceConstraintsT: TypeAlias = (\n    IntegerConstraints\n    | FloatConstraints\n    | StringConstraints\n    | BytesConstraints\n    | BooleanConstraints\n)\nChoiceTypeT: TypeAlias = Literal[\"integer\", \"string\", \"boolean\", \"float\", \"bytes\"]\nChoiceKeyT: TypeAlias = (\n    int | str | bytes | tuple[Literal[\"bool\"], bool] | tuple[Literal[\"float\"], int]\n)\n\n\n@dataclass(slots=True, frozen=False)\nclass ChoiceTemplate:\n    type: Literal[\"simplest\"]\n    count: int | None\n\n    def __post_init__(self) -> None:\n        if self.count is not None:\n            assert self.count > 0\n\n\n@dataclass(slots=True, frozen=False)\nclass ChoiceNode:\n    type: ChoiceTypeT\n    value: ChoiceT\n    constraints: ChoiceConstraintsT\n    was_forced: bool\n    index: int | None = None\n\n    def copy(\n        self,\n        *,\n        with_value: ChoiceT | None = None,\n        with_constraints: ChoiceConstraintsT | None = None,\n    ) -> \"ChoiceNode\":\n        # we may want to allow this combination in the future, but for now it's\n        # a footgun.\n        if self.was_forced:\n            assert with_value is None, \"modifying a forced node doesn't make sense\"\n        # explicitly not copying index. node indices are only assigned via\n        # ExampleRecord. This prevents footguns with relying on stale indices\n        # after copying.\n        return ChoiceNode(\n            type=self.type,\n            value=self.value if with_value is None else with_value,\n            constraints=(\n                self.constraints if with_constraints is None else with_constraints\n            ),\n            was_forced=self.was_forced,\n        )\n\n    @property\n    def trivial(self) -> bool:\n        \"\"\"\n        A node is trivial if it cannot be simplified any further. This does not\n        mean that modifying a trivial node can't produce simpler test cases when\n        viewing the tree as a whole. Just that when viewing this node in\n        isolation, this is the simplest the node can get.\n        \"\"\"\n        if self.was_forced:\n            return True\n\n        if self.type != \"float\":\n            zero_value = choice_from_index(0, self.type, self.constraints)\n            return choice_equal(self.value, zero_value)\n        else:\n            constraints = cast(FloatConstraints, self.constraints)\n            min_value = constraints[\"min_value\"]\n            max_value = constraints[\"max_value\"]\n            shrink_towards = 0.0\n\n            if min_value == -math.inf and max_value == math.inf:\n                return choice_equal(self.value, shrink_towards)\n\n            if (\n                not math.isinf(min_value)\n                and not math.isinf(max_value)\n                and math.ceil(min_value) <= math.floor(max_value)\n            ):\n                # the interval contains an integer. the simplest integer is the\n                # one closest to shrink_towards\n                shrink_towards = max(math.ceil(min_value), shrink_towards)\n                shrink_towards = min(math.floor(max_value), shrink_towards)\n                return choice_equal(self.value, float(shrink_towards))\n\n            # the real answer here is \"the value in [min_value, max_value] with\n            # the lowest denominator when represented as a fraction\".\n            # It would be good to compute this correctly in the future, but it's\n            # also not incorrect to be conservative here.\n            return False\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, ChoiceNode):\n            return NotImplemented\n\n        return (\n            self.type == other.type\n            and choice_equal(self.value, other.value)\n            and choice_constraints_equal(self.type, self.constraints, other.constraints)\n            and self.was_forced == other.was_forced\n        )\n\n    def __hash__(self) -> int:\n        return hash(\n            (\n                self.type,\n                choice_key(self.value),\n                choice_constraints_key(self.type, self.constraints),\n                self.was_forced,\n            )\n        )\n\n    def __repr__(self) -> str:\n        forced_marker = \" [forced]\" if self.was_forced else \"\"\n        return f\"{self.type} {self.value!r}{forced_marker} {self.constraints!r}\"\n\n\ndef _size_to_index(size: int, *, alphabet_size: int) -> int:\n    # this is the closed form of this geometric series:\n    # for i in range(size):\n    #     index += alphabet_size**i\n    if alphabet_size <= 0:\n        assert size == 0\n        return 0\n    if alphabet_size == 1:\n        return size\n    v = (alphabet_size**size - 1) // (alphabet_size - 1)\n    # mypy thinks (m: int) // (n: int) -> Any. assert it back to int.\n    return cast(int, v)\n\n\ndef _index_to_size(index: int, alphabet_size: int) -> int:\n    if alphabet_size == 0:\n        return 0\n    elif alphabet_size == 1:\n        # there is only one string of each size, so the size is equal to its\n        # ordering.\n        return index\n\n    # the closed-form inverse of _size_to_index is\n    #   size = math.floor(math.log(index * (alphabet_size - 1) + 1, alphabet_size))\n    # which is fast, but suffers from float precision errors. As performance is\n    # relatively critical here, we'll use this formula by default, but fall back to\n    # a much slower integer-only logarithm when the calculation is too close for\n    # comfort.\n    total = index * (alphabet_size - 1) + 1\n    size = math.log(total, alphabet_size)\n\n    # if this computation is close enough that it could have been affected by\n    # floating point errors, use a much slower integer-only logarithm instead,\n    # which is guaranteed to be precise.\n    if 0 < math.ceil(size) - size < 1e-7:\n        s = 0\n        while total >= alphabet_size:\n            total //= alphabet_size\n            s += 1\n        return s\n    return math.floor(size)\n\n\ndef collection_index(\n    choice: Sequence[T],\n    *,\n    min_size: int,\n    alphabet_size: int,\n    to_order: Callable[[T], int],\n) -> int:\n    # Collections are ordered by counting the number of values of each size,\n    # starting with min_size. alphabet_size indicates how many options there\n    # are for a single element. to_order orders an element by returning an n ≥ 0.\n\n    # we start by adding the size to the index, relative to min_size.\n    index = _size_to_index(len(choice), alphabet_size=alphabet_size) - _size_to_index(\n        min_size, alphabet_size=alphabet_size\n    )\n    # We then add each element c to the index, starting from the end (so \"ab\" is\n    # simpler than \"ba\"). Each loop takes c at position i in the sequence and\n    # computes the number of sequences of size i which come before it in the ordering.\n\n    # this running_exp computation is equivalent to doing\n    #   index += (alphabet_size**i) * n\n    # but reuses intermediate exponentiation steps for efficiency.\n    running_exp = 1\n    for c in reversed(choice):\n        index += running_exp * to_order(c)\n        running_exp *= alphabet_size\n    return index\n\n\ndef collection_value(\n    index: int,\n    *,\n    min_size: int,\n    alphabet_size: int,\n    from_order: Callable[[int], T],\n) -> list[T]:\n    from hypothesis.internal.conjecture.engine import BUFFER_SIZE\n\n    # this function is probably easiest to make sense of as an inverse of\n    # collection_index, tracking ~corresponding lines of code between the two.\n\n    index += _size_to_index(min_size, alphabet_size=alphabet_size)\n    size = _index_to_size(index, alphabet_size=alphabet_size)\n    # index -> value computation can be arbitrarily expensive for arbitrarily\n    # large min_size collections. short-circuit if the resulting size would be\n    # obviously-too-large. callers will generally turn this into a .mark_overrun().\n    if size >= BUFFER_SIZE:\n        raise ChoiceTooLarge\n\n    # subtract out the amount responsible for the size\n    index -= _size_to_index(size, alphabet_size=alphabet_size)\n    vals: list[T] = []\n    for i in reversed(range(size)):\n        # optimization for common case when we hit index 0. Exponentiation\n        # on large integers is expensive!\n        if index == 0:\n            n = 0\n        else:\n            n = index // (alphabet_size**i)\n            # subtract out the nearest multiple of alphabet_size**i\n            index -= n * (alphabet_size**i)\n        vals.append(from_order(n))\n    return vals\n\n\ndef zigzag_index(value: int, *, shrink_towards: int) -> int:\n    # value | 0  1 -1  2 -2  3 -3  4\n    # index | 0  1  2  3  4  5  6  7\n    index = 2 * abs(shrink_towards - value)\n    if value > shrink_towards:\n        index -= 1\n    return index\n\n\ndef zigzag_value(index: int, *, shrink_towards: int) -> int:\n    assert index >= 0\n    # count how many \"steps\" away from shrink_towards we are.\n    n = (index + 1) // 2\n    # now check if we're stepping up or down from shrink_towards.\n    if (index % 2) == 0:\n        n *= -1\n    return shrink_towards + n\n\n\ndef choice_to_index(choice: ChoiceT, constraints: ChoiceConstraintsT) -> int:\n    # This function takes a choice in the choice sequence and returns the\n    # complexity index of that choice from among its possible values, where 0\n    # is the simplest.\n    #\n    # Note that the index of a choice depends on its constraints. The simplest value\n    # (at index 0) for {\"min_value\": None, \"max_value\": None} is 0, while for\n    # {\"min_value\": 1, \"max_value\": None} the simplest value is 1.\n    #\n    # choice_from_index inverts this function. An invariant on both functions is\n    # that they must be injective. Unfortunately, floats do not currently respect\n    # this. That's not *good*, but nothing has blown up - yet. And ordering\n    # floats in a sane manner is quite hard, so I've left it for another day.\n\n    if isinstance(choice, int) and not isinstance(choice, bool):\n        # Let a = shrink_towards.\n        # * Unbounded: Ordered by (|a - x|, sgn(a - x)). Think of a zigzag.\n        #   [a, a + 1, a - 1, a + 2, a - 2, ...]\n        # * Semi-bounded: Same as unbounded, except stop on one side when you hit\n        #   {min, max}_value. so min_value=-1 a=0 has order\n        #   [0, 1, -1, 2, 3, 4, ...]\n        # * Bounded: Same as unbounded and semibounded, except stop on each side\n        #   when you hit {min, max}_value.\n        #\n        # To simplify and gain intuition about this ordering, you can think about\n        # the most common case where 0 is first (a = 0). We deviate from this only\n        # rarely, e.g. for datetimes, where we generally want year 2000 to be\n        # simpler than year 0.\n        constraints = cast(IntegerConstraints, constraints)\n        shrink_towards = constraints[\"shrink_towards\"]\n        min_value = constraints[\"min_value\"]\n        max_value = constraints[\"max_value\"]\n\n        if min_value is not None:\n            shrink_towards = max(min_value, shrink_towards)\n        if max_value is not None:\n            shrink_towards = min(max_value, shrink_towards)\n\n        if min_value is None and max_value is None:\n            # case: unbounded\n            return zigzag_index(choice, shrink_towards=shrink_towards)\n        elif min_value is not None and max_value is None:\n            # case: semibounded below\n\n            # min_value = -2\n            # index | 0  1  2  3  4  5  6  7\n            #     v | 0  1 -1  2 -2  3  4  5\n            if abs(choice - shrink_towards) <= (shrink_towards - min_value):\n                return zigzag_index(choice, shrink_towards=shrink_towards)\n            return choice - min_value\n        elif max_value is not None and min_value is None:\n            # case: semibounded above\n            if abs(choice - shrink_towards) <= (max_value - shrink_towards):\n                return zigzag_index(choice, shrink_towards=shrink_towards)\n            return max_value - choice\n        else:\n            # case: bounded\n\n            # range = [-2, 5]\n            # shrink_towards = 2\n            # index |  0  1  2  3  4  5  6  7\n            #     v |  2  3  1  4  0  5 -1 -2\n            #\n            # ^ with zero weights at index = [0, 2, 6]\n            # index |  0  1  2  3  4\n            #     v |  3  4  0  5 -2\n\n            assert min_value is not None\n            assert max_value is not None\n            assert constraints[\"weights\"] is None or all(\n                w > 0 for w in constraints[\"weights\"].values()\n            ), \"technically possible but really annoying to support zero weights\"\n\n            # check which side gets exhausted first\n            if (shrink_towards - min_value) < (max_value - shrink_towards):\n                # Below shrink_towards gets exhausted first. Equivalent to\n                # semibounded below\n                if abs(choice - shrink_towards) <= (shrink_towards - min_value):\n                    return zigzag_index(choice, shrink_towards=shrink_towards)\n                return choice - min_value\n            else:\n                # Above shrink_towards gets exhausted first. Equivalent to semibounded\n                # above\n                if abs(choice - shrink_towards) <= (max_value - shrink_towards):\n                    return zigzag_index(choice, shrink_towards=shrink_towards)\n                return max_value - choice\n    elif isinstance(choice, bool):\n        constraints = cast(BooleanConstraints, constraints)\n        # Ordered by [False, True].\n        p = constraints[\"p\"]\n        if not (2 ** (-64) < p < (1 - 2 ** (-64))):\n            # only one option is possible, so whatever it is is first.\n            return 0\n        return int(choice)\n    elif isinstance(choice, bytes):\n        constraints = cast(BytesConstraints, constraints)\n        return collection_index(\n            list(choice),\n            min_size=constraints[\"min_size\"],\n            alphabet_size=2**8,\n            to_order=identity,\n        )\n    elif isinstance(choice, str):\n        constraints = cast(StringConstraints, constraints)\n        intervals = constraints[\"intervals\"]\n        return collection_index(\n            choice,\n            min_size=constraints[\"min_size\"],\n            alphabet_size=len(intervals),\n            to_order=intervals.index_from_char_in_shrink_order,\n        )\n    elif isinstance(choice, float):\n        sign = int(math.copysign(1.0, choice) < 0)\n        return (sign << 64) | float_to_lex(abs(choice))\n    else:\n        raise NotImplementedError\n\n\ndef choice_from_index(\n    index: int, choice_type: ChoiceTypeT, constraints: ChoiceConstraintsT\n) -> ChoiceT:\n    assert index >= 0\n    if choice_type == \"integer\":\n        constraints = cast(IntegerConstraints, constraints)\n        shrink_towards = constraints[\"shrink_towards\"]\n        min_value = constraints[\"min_value\"]\n        max_value = constraints[\"max_value\"]\n\n        if min_value is not None:\n            shrink_towards = max(min_value, shrink_towards)\n        if max_value is not None:\n            shrink_towards = min(max_value, shrink_towards)\n\n        if min_value is None and max_value is None:\n            # case: unbounded\n            return zigzag_value(index, shrink_towards=shrink_towards)\n        elif min_value is not None and max_value is None:\n            # case: semibounded below\n            if index <= zigzag_index(min_value, shrink_towards=shrink_towards):\n                return zigzag_value(index, shrink_towards=shrink_towards)\n            return index + min_value\n        elif max_value is not None and min_value is None:\n            # case: semibounded above\n            if index <= zigzag_index(max_value, shrink_towards=shrink_towards):\n                return zigzag_value(index, shrink_towards=shrink_towards)\n            return max_value - index\n        else:\n            # case: bounded\n            assert min_value is not None\n            assert max_value is not None\n            assert constraints[\"weights\"] is None or all(\n                w > 0 for w in constraints[\"weights\"].values()\n            ), \"possible but really annoying to support zero weights\"\n\n            if (shrink_towards - min_value) < (max_value - shrink_towards):\n                # equivalent to semibounded below case\n                if index <= zigzag_index(min_value, shrink_towards=shrink_towards):\n                    return zigzag_value(index, shrink_towards=shrink_towards)\n                return index + min_value\n            else:\n                # equivalent to semibounded above case\n                if index <= zigzag_index(max_value, shrink_towards=shrink_towards):\n                    return zigzag_value(index, shrink_towards=shrink_towards)\n                return max_value - index\n    elif choice_type == \"boolean\":\n        constraints = cast(BooleanConstraints, constraints)\n        # Ordered by [False, True].\n        p = constraints[\"p\"]\n        only = None\n        if p <= 2 ** (-64):\n            only = False\n        elif p >= (1 - 2 ** (-64)):\n            only = True\n\n        assert index in {0, 1}\n        if only is not None:\n            # only one choice\n            assert index == 0\n            return only\n        return bool(index)\n    elif choice_type == \"bytes\":\n        constraints = cast(BytesConstraints, constraints)\n        value_b = collection_value(\n            index,\n            min_size=constraints[\"min_size\"],\n            alphabet_size=2**8,\n            from_order=identity,\n        )\n        return bytes(value_b)\n    elif choice_type == \"string\":\n        constraints = cast(StringConstraints, constraints)\n        intervals = constraints[\"intervals\"]\n        # _s because mypy is unhappy with reusing different-typed names in branches,\n        # even if the branches are disjoint.\n        value_s = collection_value(\n            index,\n            min_size=constraints[\"min_size\"],\n            alphabet_size=len(intervals),\n            from_order=intervals.char_in_shrink_order,\n        )\n        return \"\".join(value_s)\n    elif choice_type == \"float\":\n        constraints = cast(FloatConstraints, constraints)\n        sign = -1 if index >> 64 else 1\n        result = sign * lex_to_float(index & ((1 << 64) - 1))\n\n        clamper = make_float_clamper(\n            min_value=constraints[\"min_value\"],\n            max_value=constraints[\"max_value\"],\n            smallest_nonzero_magnitude=constraints[\"smallest_nonzero_magnitude\"],\n            allow_nan=constraints[\"allow_nan\"],\n        )\n        return clamper(result)\n    else:\n        raise NotImplementedError\n\n\ndef choice_permitted(choice: ChoiceT, constraints: ChoiceConstraintsT) -> bool:\n    if isinstance(choice, int) and not isinstance(choice, bool):\n        constraints = cast(IntegerConstraints, constraints)\n        min_value = constraints[\"min_value\"]\n        max_value = constraints[\"max_value\"]\n        if min_value is not None and choice < min_value:\n            return False\n        return not (max_value is not None and choice > max_value)\n    elif isinstance(choice, float):\n        constraints = cast(FloatConstraints, constraints)\n        if math.isnan(choice):\n            return constraints[\"allow_nan\"]\n        if 0 < abs(choice) < constraints[\"smallest_nonzero_magnitude\"]:\n            return False\n        return sign_aware_lte(constraints[\"min_value\"], choice) and sign_aware_lte(\n            choice, constraints[\"max_value\"]\n        )\n    elif isinstance(choice, str):\n        constraints = cast(StringConstraints, constraints)\n        if len(choice) < constraints[\"min_size\"]:\n            return False\n        if (\n            constraints[\"max_size\"] is not None\n            and len(choice) > constraints[\"max_size\"]\n        ):\n            return False\n        return all(ord(c) in constraints[\"intervals\"] for c in choice)\n    elif isinstance(choice, bytes):\n        constraints = cast(BytesConstraints, constraints)\n        if len(choice) < constraints[\"min_size\"]:\n            return False\n        return constraints[\"max_size\"] is None or len(choice) <= constraints[\"max_size\"]\n    elif isinstance(choice, bool):\n        constraints = cast(BooleanConstraints, constraints)\n        if constraints[\"p\"] <= 0:\n            return choice is False\n        if constraints[\"p\"] >= 1:\n            return choice is True\n        return True\n    else:\n        raise NotImplementedError(f\"unhandled type {type(choice)} with value {choice}\")\n\n\ndef choices_key(choices: Sequence[ChoiceT]) -> tuple[ChoiceKeyT, ...]:\n    return tuple(choice_key(choice) for choice in choices)\n\n\ndef choice_key(choice: ChoiceT) -> ChoiceKeyT:\n    if isinstance(choice, float):\n        # float_to_int to distinguish -0.0/0.0, signaling/nonsignaling nans, etc,\n        # and then add a \"float\" key to avoid colliding with actual integers.\n        return (\"float\", float_to_int(choice))\n    if isinstance(choice, bool):\n        # avoid choice_key(0) == choice_key(False)\n        return (\"bool\", choice)\n    return choice\n\n\ndef choice_equal(choice1: ChoiceT, choice2: ChoiceT) -> bool:\n    assert type(choice1) is type(choice2), (choice1, choice2)\n    return choice_key(choice1) == choice_key(choice2)\n\n\ndef choice_constraints_equal(\n    choice_type: ChoiceTypeT,\n    constraints1: ChoiceConstraintsT,\n    constraints2: ChoiceConstraintsT,\n) -> bool:\n    return choice_constraints_key(choice_type, constraints1) == choice_constraints_key(\n        choice_type, constraints2\n    )\n\n\ndef choice_constraints_key(\n    choice_type: ChoiceTypeT, constraints: ChoiceConstraintsT\n) -> tuple[Hashable, ...]:\n    if choice_type == \"float\":\n        constraints = cast(FloatConstraints, constraints)\n        return (\n            float_to_int(constraints[\"min_value\"]),\n            float_to_int(constraints[\"max_value\"]),\n            constraints[\"allow_nan\"],\n            constraints[\"smallest_nonzero_magnitude\"],\n        )\n    if choice_type == \"integer\":\n        constraints = cast(IntegerConstraints, constraints)\n        return (\n            constraints[\"min_value\"],\n            constraints[\"max_value\"],\n            None if constraints[\"weights\"] is None else tuple(constraints[\"weights\"]),\n            constraints[\"shrink_towards\"],\n        )\n    return tuple(constraints[key] for key in sorted(constraints))  # type: ignore\n\n\ndef choices_size(choices: Iterable[ChoiceT]) -> int:\n    from hypothesis.database import choices_to_bytes\n\n    return len(choices_to_bytes(choices))\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/data.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nimport time\nfrom collections import defaultdict\nfrom collections.abc import Hashable, Iterable, Iterator, Sequence\nfrom dataclasses import dataclass, field\nfrom enum import IntEnum\nfrom functools import cached_property\nfrom random import Random\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    Literal,\n    NoReturn,\n    TypeAlias,\n    TypeVar,\n    cast,\n    overload,\n)\n\nfrom hypothesis.errors import (\n    CannotProceedScopeT,\n    ChoiceTooLarge,\n    Frozen,\n    InvalidArgument,\n    StopTest,\n)\nfrom hypothesis.internal.cache import LRUCache\nfrom hypothesis.internal.compat import add_note\nfrom hypothesis.internal.conjecture.choice import (\n    BooleanConstraints,\n    BytesConstraints,\n    ChoiceConstraintsT,\n    ChoiceNode,\n    ChoiceT,\n    ChoiceTemplate,\n    ChoiceTypeT,\n    FloatConstraints,\n    IntegerConstraints,\n    StringConstraints,\n    choice_constraints_key,\n    choice_from_index,\n    choice_permitted,\n    choices_size,\n)\nfrom hypothesis.internal.conjecture.junkdrawer import IntList, gc_cumulative_time\nfrom hypothesis.internal.conjecture.providers import (\n    COLLECTION_DEFAULT_MAX_SIZE,\n    HypothesisProvider,\n    PrimitiveProvider,\n)\nfrom hypothesis.internal.conjecture.utils import calc_label_from_name\nfrom hypothesis.internal.escalation import InterestingOrigin\nfrom hypothesis.internal.floats import (\n    SMALLEST_SUBNORMAL,\n    float_to_int,\n    int_to_float,\n    sign_aware_lte,\n)\nfrom hypothesis.internal.intervalsets import IntervalSet\nfrom hypothesis.internal.observability import PredicateCounts\nfrom hypothesis.reporting import debug_report\nfrom hypothesis.utils.conventions import not_set\nfrom hypothesis.utils.deprecation import note_deprecation\nfrom hypothesis.utils.threading import ThreadLocal\n\nif TYPE_CHECKING:\n    from hypothesis.strategies import SearchStrategy\n    from hypothesis.strategies._internal.core import DataObject\n    from hypothesis.strategies._internal.random import RandomState\n    from hypothesis.strategies._internal.strategies import Ex\n\n\ndef __getattr__(name: str) -> Any:\n    if name == \"AVAILABLE_PROVIDERS\":\n        from hypothesis.internal.conjecture.providers import AVAILABLE_PROVIDERS\n\n        note_deprecation(\n            \"hypothesis.internal.conjecture.data.AVAILABLE_PROVIDERS has been moved to \"\n            \"hypothesis.internal.conjecture.providers.AVAILABLE_PROVIDERS.\",\n            since=\"2025-01-25\",\n            has_codemod=False,\n            stacklevel=1,\n        )\n        return AVAILABLE_PROVIDERS\n\n    raise AttributeError(\n        f\"Module 'hypothesis.internal.conjecture.data' has no attribute {name}\"\n    )\n\n\nT = TypeVar(\"T\")\nTargetObservations = dict[str, int | float]\n# index, choice_type, constraints, forced value\nMisalignedAt: TypeAlias = tuple[int, ChoiceTypeT, ChoiceConstraintsT, ChoiceT | None]\n\nTOP_LABEL = calc_label_from_name(\"top\")\nMAX_DEPTH = 100\n\nthreadlocal = ThreadLocal(global_test_counter=int)\n\n\nclass Status(IntEnum):\n    OVERRUN = 0\n    INVALID = 1\n    VALID = 2\n    INTERESTING = 3\n\n    def __repr__(self) -> str:\n        return f\"Status.{self.name}\"\n\n\n@dataclass(slots=True, frozen=True)\nclass StructuralCoverageTag:\n    label: int\n\n\nSTRUCTURAL_COVERAGE_CACHE: dict[int, StructuralCoverageTag] = {}\n\n\ndef structural_coverage(label: int) -> StructuralCoverageTag:\n    try:\n        return STRUCTURAL_COVERAGE_CACHE[label]\n    except KeyError:\n        return STRUCTURAL_COVERAGE_CACHE.setdefault(label, StructuralCoverageTag(label))\n\n\n# This cache can be quite hot and so we prefer LRUCache over LRUReusedCache for\n# performance. We lose scan resistance, but that's probably fine here.\nPOOLED_CONSTRAINTS_CACHE: LRUCache[tuple[Any, ...], ChoiceConstraintsT] = LRUCache(4096)\n\n\nclass Span:\n    \"\"\"A span tracks the hierarchical structure of choices within a single test run.\n\n    Spans are created to mark regions of the choice sequence that are\n    logically related to each other. For instance, Hypothesis tracks:\n    - A single top-level span for the entire choice sequence\n    - A span for the choices made by each strategy\n    - Some strategies define additional spans within their choices. For instance,\n      st.lists() tracks the \"should add another element\" choice and the \"add\n      another element\" choices as separate spans.\n\n    Spans provide useful information to the shrinker, mutator, targeted PBT,\n    and other subsystems of Hypothesis.\n\n    Rather than store each ``Span`` as a rich object, it is actually\n    just an index into the ``Spans`` class defined below. This has two\n    purposes: Firstly, for most properties of spans we will never need\n    to allocate storage at all, because most properties are not used on\n    most spans. Secondly, by storing the spans as compact lists\n    of integers, we save a considerable amount of space compared to\n    Python's normal object size.\n\n    This does have the downside that it increases the amount of allocation\n    we do, and slows things down as a result, in some usage patterns because\n    we repeatedly allocate the same Span or int objects, but it will\n    often dramatically reduce our memory usage, so is worth it.\n    \"\"\"\n\n    __slots__ = (\"index\", \"owner\")\n\n    def __init__(self, owner: \"Spans\", index: int) -> None:\n        self.owner = owner\n        self.index = index\n\n    def __eq__(self, other: object) -> bool:\n        if self is other:\n            return True\n        if not isinstance(other, Span):\n            return NotImplemented\n        return (self.owner is other.owner) and (self.index == other.index)\n\n    def __ne__(self, other: object) -> bool:\n        if self is other:\n            return False\n        if not isinstance(other, Span):\n            return NotImplemented\n        return (self.owner is not other.owner) or (self.index != other.index)\n\n    def __repr__(self) -> str:\n        return f\"spans[{self.index}]\"\n\n    @property\n    def label(self) -> int:\n        \"\"\"A label is an opaque value that associates each span with its\n        approximate origin, such as a particular strategy class or a particular\n        kind of draw.\"\"\"\n        return self.owner.labels[self.owner.label_indices[self.index]]\n\n    @property\n    def parent(self) -> int | None:\n        \"\"\"The index of the span that this one is nested directly within.\"\"\"\n        if self.index == 0:\n            return None\n        return self.owner.parentage[self.index]\n\n    @property\n    def start(self) -> int:\n        return self.owner.starts[self.index]\n\n    @property\n    def end(self) -> int:\n        return self.owner.ends[self.index]\n\n    @property\n    def depth(self) -> int:\n        \"\"\"\n        Depth of this span in the span tree. The top-level span has a depth of 0.\n        \"\"\"\n        return self.owner.depths[self.index]\n\n    @property\n    def discarded(self) -> bool:\n        \"\"\"True if this is span's ``stop_span`` call had ``discard`` set to\n        ``True``. This means we believe that the shrinker should be able to delete\n        this span completely, without affecting the value produced by its enclosing\n        strategy. Typically set when a rejection sampler decides to reject a\n        generated value and try again.\"\"\"\n        return self.index in self.owner.discarded\n\n    @property\n    def choice_count(self) -> int:\n        \"\"\"The number of choices in this span.\"\"\"\n        return self.end - self.start\n\n    @property\n    def children(self) -> \"list[Span]\":\n        \"\"\"The list of all spans with this as a parent, in increasing index\n        order.\"\"\"\n        return [self.owner[i] for i in self.owner.children[self.index]]\n\n\nclass SpanProperty:\n    \"\"\"There are many properties of spans that we calculate by\n    essentially rerunning the test case multiple times based on the\n    calls which we record in SpanProperty.\n\n    This class defines a visitor, subclasses of which can be used\n    to calculate these properties.\n    \"\"\"\n\n    def __init__(self, spans: \"Spans\"):\n        self.span_stack: list[int] = []\n        self.spans = spans\n        self.span_count = 0\n        self.choice_count = 0\n\n    def run(self) -> Any:\n        \"\"\"Rerun the test case with this visitor and return the\n        results of ``self.finish()``.\"\"\"\n        for record in self.spans.trail:\n            if record == TrailType.STOP_SPAN_DISCARD:\n                self.__pop(discarded=True)\n            elif record == TrailType.STOP_SPAN_NO_DISCARD:\n                self.__pop(discarded=False)\n            elif record == TrailType.CHOICE:\n                self.choice_count += 1\n            else:\n                # everything after TrailType.CHOICE is the label of a span start.\n                self.__push(record - TrailType.CHOICE - 1)\n\n        return self.finish()\n\n    def __push(self, label_index: int) -> None:\n        i = self.span_count\n        assert i < len(self.spans)\n        self.start_span(i, label_index=label_index)\n        self.span_count += 1\n        self.span_stack.append(i)\n\n    def __pop(self, *, discarded: bool) -> None:\n        i = self.span_stack.pop()\n        self.stop_span(i, discarded=discarded)\n\n    def start_span(self, i: int, label_index: int) -> None:\n        \"\"\"Called at the start of each span, with ``i`` the\n        index of the span and ``label_index`` the index of\n        its label in ``self.spans.labels``.\"\"\"\n\n    def stop_span(self, i: int, *, discarded: bool) -> None:\n        \"\"\"Called at the end of each span, with ``i`` the\n        index of the span and ``discarded`` being ``True`` if ``stop_span``\n        was called with ``discard=True``.\"\"\"\n\n    def finish(self) -> Any:\n        raise NotImplementedError\n\n\nclass TrailType(IntEnum):\n    STOP_SPAN_DISCARD = 1\n    STOP_SPAN_NO_DISCARD = 2\n    CHOICE = 3\n    # every trail element larger than TrailType.CHOICE is the label of a span\n    # start, offset by its index. So the first span label is stored as 4, the\n    # second as 5, etc, regardless of its actual integer label.\n\n\nclass SpanRecord:\n    \"\"\"Records the series of ``start_span``, ``stop_span``, and\n    ``draw_bits`` calls so that these may be stored in ``Spans`` and\n    replayed when we need to know about the structure of individual\n    ``Span`` objects.\n\n    Note that there is significant similarity between this class and\n    ``DataObserver``, and the plan is to eventually unify them, but\n    they currently have slightly different functions and implementations.\n    \"\"\"\n\n    def __init__(self) -> None:\n        self.labels: list[int] = []\n        self.__index_of_labels: dict[int, int] | None = {}\n        self.trail = IntList()\n        self.nodes: list[ChoiceNode] = []\n\n    def freeze(self) -> None:\n        self.__index_of_labels = None\n\n    def record_choice(self) -> None:\n        self.trail.append(TrailType.CHOICE)\n\n    def start_span(self, label: int) -> None:\n        assert self.__index_of_labels is not None\n        try:\n            i = self.__index_of_labels[label]\n        except KeyError:\n            i = self.__index_of_labels.setdefault(label, len(self.labels))\n            self.labels.append(label)\n        self.trail.append(TrailType.CHOICE + 1 + i)\n\n    def stop_span(self, *, discard: bool) -> None:\n        if discard:\n            self.trail.append(TrailType.STOP_SPAN_DISCARD)\n        else:\n            self.trail.append(TrailType.STOP_SPAN_NO_DISCARD)\n\n\nclass _starts_and_ends(SpanProperty):\n    def __init__(self, spans: \"Spans\") -> None:\n        super().__init__(spans)\n        self.starts = IntList.of_length(len(self.spans))\n        self.ends = IntList.of_length(len(self.spans))\n\n    def start_span(self, i: int, label_index: int) -> None:\n        self.starts[i] = self.choice_count\n\n    def stop_span(self, i: int, *, discarded: bool) -> None:\n        self.ends[i] = self.choice_count\n\n    def finish(self) -> tuple[IntList, IntList]:\n        return (self.starts, self.ends)\n\n\nclass _discarded(SpanProperty):\n    def __init__(self, spans: \"Spans\") -> None:\n        super().__init__(spans)\n        self.result: set[int] = set()\n\n    def finish(self) -> frozenset[int]:\n        return frozenset(self.result)\n\n    def stop_span(self, i: int, *, discarded: bool) -> None:\n        if discarded:\n            self.result.add(i)\n\n\nclass _parentage(SpanProperty):\n    def __init__(self, spans: \"Spans\") -> None:\n        super().__init__(spans)\n        self.result = IntList.of_length(len(self.spans))\n\n    def stop_span(self, i: int, *, discarded: bool) -> None:\n        if i > 0:\n            self.result[i] = self.span_stack[-1]\n\n    def finish(self) -> IntList:\n        return self.result\n\n\nclass _depths(SpanProperty):\n    def __init__(self, spans: \"Spans\") -> None:\n        super().__init__(spans)\n        self.result = IntList.of_length(len(self.spans))\n\n    def start_span(self, i: int, label_index: int) -> None:\n        self.result[i] = len(self.span_stack)\n\n    def finish(self) -> IntList:\n        return self.result\n\n\nclass _label_indices(SpanProperty):\n    def __init__(self, spans: \"Spans\") -> None:\n        super().__init__(spans)\n        self.result = IntList.of_length(len(self.spans))\n\n    def start_span(self, i: int, label_index: int) -> None:\n        self.result[i] = label_index\n\n    def finish(self) -> IntList:\n        return self.result\n\n\nclass _mutator_groups(SpanProperty):\n    def __init__(self, spans: \"Spans\") -> None:\n        super().__init__(spans)\n        self.groups: dict[int, set[tuple[int, int]]] = defaultdict(set)\n\n    def start_span(self, i: int, label_index: int) -> None:\n        # TODO should we discard start == end cases? occurs for eg st.data()\n        # which is conditionally or never drawn from. arguably swapping\n        # nodes with the empty list is a useful mutation enabled by start == end?\n        key = (self.spans[i].start, self.spans[i].end)\n        self.groups[label_index].add(key)\n\n    def finish(self) -> Iterable[set[tuple[int, int]]]:\n        # Discard groups with only one span, since the mutator can't\n        # do anything useful with them.\n        return [g for g in self.groups.values() if len(g) >= 2]\n\n\nclass Spans:\n    \"\"\"A lazy collection of ``Span`` objects, derived from\n    the record of recorded behaviour in ``SpanRecord``.\n\n    Behaves logically as if it were a list of ``Span`` objects,\n    but actually mostly exists as a compact store of information\n    for them to reference into. All properties on here are best\n    understood as the backing storage for ``Span`` and are\n    described there.\n    \"\"\"\n\n    def __init__(self, record: SpanRecord) -> None:\n        self.trail = record.trail\n        self.labels = record.labels\n        self.__length = self.trail.count(\n            TrailType.STOP_SPAN_DISCARD\n        ) + record.trail.count(TrailType.STOP_SPAN_NO_DISCARD)\n        self.__children: list[Sequence[int]] | None = None\n\n    @cached_property\n    def starts_and_ends(self) -> tuple[IntList, IntList]:\n        return _starts_and_ends(self).run()\n\n    @property\n    def starts(self) -> IntList:\n        return self.starts_and_ends[0]\n\n    @property\n    def ends(self) -> IntList:\n        return self.starts_and_ends[1]\n\n    @cached_property\n    def discarded(self) -> frozenset[int]:\n        return _discarded(self).run()\n\n    @cached_property\n    def parentage(self) -> IntList:\n        return _parentage(self).run()\n\n    @cached_property\n    def depths(self) -> IntList:\n        return _depths(self).run()\n\n    @cached_property\n    def label_indices(self) -> IntList:\n        return _label_indices(self).run()\n\n    @cached_property\n    def mutator_groups(self) -> list[set[tuple[int, int]]]:\n        return _mutator_groups(self).run()\n\n    @property\n    def children(self) -> list[Sequence[int]]:\n        if self.__children is None:\n            children = [IntList() for _ in range(len(self))]\n            for i, p in enumerate(self.parentage):\n                if i > 0:\n                    children[p].append(i)\n            # Replace empty children lists with a tuple to reduce\n            # memory usage.\n            for i, c in enumerate(children):\n                if not c:\n                    children[i] = ()  # type: ignore\n            self.__children = children  # type: ignore\n        return self.__children  # type: ignore\n\n    def __len__(self) -> int:\n        return self.__length\n\n    def __getitem__(self, i: int) -> Span:\n        n = self.__length\n        if i < -n or i >= n:\n            raise IndexError(f\"Index {i} out of range [-{n}, {n})\")\n        if i < 0:\n            i += n\n        return Span(self, i)\n\n    # not strictly necessary as we have len/getitem, but required for mypy.\n    # https://github.com/python/mypy/issues/9737\n    def __iter__(self) -> Iterator[Span]:\n        for i in range(len(self)):\n            yield self[i]\n\n\nclass _Overrun:\n    status: Status = Status.OVERRUN\n\n    def __repr__(self) -> str:\n        return \"Overrun\"\n\n\nOverrun = _Overrun()\n\n\nclass DataObserver:\n    \"\"\"Observer class for recording the behaviour of a\n    ConjectureData object, primarily used for tracking\n    the behaviour in the tree cache.\"\"\"\n\n    def conclude_test(\n        self,\n        status: Status,\n        interesting_origin: InterestingOrigin | None,\n    ) -> None:\n        \"\"\"Called when ``conclude_test`` is called on the\n        observed ``ConjectureData``, with the same arguments.\n\n        Note that this is called after ``freeze`` has completed.\n        \"\"\"\n\n    def kill_branch(self) -> None:\n        \"\"\"Mark this part of the tree as not worth re-exploring.\"\"\"\n\n    def draw_integer(\n        self, value: int, *, constraints: IntegerConstraints, was_forced: bool\n    ) -> None:\n        pass\n\n    def draw_float(\n        self, value: float, *, constraints: FloatConstraints, was_forced: bool\n    ) -> None:\n        pass\n\n    def draw_string(\n        self, value: str, *, constraints: StringConstraints, was_forced: bool\n    ) -> None:\n        pass\n\n    def draw_bytes(\n        self, value: bytes, *, constraints: BytesConstraints, was_forced: bool\n    ) -> None:\n        pass\n\n    def draw_boolean(\n        self, value: bool, *, constraints: BooleanConstraints, was_forced: bool\n    ) -> None:\n        pass\n\n\n@dataclass(slots=True, frozen=True)\nclass ConjectureResult:\n    \"\"\"Result class storing the parts of ConjectureData that we\n    will care about after the original ConjectureData has outlived its\n    usefulness.\"\"\"\n\n    status: Status\n    interesting_origin: InterestingOrigin | None\n    nodes: tuple[ChoiceNode, ...] = field(repr=False, compare=False)\n    length: int\n    output: str\n    expected_exception: BaseException | None\n    expected_traceback: str | None\n    has_discards: bool\n    target_observations: TargetObservations\n    tags: frozenset[StructuralCoverageTag]\n    spans: Spans = field(repr=False, compare=False)\n    arg_slices: set[tuple[int, int]] = field(repr=False)\n    slice_comments: dict[tuple[int, int], str] = field(repr=False)\n    misaligned_at: MisalignedAt | None = field(repr=False)\n    cannot_proceed_scope: CannotProceedScopeT | None = field(repr=False)\n\n    def as_result(self) -> \"ConjectureResult\":\n        return self\n\n    @property\n    def choices(self) -> tuple[ChoiceT, ...]:\n        return tuple(node.value for node in self.nodes)\n\n\nclass ConjectureData:\n    @classmethod\n    def for_choices(\n        cls,\n        choices: Sequence[ChoiceTemplate | ChoiceT],\n        *,\n        observer: DataObserver | None = None,\n        provider: PrimitiveProvider | type[PrimitiveProvider] = HypothesisProvider,\n        random: Random | None = None,\n    ) -> \"ConjectureData\":\n        from hypothesis.internal.conjecture.engine import choice_count\n\n        return cls(\n            max_choices=choice_count(choices),\n            random=random,\n            prefix=choices,\n            observer=observer,\n            provider=provider,\n        )\n\n    def __init__(\n        self,\n        *,\n        random: Random | None,\n        observer: DataObserver | None = None,\n        provider: PrimitiveProvider | type[PrimitiveProvider] = HypothesisProvider,\n        prefix: Sequence[ChoiceTemplate | ChoiceT] | None = None,\n        max_choices: int | None = None,\n        provider_kw: dict[str, Any] | None = None,\n    ) -> None:\n        from hypothesis.internal.conjecture.engine import BUFFER_SIZE\n\n        if observer is None:\n            observer = DataObserver()\n        if provider_kw is None:\n            provider_kw = {}\n        elif not isinstance(provider, type):\n            raise InvalidArgument(\n                f\"Expected {provider=} to be a class since {provider_kw=} was \"\n                \"passed, but got an instance instead.\"\n            )\n\n        assert isinstance(observer, DataObserver)\n        self.observer = observer\n        self.max_choices = max_choices\n        self.max_length = BUFFER_SIZE\n        self.overdraw = 0\n        self._random = random\n\n        self.length: int = 0\n        self.index: int = 0\n        self.output: str = \"\"\n        self.status: Status = Status.VALID\n        self.frozen: bool = False\n        self.testcounter: int = threadlocal.global_test_counter\n        threadlocal.global_test_counter += 1\n        self.start_time = time.perf_counter()\n        self.gc_start_time = gc_cumulative_time()\n        self.events: dict[str, str | int | float] = {}\n        self.interesting_origin: InterestingOrigin | None = None\n        self.draw_times: dict[str, float] = {}\n        self._stateful_run_times: dict[str, float] = defaultdict(float)\n        self.max_depth: int = 0\n        self.has_discards: bool = False\n\n        self.provider: PrimitiveProvider = (\n            provider(self, **provider_kw) if isinstance(provider, type) else provider\n        )\n        assert isinstance(self.provider, PrimitiveProvider)\n\n        self.__result: ConjectureResult | None = None\n\n        # Observations used for targeted search.  They'll be aggregated in\n        # ConjectureRunner.generate_new_examples and fed to TargetSelector.\n        self.target_observations: TargetObservations = {}\n\n        # Tags which indicate something about which part of the search space\n        # this example is in. These are used to guide generation.\n        self.tags: set[StructuralCoverageTag] = set()\n        self.labels_for_structure_stack: list[set[int]] = []\n\n        # Normally unpopulated but we need this in the niche case\n        # that self.as_result() is Overrun but we still want the\n        # examples for reporting purposes.\n        self.__spans: Spans | None = None\n\n        # We want the top level span to have depth 0, so we start at -1.\n        self.depth: int = -1\n        self.__span_record = SpanRecord()\n\n        # Slice indices for discrete reportable parts that which-parts-matter can\n        # try varying, to report if the minimal example always fails anyway.\n        self.arg_slices: set[tuple[int, int]] = set()\n        self.slice_comments: dict[tuple[int, int], str] = {}\n        self._observability_args: dict[str, Any] = {}\n        self._observability_predicates: defaultdict[str, PredicateCounts] = defaultdict(\n            PredicateCounts\n        )\n\n        self._sampled_from_all_strategies_elements_message: (\n            tuple[str, object] | None\n        ) = None\n        self._shared_strategy_draws: dict[Hashable, tuple[Any, SearchStrategy]] = {}\n        self._shared_data_strategy: DataObject | None = None\n        self._stateful_repr_parts: list[Any] | None = None\n        self.states_for_ids: dict[int, RandomState] | None = None\n        self.seeds_to_states: dict[Any, RandomState] | None = None\n        self.hypothesis_runner: Any = not_set\n\n        self.expected_exception: BaseException | None = None\n        self.expected_traceback: str | None = None\n\n        self.prefix = prefix\n        self.nodes: tuple[ChoiceNode, ...] = ()\n        self.misaligned_at: MisalignedAt | None = None\n        self.cannot_proceed_scope: CannotProceedScopeT | None = None\n        self.start_span(TOP_LABEL)\n\n    def __repr__(self) -> str:\n        return \"ConjectureData(%s, %d choices%s)\" % (\n            self.status.name,\n            len(self.nodes),\n            \", frozen\" if self.frozen else \"\",\n        )\n\n    @property\n    def choices(self) -> tuple[ChoiceT, ...]:\n        return tuple(node.value for node in self.nodes)\n\n    # draw_* functions might be called in one of two contexts: either \"above\" or\n    # \"below\" the choice sequence. For instance, draw_string calls draw_boolean\n    # from ``many`` when calculating the number of characters to return. We do\n    # not want these choices to get written to the choice sequence, because they\n    # are not true choices themselves.\n    #\n    # `observe` formalizes this. The choice will only be written to the choice\n    # sequence if observe is True.\n\n    @overload\n    def _draw(\n        self,\n        choice_type: Literal[\"integer\"],\n        constraints: IntegerConstraints,\n        *,\n        observe: bool,\n        forced: int | None,\n    ) -> int: ...\n\n    @overload\n    def _draw(\n        self,\n        choice_type: Literal[\"float\"],\n        constraints: FloatConstraints,\n        *,\n        observe: bool,\n        forced: float | None,\n    ) -> float: ...\n\n    @overload\n    def _draw(\n        self,\n        choice_type: Literal[\"string\"],\n        constraints: StringConstraints,\n        *,\n        observe: bool,\n        forced: str | None,\n    ) -> str: ...\n\n    @overload\n    def _draw(\n        self,\n        choice_type: Literal[\"bytes\"],\n        constraints: BytesConstraints,\n        *,\n        observe: bool,\n        forced: bytes | None,\n    ) -> bytes: ...\n\n    @overload\n    def _draw(\n        self,\n        choice_type: Literal[\"boolean\"],\n        constraints: BooleanConstraints,\n        *,\n        observe: bool,\n        forced: bool | None,\n    ) -> bool: ...\n\n    def _draw(\n        self,\n        choice_type: ChoiceTypeT,\n        constraints: ChoiceConstraintsT,\n        *,\n        observe: bool,\n        forced: ChoiceT | None,\n    ) -> ChoiceT:\n        # this is somewhat redundant with the length > max_length check at the\n        # end of the function, but avoids trying to use a null self.random when\n        # drawing past the node of a ConjectureData.for_choices data.\n        if self.length == self.max_length:\n            debug_report(f\"overrun because hit {self.max_length=}\")\n            self.mark_overrun()\n        if len(self.nodes) == self.max_choices:\n            debug_report(f\"overrun because hit {self.max_choices=}\")\n            self.mark_overrun()\n\n        if observe and self.prefix is not None and self.index < len(self.prefix):\n            value = self._pop_choice(choice_type, constraints, forced=forced)\n        elif forced is None:\n            value = getattr(self.provider, f\"draw_{choice_type}\")(**constraints)\n\n        if forced is not None:\n            value = forced\n\n        # nan values generated via int_to_float break list membership:\n        #\n        #  >>> n = 18444492273895866368\n        # >>> assert math.isnan(int_to_float(n))\n        # >>> assert int_to_float(n) not in [int_to_float(n)]\n        #\n        # because int_to_float nans are not equal in the sense of either\n        # `a == b` or `a is b`.\n        #\n        # This can lead to flaky errors when collections require unique\n        # floats. What was happening is that in some places we provided math.nan\n        # provide math.nan, and in others we provided\n        # int_to_float(float_to_int(math.nan)), and which one gets used\n        # was not deterministic across test iterations.\n        #\n        # To fix this, *never* provide a nan value which is equal (via `is`) to\n        # another provided nan value. This sacrifices some test power; we should\n        # bring that back (ABOVE the choice sequence layer) in the future.\n        #\n        # See https://github.com/HypothesisWorks/hypothesis/issues/3926.\n        if choice_type == \"float\":\n            assert isinstance(value, float)\n            if math.isnan(value):\n                value = int_to_float(float_to_int(value))\n\n        if observe:\n            was_forced = forced is not None\n            getattr(self.observer, f\"draw_{choice_type}\")(\n                value, constraints=constraints, was_forced=was_forced\n            )\n            size = 0 if self.provider.avoid_realization else choices_size([value])\n            if self.length + size > self.max_length:\n                debug_report(\n                    f\"overrun because {self.length=} + {size=} > {self.max_length=}\"\n                )\n                self.mark_overrun()\n\n            node = ChoiceNode(\n                type=choice_type,\n                value=value,\n                constraints=constraints,\n                was_forced=was_forced,\n                index=len(self.nodes),\n            )\n            self.__span_record.record_choice()\n            self.nodes += (node,)\n            self.length += size\n\n        return value\n\n    def draw_integer(\n        self,\n        min_value: int | None = None,\n        max_value: int | None = None,\n        *,\n        weights: dict[int, float] | None = None,\n        shrink_towards: int = 0,\n        forced: int | None = None,\n        observe: bool = True,\n    ) -> int:\n        # Validate arguments\n        if weights is not None:\n            assert min_value is not None\n            assert max_value is not None\n            assert len(weights) <= 255  # arbitrary practical limit\n            # We can and should eventually support total weights. But this\n            # complicates shrinking as we can no longer assume we can force\n            # a value to the unmapped probability mass if that mass might be 0.\n            assert sum(weights.values()) < 1\n            # similarly, things get simpler if we assume every value is possible.\n            # we'll want to drop this restriction eventually.\n            assert all(w != 0 for w in weights.values())\n\n        if forced is not None and min_value is not None:\n            assert min_value <= forced\n        if forced is not None and max_value is not None:\n            assert forced <= max_value\n\n        constraints: IntegerConstraints = self._pooled_constraints(\n            \"integer\",\n            {\n                \"min_value\": min_value,\n                \"max_value\": max_value,\n                \"weights\": weights,\n                \"shrink_towards\": shrink_towards,\n            },\n        )\n        return self._draw(\"integer\", constraints, observe=observe, forced=forced)\n\n    def draw_float(\n        self,\n        min_value: float = -math.inf,\n        max_value: float = math.inf,\n        *,\n        allow_nan: bool = True,\n        smallest_nonzero_magnitude: float = SMALLEST_SUBNORMAL,\n        # TODO: consider supporting these float widths at the choice sequence\n        # level in the future.\n        # width: Literal[16, 32, 64] = 64,\n        forced: float | None = None,\n        observe: bool = True,\n    ) -> float:\n        assert smallest_nonzero_magnitude > 0\n        assert not math.isnan(min_value)\n        assert not math.isnan(max_value)\n\n        if smallest_nonzero_magnitude == 0.0:  # pragma: no cover\n            raise FloatingPointError(\n                \"Got allow_subnormal=True, but we can't represent subnormal floats \"\n                \"right now, in violation of the IEEE-754 floating-point \"\n                \"specification.  This is usually because something was compiled with \"\n                \"-ffast-math or a similar option, which sets global processor state.  \"\n                \"See https://simonbyrne.github.io/notes/fastmath/ for a more detailed \"\n                \"writeup - and good luck!\"\n            )\n\n        if forced is not None:\n            assert allow_nan or not math.isnan(forced)\n            assert math.isnan(forced) or (\n                sign_aware_lte(min_value, forced) and sign_aware_lte(forced, max_value)\n            )\n\n        constraints: FloatConstraints = self._pooled_constraints(\n            \"float\",\n            {\n                \"min_value\": min_value,\n                \"max_value\": max_value,\n                \"allow_nan\": allow_nan,\n                \"smallest_nonzero_magnitude\": smallest_nonzero_magnitude,\n            },\n        )\n        return self._draw(\"float\", constraints, observe=observe, forced=forced)\n\n    def draw_string(\n        self,\n        intervals: IntervalSet,\n        *,\n        min_size: int = 0,\n        max_size: int = COLLECTION_DEFAULT_MAX_SIZE,\n        forced: str | None = None,\n        observe: bool = True,\n    ) -> str:\n        assert forced is None or min_size <= len(forced) <= max_size\n        assert min_size >= 0\n        if len(intervals) == 0:\n            assert min_size == 0\n\n        constraints: StringConstraints = self._pooled_constraints(\n            \"string\",\n            {\n                \"intervals\": intervals,\n                \"min_size\": min_size,\n                \"max_size\": max_size,\n            },\n        )\n        return self._draw(\"string\", constraints, observe=observe, forced=forced)\n\n    def draw_bytes(\n        self,\n        min_size: int = 0,\n        max_size: int = COLLECTION_DEFAULT_MAX_SIZE,\n        *,\n        forced: bytes | None = None,\n        observe: bool = True,\n    ) -> bytes:\n        assert forced is None or min_size <= len(forced) <= max_size\n        assert min_size >= 0\n\n        constraints: BytesConstraints = self._pooled_constraints(\n            \"bytes\", {\"min_size\": min_size, \"max_size\": max_size}\n        )\n        return self._draw(\"bytes\", constraints, observe=observe, forced=forced)\n\n    def draw_boolean(\n        self,\n        p: float = 0.5,\n        *,\n        forced: bool | None = None,\n        observe: bool = True,\n    ) -> bool:\n        assert (forced is not True) or p > 0\n        assert (forced is not False) or p < 1\n\n        constraints: BooleanConstraints = self._pooled_constraints(\"boolean\", {\"p\": p})\n        return self._draw(\"boolean\", constraints, observe=observe, forced=forced)\n\n    @overload\n    def _pooled_constraints(\n        self, choice_type: Literal[\"integer\"], constraints: IntegerConstraints\n    ) -> IntegerConstraints: ...\n\n    @overload\n    def _pooled_constraints(\n        self, choice_type: Literal[\"float\"], constraints: FloatConstraints\n    ) -> FloatConstraints: ...\n\n    @overload\n    def _pooled_constraints(\n        self, choice_type: Literal[\"string\"], constraints: StringConstraints\n    ) -> StringConstraints: ...\n\n    @overload\n    def _pooled_constraints(\n        self, choice_type: Literal[\"bytes\"], constraints: BytesConstraints\n    ) -> BytesConstraints: ...\n\n    @overload\n    def _pooled_constraints(\n        self, choice_type: Literal[\"boolean\"], constraints: BooleanConstraints\n    ) -> BooleanConstraints: ...\n\n    def _pooled_constraints(\n        self, choice_type: ChoiceTypeT, constraints: ChoiceConstraintsT\n    ) -> ChoiceConstraintsT:\n        \"\"\"Memoize common dictionary objects to reduce memory pressure.\"\"\"\n        # caching runs afoul of nondeterminism checks\n        if self.provider.avoid_realization:\n            return constraints\n\n        key = (choice_type, *choice_constraints_key(choice_type, constraints))\n        try:\n            return POOLED_CONSTRAINTS_CACHE[key]\n        except KeyError:\n            POOLED_CONSTRAINTS_CACHE[key] = constraints\n            return constraints\n\n    def _pop_choice(\n        self,\n        choice_type: ChoiceTypeT,\n        constraints: ChoiceConstraintsT,\n        *,\n        forced: ChoiceT | None,\n    ) -> ChoiceT:\n        assert self.prefix is not None\n        # checked in _draw\n        assert self.index < len(self.prefix)\n\n        value = self.prefix[self.index]\n        if isinstance(value, ChoiceTemplate):\n            node: ChoiceTemplate = value\n            if node.count is not None:\n                assert node.count >= 0\n            # node templates have to be at the end for now, since it's not immediately\n            # apparent how to handle overruning a node template while generating a single\n            # node if the alternative is not \"the entire data is an overrun\".\n            assert self.index == len(self.prefix) - 1\n            if node.type == \"simplest\":\n                if forced is not None:\n                    choice = forced\n                try:\n                    choice = choice_from_index(0, choice_type, constraints)\n                except ChoiceTooLarge:\n                    self.mark_overrun()\n            else:\n                raise NotImplementedError\n\n            if node.count is not None:\n                node.count -= 1\n                if node.count < 0:\n                    self.mark_overrun()\n            return choice\n\n        choice = value\n        node_choice_type = {\n            str: \"string\",\n            float: \"float\",\n            int: \"integer\",\n            bool: \"boolean\",\n            bytes: \"bytes\",\n        }[type(choice)]\n        # If we're trying to:\n        # * draw a different choice type at the same location\n        # * draw the same choice type with a different constraints, which does not permit\n        #   the current value\n        #\n        # then we call this a misalignment, because the choice sequence has\n        # changed from what we expected at some point. An easy misalignment is\n        #\n        #   one_of(integers(0, 100), integers(101, 200))\n        #\n        # where the choice sequence [0, 100] has constraints {min_value: 0, max_value: 100}\n        # at index 1, but [0, 101] has constraints {min_value: 101, max_value: 200} at\n        # index 1 (which does not permit any of the values 0-100).\n        #\n        # When the choice sequence becomes misaligned, we generate a new value of the\n        # type and constraints the strategy expects.\n        if node_choice_type != choice_type or not choice_permitted(choice, constraints):\n            # only track first misalignment for now.\n            if self.misaligned_at is None:\n                self.misaligned_at = (self.index, choice_type, constraints, forced)\n            try:\n                # Fill in any misalignments with index 0 choices. An alternative to\n                # this is using the index of the misaligned choice instead\n                # of index 0, which may be useful for maintaining\n                # \"similarly-complex choices\" in the shrinker. This requires\n                # attaching an index to every choice in ConjectureData.for_choices,\n                # which we don't always have (e.g. when reading from db).\n                #\n                # If we really wanted this in the future we could make this complexity\n                # optional, use it if present, and default to index 0 otherwise.\n                # This complicates our internal api and so I'd like to avoid it\n                # if possible.\n                #\n                # Additionally, I don't think slips which require\n                # slipping to high-complexity values are common. Though arguably\n                # we may want to expand a bit beyond *just* the simplest choice.\n                # (we could for example consider sampling choices from index 0-10).\n                choice = choice_from_index(0, choice_type, constraints)\n            except ChoiceTooLarge:\n                # should really never happen with a 0-index choice, but let's be safe.\n                self.mark_overrun()\n\n        self.index += 1\n        return choice\n\n    def as_result(self) -> ConjectureResult | _Overrun:\n        \"\"\"Convert the result of running this test into\n        either an Overrun object or a ConjectureResult.\"\"\"\n\n        assert self.frozen\n        if self.status == Status.OVERRUN:\n            return Overrun\n        if self.__result is None:\n            self.__result = ConjectureResult(\n                status=self.status,\n                interesting_origin=self.interesting_origin,\n                spans=self.spans,\n                nodes=self.nodes,\n                length=self.length,\n                output=self.output,\n                expected_traceback=self.expected_traceback,\n                expected_exception=self.expected_exception,\n                has_discards=self.has_discards,\n                target_observations=self.target_observations,\n                tags=frozenset(self.tags),\n                arg_slices=self.arg_slices,\n                slice_comments=self.slice_comments,\n                misaligned_at=self.misaligned_at,\n                cannot_proceed_scope=self.cannot_proceed_scope,\n            )\n            assert self.__result is not None\n        return self.__result\n\n    def __assert_not_frozen(self, name: str) -> None:\n        if self.frozen:\n            raise Frozen(f\"Cannot call {name} on frozen ConjectureData\")\n\n    def note(self, value: Any) -> None:\n        self.__assert_not_frozen(\"note\")\n        if not isinstance(value, str):\n            value = repr(value)\n        self.output += value\n\n    def draw(\n        self,\n        strategy: \"SearchStrategy[Ex]\",\n        label: int | None = None,\n        observe_as: str | None = None,\n    ) -> \"Ex\":\n        from hypothesis.internal.observability import observability_enabled\n        from hypothesis.strategies._internal.lazy import unwrap_strategies\n        from hypothesis.strategies._internal.utils import to_jsonable\n\n        at_top_level = self.depth == 0\n        start_time = None\n        if at_top_level:\n            # We start this timer early, because accessing attributes on a LazyStrategy\n            # can be almost arbitrarily slow.  In cases like characters() and text()\n            # where we cache something expensive, this led to Flaky deadline errors!\n            # See https://github.com/HypothesisWorks/hypothesis/issues/2108\n            start_time = time.perf_counter()\n            gc_start_time = gc_cumulative_time()\n\n        strategy.validate()\n\n        if strategy.is_empty:\n            self.mark_invalid(f\"empty strategy {self!r}\")\n\n        if self.depth >= MAX_DEPTH:\n            self.mark_invalid(\"max depth exceeded\")\n\n        # Jump directly to the unwrapped strategy for the label and for do_draw.\n        # This avoids adding an extra span to all lazy strategies.\n        unwrapped = unwrap_strategies(strategy)\n        if label is None:\n            label = unwrapped.label\n            assert isinstance(label, int)\n\n        self.start_span(label=label)\n        try:\n            if not at_top_level:\n                return unwrapped.do_draw(self)\n            assert start_time is not None\n            key = observe_as or f\"generate:unlabeled_{len(self.draw_times)}\"\n            try:\n                try:\n                    v = unwrapped.do_draw(self)\n                finally:\n                    # Subtract the time spent in GC to avoid overcounting, as it is\n                    # accounted for at the overall example level.\n                    in_gctime = gc_cumulative_time() - gc_start_time\n                    self.draw_times[key] = time.perf_counter() - start_time - in_gctime\n            except Exception as err:\n                add_note(\n                    err,\n                    f\"while generating {key.removeprefix('generate:')!r} from {strategy!r}\",\n                )\n                raise\n            if observability_enabled():\n                avoid = self.provider.avoid_realization\n                self._observability_args[key] = to_jsonable(v, avoid_realization=avoid)\n            return v\n        finally:\n            self.stop_span()\n\n    def start_span(self, label: int) -> None:\n        self.provider.span_start(label)\n        self.__assert_not_frozen(\"start_span\")\n        self.depth += 1\n        # Logically it would make sense for this to just be\n        # ``self.depth = max(self.depth, self.max_depth)``, which is what it used to\n        # be until we ran the code under tracemalloc and found a rather significant\n        # chunk of allocation was happening here. This was presumably due to varargs\n        # or the like, but we didn't investigate further given that it was easy\n        # to fix with this check.\n        if self.depth > self.max_depth:\n            self.max_depth = self.depth\n        self.__span_record.start_span(label)\n        self.labels_for_structure_stack.append({label})\n\n    def stop_span(self, *, discard: bool = False) -> None:\n        self.provider.span_end(discard)\n        if self.frozen:\n            return\n        if discard:\n            self.has_discards = True\n        self.depth -= 1\n        assert self.depth >= -1\n        self.__span_record.stop_span(discard=discard)\n\n        labels_for_structure = self.labels_for_structure_stack.pop()\n\n        if not discard:\n            if self.labels_for_structure_stack:\n                self.labels_for_structure_stack[-1].update(labels_for_structure)\n            else:\n                self.tags.update([structural_coverage(l) for l in labels_for_structure])\n\n        if discard:\n            # Once we've discarded a span, every test case starting with\n            # this prefix contains discards. We prune the tree at that point so\n            # as to avoid future test cases bothering with this region, on the\n            # assumption that some span that you could have used instead\n            # there would *not* trigger the discard. This greatly speeds up\n            # test case generation in some cases, because it allows us to\n            # ignore large swathes of the search space that are effectively\n            # redundant.\n            #\n            # A scenario that can cause us problems but which we deliberately\n            # have decided not to support is that if there are side effects\n            # during data generation then you may end up with a scenario where\n            # every good test case generates a discard because the discarded\n            # section sets up important things for later. This is not terribly\n            # likely and all that you see in this case is some degradation in\n            # quality of testing, so we don't worry about it.\n            #\n            # Note that killing the branch does *not* mean we will never\n            # explore below this point, and in particular we may do so during\n            # shrinking. Any explicit request for a data object that starts\n            # with the branch here will work just fine, but novel prefix\n            # generation will avoid it, and we can use it to detect when we\n            # have explored the entire tree (up to redundancy).\n\n            self.observer.kill_branch()\n\n    @property\n    def spans(self) -> Spans:\n        assert self.frozen\n        if self.__spans is None:\n            self.__spans = Spans(record=self.__span_record)\n        return self.__spans\n\n    def freeze(self) -> None:\n        if self.frozen:\n            return\n        self.finish_time = time.perf_counter()\n        self.gc_finish_time = gc_cumulative_time()\n\n        # Always finish by closing all remaining spans so that we have a valid tree.\n        while self.depth >= 0:\n            self.stop_span()\n\n        self.__span_record.freeze()\n        self.frozen = True\n        self.observer.conclude_test(self.status, self.interesting_origin)\n\n    def choice(\n        self,\n        values: Sequence[T],\n        *,\n        forced: T | None = None,\n        observe: bool = True,\n    ) -> T:\n        forced_i = None if forced is None else values.index(forced)\n        i = self.draw_integer(\n            0,\n            len(values) - 1,\n            forced=forced_i,\n            observe=observe,\n        )\n        return values[i]\n\n    def conclude_test(\n        self,\n        status: Status,\n        interesting_origin: InterestingOrigin | None = None,\n    ) -> NoReturn:\n        assert (interesting_origin is None) or (status == Status.INTERESTING)\n        self.__assert_not_frozen(\"conclude_test\")\n        self.interesting_origin = interesting_origin\n        self.status = status\n        self.freeze()\n        raise StopTest(self.testcounter)\n\n    def mark_interesting(self, interesting_origin: InterestingOrigin) -> NoReturn:\n        self.conclude_test(Status.INTERESTING, interesting_origin)\n\n    def mark_invalid(self, why: str | None = None) -> NoReturn:\n        if why is not None:\n            self.events[\"invalid because\"] = why\n        self.conclude_test(Status.INVALID)\n\n    def mark_overrun(self) -> NoReturn:\n        self.conclude_test(Status.OVERRUN)\n\n\ndef draw_choice(\n    choice_type: ChoiceTypeT, constraints: ChoiceConstraintsT, *, random: Random\n) -> ChoiceT:\n    cd = ConjectureData(random=random)\n    return cast(ChoiceT, getattr(cd.provider, f\"draw_{choice_type}\")(**constraints))\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/datatree.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nfrom collections.abc import Generator, Set\nfrom dataclasses import dataclass, field\nfrom random import Random\nfrom typing import TYPE_CHECKING, Final, TypeAlias, cast\n\nfrom hypothesis.errors import (\n    FlakyReplay,\n    FlakyStrategyDefinition,\n    HypothesisException,\n    StopTest,\n)\nfrom hypothesis.internal import floats as flt\nfrom hypothesis.internal.conjecture.choice import (\n    BooleanConstraints,\n    BytesConstraints,\n    ChoiceConstraintsT,\n    ChoiceT,\n    ChoiceTypeT,\n    FloatConstraints,\n    IntegerConstraints,\n    StringConstraints,\n    choice_from_index,\n)\nfrom hypothesis.internal.conjecture.data import ConjectureData, DataObserver, Status\nfrom hypothesis.internal.escalation import InterestingOrigin\nfrom hypothesis.internal.floats import (\n    count_between_floats,\n    float_to_int,\n    int_to_float,\n    sign_aware_lte,\n)\n\nif TYPE_CHECKING:\n    from hypothesis.vendor.pretty import RepresentationPrinter\n\nChildrenCacheValueT: TypeAlias = tuple[\n    Generator[ChoiceT, None, None], list[ChoiceT], set[ChoiceT]\n]\n\n\nclass PreviouslyUnseenBehaviour(HypothesisException):\n    pass\n\n\n_FLAKY_STRAT_MSG = (\n    \"Inconsistent data generation! Data generation behaved differently \"\n    \"between different runs. Is your data generation depending on external \"\n    \"state?\"\n)\n\n\nEMPTY: frozenset[int] = frozenset()\n\n\n@dataclass(slots=True, frozen=True)\nclass Killed:\n    \"\"\"Represents a transition to part of the tree which has been marked as\n    \"killed\", meaning we want to treat it as not worth exploring, so it will\n    be treated as if it were completely explored for the purposes of\n    exhaustion.\"\"\"\n\n    next_node: \"TreeNode\"\n\n    def _repr_pretty_(self, p: \"RepresentationPrinter\", cycle: bool) -> None:\n        assert cycle is False\n        p.text(\"Killed\")\n\n\ndef _node_pretty(\n    choice_type: ChoiceTypeT,\n    value: ChoiceT,\n    constraints: ChoiceConstraintsT,\n    *,\n    forced: bool,\n) -> str:\n    forced_marker = \" [forced]\" if forced else \"\"\n    return f\"{choice_type} {value!r}{forced_marker} {constraints}\"\n\n\n@dataclass(slots=True, frozen=False)\nclass Branch:\n    \"\"\"Represents a transition where multiple choices can be made as to what\n    to drawn.\"\"\"\n\n    constraints: ChoiceConstraintsT\n    choice_type: ChoiceTypeT\n    children: dict[ChoiceT, \"TreeNode\"] = field(repr=False)\n\n    @property\n    def max_children(self) -> int:\n        max_children = compute_max_children(self.choice_type, self.constraints)\n        assert max_children > 0\n        return max_children\n\n    def _repr_pretty_(self, p: \"RepresentationPrinter\", cycle: bool) -> None:\n        assert cycle is False\n        for i, (value, child) in enumerate(self.children.items()):\n            if i > 0:\n                p.break_()\n            p.text(\n                _node_pretty(self.choice_type, value, self.constraints, forced=False)\n            )\n            with p.indent(2):\n                p.break_()\n                p.pretty(child)\n\n\n@dataclass(slots=True, frozen=True)\nclass Conclusion:\n    \"\"\"Represents a transition to a finished state.\"\"\"\n\n    status: Status\n    interesting_origin: InterestingOrigin | None\n\n    def _repr_pretty_(self, p: \"RepresentationPrinter\", cycle: bool) -> None:\n        assert cycle is False\n        o = self.interesting_origin\n        # avoid str(o), which can include multiple lines of context\n        origin = (\n            \"\" if o is None else f\", {o.exc_type.__name__} at {o.filename}:{o.lineno}\"\n        )\n        p.text(f\"Conclusion ({self.status!r}{origin})\")\n\n\n# The number of max children where, beyond this, it is practically impossible\n# for hypothesis to saturate / explore all children nodes in a reasonable time\n# frame. We use this to bail out of expensive max children computations early,\n# where the numbers involved are so large that we know they will be larger than\n# this number.\n#\n# Note that it's ok for us to underestimate the number of max children of a node\n# by using this. We just may think the node is exhausted when in fact it has more\n# possible children to be explored. This has the potential to finish generation\n# early due to exhausting the entire tree, but that is quite unlikely: (1) the\n# number of examples would have to be quite high, and (2) the tree would have to\n# contain only one or two nodes, or generate_novel_prefix would simply switch to\n# exploring another non-exhausted node.\n#\n# Also note that we may sometimes compute max children above this value. In other\n# words, this is *not* a hard maximum on the computed max children. It's the point\n# where further computation is not beneficial - but sometimes doing that computation\n# unconditionally is cheaper than estimating against this value.\n#\n# The one case where this may be detrimental is fuzzing, where the throughput of\n# examples is so high that it really may saturate important nodes. We'll cross\n# that bridge when we come to it.\nMAX_CHILDREN_EFFECTIVELY_INFINITE: Final[int] = 10_000_000\n\n\ndef _count_distinct_strings(*, alphabet_size: int, min_size: int, max_size: int) -> int:\n    # We want to estimate if we're going to have more children than\n    # MAX_CHILDREN_EFFECTIVELY_INFINITE, without computing a potentially\n    # extremely expensive pow. We'll check the two extreme cases - if the\n    # number of strings in the largest string size alone is enough to put us\n    # over this limit (at alphabet_size >= 2), and if the variation in sizes\n    # (at alphabet_size == 1) is enough. If neither result in an early return,\n    # the exact result should be reasonably cheap to compute.\n    if alphabet_size == 0:\n        # Special-case the empty string, avoid error in math.log(0).\n        return 1\n    elif alphabet_size == 1:\n        # Special-case the constant alphabet, invalid in the geom-series sum.\n        return max_size - min_size + 1\n    else:\n        # Estimate against log, which is cheaper than computing a pow.\n        #\n        #   m = max_size\n        #   a = alphabet_size\n        #   N = MAX_CHILDREN_EFFECTIVELY_INFINITE\n        #\n        #           a**m > N\n        # <=> m * log(a) > log(N)\n        log_max_sized_children = max_size * math.log(alphabet_size)\n        if log_max_sized_children > math.log(MAX_CHILDREN_EFFECTIVELY_INFINITE):\n            return MAX_CHILDREN_EFFECTIVELY_INFINITE\n\n    # The sum of a geometric series is given by (ref: wikipedia):\n    #     ᵐ∑ₖ₌₀ aᵏ = (aᵐ⁺¹ - 1) / (a - 1)\n    #               = S(m) / S(0)\n    # assuming a != 1 and using the definition\n    #         S(m) := aᵐ⁺¹ - 1.\n    # The sum we want, starting from a number n [0 <= n <= m] rather than zero, is\n    #     ᵐ∑ₖ₌ₙ aᵏ = ᵐ∑ₖ₌₀ aᵏ - ⁿ⁻¹∑ₖ₌₀ aᵏ = S(m) / S(0) - S(n - 1) / S(0)\n    def S(n):\n        return alphabet_size ** (n + 1) - 1\n\n    return (S(max_size) - S(min_size - 1)) // S(0)\n\n\ndef compute_max_children(\n    choice_type: ChoiceTypeT, constraints: ChoiceConstraintsT\n) -> int:\n    if choice_type == \"integer\":\n        constraints = cast(IntegerConstraints, constraints)\n        min_value = constraints[\"min_value\"]\n        max_value = constraints[\"max_value\"]\n\n        if min_value is None and max_value is None:\n            # full 128 bit range.\n            return 2**128 - 1\n        if min_value is not None and max_value is not None:\n            # count between min/max value.\n            return max_value - min_value + 1\n\n        # hard case: only one bound was specified. Here we probe either upwards\n        # or downwards with our full 128 bit generation, but only half of these\n        # (plus one for the case of generating zero) result in a probe in the\n        # direction we want. ((2**128 - 1) // 2) + 1 == 2 ** 127\n        assert (min_value is None) != (max_value is None)\n        return 2**127\n    elif choice_type == \"boolean\":\n        constraints = cast(BooleanConstraints, constraints)\n        p = constraints[\"p\"]\n        # probabilities of 0 or 1 (or effectively 0 or 1) only have one choice.\n        if p <= 2 ** (-64) or p >= (1 - 2 ** (-64)):\n            return 1\n        return 2\n    elif choice_type == \"bytes\":\n        constraints = cast(BytesConstraints, constraints)\n        return _count_distinct_strings(\n            alphabet_size=2**8,\n            min_size=constraints[\"min_size\"],\n            max_size=constraints[\"max_size\"],\n        )\n    elif choice_type == \"string\":\n        constraints = cast(StringConstraints, constraints)\n        min_size = constraints[\"min_size\"]\n        max_size = constraints[\"max_size\"]\n        intervals = constraints[\"intervals\"]\n\n        return _count_distinct_strings(\n            alphabet_size=len(intervals), min_size=min_size, max_size=max_size\n        )\n    elif choice_type == \"float\":\n        constraints = cast(FloatConstraints, constraints)\n        min_value_f = constraints[\"min_value\"]\n        max_value_f = constraints[\"max_value\"]\n        smallest_nonzero_magnitude = constraints[\"smallest_nonzero_magnitude\"]\n\n        count = count_between_floats(min_value_f, max_value_f)\n\n        # we have two intervals:\n        # a. [min_value, max_value]\n        # b. [-smallest_nonzero_magnitude, smallest_nonzero_magnitude]\n        #\n        # which could be subsets (in either order), overlapping, or disjoint. We\n        # want the interval difference a - b.\n\n        # next_down because endpoints are ok with smallest_nonzero_magnitude\n        min_point = max(min_value_f, -flt.next_down(smallest_nonzero_magnitude))\n        max_point = min(max_value_f, flt.next_down(smallest_nonzero_magnitude))\n\n        if min_point > max_point:\n            # case: disjoint intervals.\n            return count\n\n        count -= count_between_floats(min_point, max_point)\n        if sign_aware_lte(min_value_f, -0.0) and sign_aware_lte(-0.0, max_value_f):\n            # account for -0.0\n            count += 1\n        if sign_aware_lte(min_value_f, 0.0) and sign_aware_lte(0.0, max_value_f):\n            # account for 0.0\n            count += 1\n        return count\n\n    raise NotImplementedError(f\"unhandled choice_type {choice_type}\")\n\n\n# In theory, this is a strict superset of the functionality of compute_max_children;\n#\n#   assert len(all_children(choice_type, constraints)) == compute_max_children(choice_type, constraints)\n#\n# In practice, we maintain two distinct implementations for efficiency and space\n# reasons. If you just need the number of children, it is cheaper to use\n# compute_max_children than to reify the list of children (only to immediately\n# throw it away).\ndef _floats_between(a: float, b: float) -> Generator[float, None, None]:\n    for n in range(float_to_int(a), float_to_int(b) + 1):\n        yield int_to_float(n)\n\n\ndef all_children(\n    choice_type: ChoiceTypeT, constraints: ChoiceConstraintsT\n) -> Generator[ChoiceT, None, None]:\n    if choice_type != \"float\":\n        for index in range(compute_max_children(choice_type, constraints)):\n            yield choice_from_index(index, choice_type, constraints)\n    else:\n        constraints = cast(FloatConstraints, constraints)\n        # the float ordering is not injective (because of resampling\n        # out-of-bounds values), so using choice_from_index would result in\n        # duplicates. This violates invariants in datatree about being able\n        # to draw unique new children using all_children.\n        #\n        # We instead maintain a separate implementation for floats.\n        # TODO_IR write a better (bijective) ordering for floats and remove this!\n        min_value = constraints[\"min_value\"]\n        max_value = constraints[\"max_value\"]\n        smallest_nonzero_magnitude = constraints[\"smallest_nonzero_magnitude\"]\n\n        # handle zeroes separately so smallest_nonzero_magnitude can think of\n        # itself as a complete interval (instead of a hole at ±0).\n        if sign_aware_lte(min_value, -0.0) and sign_aware_lte(-0.0, max_value):\n            yield -0.0\n        if sign_aware_lte(min_value, 0.0) and sign_aware_lte(0.0, max_value):\n            yield 0.0\n\n        if flt.is_negative(min_value):\n            if flt.is_negative(max_value):\n                # case: both negative.\n                max_point = min(max_value, -smallest_nonzero_magnitude)\n                # float_to_int increases as negative magnitude increases, so\n                # invert order.\n                yield from _floats_between(max_point, min_value)\n            else:\n                # case: straddles midpoint (which is between -0.0 and 0.0).\n                yield from _floats_between(-smallest_nonzero_magnitude, min_value)\n                yield from _floats_between(smallest_nonzero_magnitude, max_value)\n        else:\n            # case: both positive.\n            min_point = max(min_value, smallest_nonzero_magnitude)\n            yield from _floats_between(min_point, max_value)\n\n\n@dataclass(slots=True, frozen=False)\nclass TreeNode:\n    \"\"\"\n    A node, or collection of directly descended nodes, in a DataTree.\n\n    We store the DataTree as a radix tree (https://en.wikipedia.org/wiki/Radix_tree),\n    which means that nodes that are the only child of their parent are collapsed\n    into their parent to save space.\n\n    Conceptually, you can unfold a single TreeNode storing n values in its lists\n    into a sequence of n nodes, each a child of the last. In other words,\n    (constraints[i], values[i], choice_types[i]) corresponds to the single node at index\n    i.\n\n    Note that if a TreeNode represents a choice (i.e. the nodes cannot be compacted\n    via the radix tree definition), then its lists will be empty and it will\n    store a `Branch` representing that choce in its `transition`.\n\n    Examples\n    --------\n\n    Consider sequentially drawing a boolean, then an integer.\n\n            data.draw_boolean()\n            data.draw_integer(1, 3)\n\n    If we draw True and then 2, the tree may conceptually look like this.\n\n                      ┌──────┐\n                      │ root │\n                      └──┬───┘\n                      ┌──┴───┐\n                      │ True │\n                      └──┬───┘\n                      ┌──┴───┐\n                      │  2   │\n                      └──────┘\n\n    But since 2 is the only child of True, we will compact these nodes and store\n    them as a single TreeNode.\n\n                      ┌──────┐\n                      │ root │\n                      └──┬───┘\n                    ┌────┴──────┐\n                    │ [True, 2] │\n                    └───────────┘\n\n    If we then draw True and then 3, True will have multiple children and we\n    can no longer store this compacted representation. We would call split_at(0)\n    on the [True, 2] node to indicate that we need to add a choice at 0-index\n    node (True).\n\n                      ┌──────┐\n                      │ root │\n                      └──┬───┘\n                      ┌──┴───┐\n                    ┌─┤ True ├─┐\n                    │ └──────┘ │\n                  ┌─┴─┐      ┌─┴─┐\n                  │ 2 │      │ 3 │\n                  └───┘      └───┘\n    \"\"\"\n\n    # The constraints, value, and choice_types of the nodes stored here. These always\n    # have the same length. The values at index i belong to node i.\n    constraints: list[ChoiceConstraintsT] = field(default_factory=list)\n    values: list[ChoiceT] = field(default_factory=list)\n    choice_types: list[ChoiceTypeT] = field(default_factory=list)\n\n    # The indices of nodes which had forced values.\n    #\n    # Stored as None if no indices have been forced, purely for space saving\n    # reasons (we force quite rarely).\n    __forced: set[int] | None = field(default=None, init=False)\n\n    # What happens next after drawing these nodes. (conceptually, \"what is the\n    # child/children of the last node stored here\").\n    #\n    # One of:\n    # - None (we don't know yet)\n    # - Branch (we have seen multiple possible outcomes here)\n    # - Conclusion (ConjectureData.conclude_test was called here)\n    # - Killed (this branch is valid and may even have children, but should not\n    #   be explored when generating novel prefixes)\n    transition: None | Branch | Conclusion | Killed = None\n\n    # A tree node is exhausted if every possible sequence of draws below it has\n    # been explored. We only update this when performing operations that could\n    # change the answer.\n    #\n    # See also TreeNode.check_exhausted.\n    is_exhausted: bool = field(default=False, init=False)\n\n    @property\n    def forced(self) -> Set[int]:\n        if not self.__forced:\n            return EMPTY\n        return self.__forced\n\n    def mark_forced(self, i: int) -> None:\n        \"\"\"\n        Note that the draw at node i was forced.\n        \"\"\"\n        assert 0 <= i < len(self.values)\n        if self.__forced is None:\n            self.__forced = set()\n        self.__forced.add(i)\n\n    def split_at(self, i: int) -> None:\n        \"\"\"\n        Splits the tree so that it can incorporate a decision at the draw call\n        corresponding to the node at position i.\n\n        Raises FlakyStrategyDefinition if node i was forced.\n        \"\"\"\n\n        if i in self.forced:\n            raise FlakyStrategyDefinition(_FLAKY_STRAT_MSG)\n\n        assert not self.is_exhausted\n\n        key = self.values[i]\n\n        child = TreeNode(\n            choice_types=self.choice_types[i + 1 :],\n            constraints=self.constraints[i + 1 :],\n            values=self.values[i + 1 :],\n            transition=self.transition,\n        )\n        self.transition = Branch(\n            constraints=self.constraints[i],\n            choice_type=self.choice_types[i],\n            children={key: child},\n        )\n        if self.__forced is not None:\n            child.__forced = {j - i - 1 for j in self.__forced if j > i}\n            self.__forced = {j for j in self.__forced if j < i}\n        child.check_exhausted()\n        del self.choice_types[i:]\n        del self.values[i:]\n        del self.constraints[i:]\n        assert len(self.values) == len(self.constraints) == len(self.choice_types) == i\n\n    def check_exhausted(self) -> bool:\n        \"\"\"\n        Recalculates is_exhausted if necessary, and then returns it.\n\n        A node is exhausted if:\n        - Its transition is Conclusion or Killed\n        - It has the maximum number of children (i.e. we have found all of its\n          possible children), and all its children are exhausted\n\n        Therefore, we only need to compute this for a node when:\n        - We first create it in split_at\n        - We set its transition to either Conclusion or Killed\n          (TreeRecordingObserver.conclude_test or TreeRecordingObserver.kill_branch)\n        - We exhaust any of its children\n        \"\"\"\n\n        if (\n            # a node cannot go from is_exhausted -> not is_exhausted.\n            not self.is_exhausted\n            # if we don't know what happens after this node, we don't have\n            # enough information to tell if it's exhausted.\n            and self.transition is not None\n            # if there are still any nodes left which are the only child of their\n            # parent (len(self.values) > 0), then this TreeNode must be not\n            # exhausted, unless all of those nodes were forced.\n            #\n            # This is because we maintain an invariant of only adding nodes to\n            # DataTree which have at least 2 possible values, so we know that if\n            # they do not have any siblings that we still have more choices to\n            # discover.\n            #\n            # (We actually *do* currently add single-valued nodes to the tree,\n            # but immediately split them into a transition to avoid falsifying\n            # this check. this is a bit of a hack.)\n            and len(self.forced) == len(self.values)\n        ):\n            if isinstance(self.transition, (Conclusion, Killed)):\n                self.is_exhausted = True\n            elif len(self.transition.children) == self.transition.max_children:\n                self.is_exhausted = all(\n                    v.is_exhausted for v in self.transition.children.values()\n                )\n        return self.is_exhausted\n\n    def _repr_pretty_(self, p: \"RepresentationPrinter\", cycle: bool) -> None:\n        assert cycle is False\n        indent = 0\n        for i, (choice_type, constraints, value) in enumerate(\n            zip(self.choice_types, self.constraints, self.values, strict=True)\n        ):\n            with p.indent(indent):\n                if i > 0:\n                    p.break_()\n                p.text(\n                    _node_pretty(\n                        choice_type, value, constraints, forced=i in self.forced\n                    )\n                )\n            indent += 2\n\n        with p.indent(indent):\n            if len(self.values) > 0:\n                p.break_()\n            if self.transition is not None:\n                p.pretty(self.transition)\n            else:\n                p.text(\"unknown\")\n\n\nclass DataTree:\n    \"\"\"\n    A DataTree tracks the structured history of draws in some test function,\n    across multiple ConjectureData objects.\n\n    This information is used by ConjectureRunner to generate novel prefixes of\n    this tree (see generate_novel_prefix). A novel prefix is a sequence of draws\n    which the tree has not seen before, and therefore the ConjectureRunner has\n    not generated as an input to the test function before.\n\n    DataTree tracks the following:\n\n    - Drawn choices in the choice sequence\n      - ConjectureData.draw_integer()\n      - ConjectureData.draw_float()\n      - ConjectureData.draw_string()\n      - ConjectureData.draw_boolean()\n      - ConjectureData.draw_bytes()\n    - Test conclusions (with some Status, e.g. Status.VALID)\n      - ConjectureData.conclude_test()\n\n    A DataTree is — surprise — a *tree*. A node in this tree is either a choice draw\n    with some value, a test conclusion with some Status, or a special `Killed` value,\n    which denotes that further draws may exist beyond this node but should not be\n    considered worth exploring when generating novel prefixes. A node is a leaf\n    iff it is a conclusion or Killed.\n\n    A branch from node A to node B indicates that we have previously seen some\n    sequence (a, b) of draws, where a and b are the values in nodes A and B.\n    Similar intuition holds for conclusion and Killed nodes.\n\n    Examples\n    --------\n\n    To see how a DataTree gets built through successive sets of draws, consider\n    the following code that calls through to some ConjecutreData object `data`.\n    The first call can be either True or False, and the second call can be any\n    integer in the range [1, 3].\n\n        data.draw_boolean()\n        data.draw_integer(1, 3)\n\n    To start, the corresponding DataTree object is completely empty.\n\n                      ┌──────┐\n                      │ root │\n                      └──────┘\n\n    We happen to draw True and then 2 in the above code. The tree tracks this.\n    (2 also connects to a child Conclusion node with Status.VALID since it's the\n    final draw in the code. I'll omit Conclusion nodes in diagrams for brevity.)\n\n                      ┌──────┐\n                      │ root │\n                      └──┬───┘\n                      ┌──┴───┐\n                      │ True │\n                      └──┬───┘\n                      ┌──┴───┐\n                      │  2   │\n                      └──────┘\n\n    This is a very boring tree so far! But now we happen to draw False and\n    then 1. This causes a split in the tree. Remember, DataTree tracks history\n    over all invocations of a function, not just one. The end goal is to know\n    what invocations haven't been tried yet, after all.\n\n                      ┌──────┐\n                  ┌───┤ root ├───┐\n                  │   └──────┘   │\n               ┌──┴───┐        ┌─┴─────┐\n               │ True │        │ False │\n               └──┬───┘        └──┬────┘\n                ┌─┴─┐           ┌─┴─┐\n                │ 2 │           │ 1 │\n                └───┘           └───┘\n\n    If we were to ask DataTree for a novel prefix at this point, it might\n    generate any of (True, 1), (True, 3), (False, 2), or (False, 3).\n\n    Note that the novel prefix stops as soon as it generates a novel node. For\n    instance, if we had generated a novel prefix back when the tree was only\n    root -> True -> 2, we could have gotten any of (True, 1), (True, 3), or\n    (False). But we could *not* have gotten (False, n), because both False and\n    n were novel at that point, and we stop at the first novel node — False.\n\n    I won't belabor this example. Here's what the tree looks like when fully\n    explored:\n\n                      ┌──────┐\n               ┌──────┤ root ├──────┐\n               │      └──────┘      │\n            ┌──┴───┐              ┌─┴─────┐\n         ┌──┤ True ├──┐       ┌───┤ False ├──┐\n         │  └──┬───┘  │       │   └──┬────┘  │\n       ┌─┴─┐ ┌─┴─┐  ┌─┴─┐   ┌─┴─┐  ┌─┴─┐   ┌─┴─┐\n       │ 1 │ │ 2 │  │ 3 │   │ 1 │  │ 2 │   │ 3 │\n       └───┘ └───┘  └───┘   └───┘  └───┘   └───┘\n\n    You could imagine much more complicated trees than this arising in practice,\n    and indeed they do. In particular, the tree need not be balanced or 'nice'\n    like the tree above. For instance,\n\n        b = data.draw_boolean()\n        if b:\n            data.draw_integer(1, 3)\n\n    results in a tree with the entire right part lopped off, and False leading\n    straight to a conclusion node with Status.VALID. As another example,\n\n        n = data.draw_integers()\n        assume(n >= 3)\n        data.draw_string()\n\n    results in a tree with the 0, 1, and 2 nodes leading straight to a\n    conclusion node with Status.INVALID, and the rest branching off into all\n    the possibilities of draw_string.\n\n    Notes\n    -----\n\n    The above examples are slightly simplified and are intended to convey\n    intuition. In practice, there are some implementation details to be aware\n    of.\n\n    - In draw nodes, we store the constraints used in addition to the value drawn.\n      E.g. the node corresponding to data.draw_float(min_value=1.0, max_value=1.5)\n      would store {\"min_value\": 1.0, \"max_value\": 1.5, ...} (default values for\n      other constraints omitted).\n\n      The constraints parameters have the potential to change both the range of\n      possible outputs of a node, and the probability distribution within that\n      range, so we need to use these when drawing in DataTree as well. We draw\n      values using these constraints when (1) generating a novel value for a node\n      and (2) choosing a random child when traversing the tree.\n\n    - For space efficiency, rather than tracking the full tree structure, we\n      store DataTree as a radix tree. This is conceptually equivalent (radix\n      trees can always be \"unfolded\" to the full tree) but it means the internal\n      representation may differ in practice.\n\n      See TreeNode for more information.\n    \"\"\"\n\n    def __init__(self) -> None:\n        self.root: TreeNode = TreeNode()\n        self._children_cache: dict[ChoiceT, ChildrenCacheValueT] = {}\n\n    @property\n    def is_exhausted(self) -> bool:\n        \"\"\"\n        Returns True if every node is exhausted, and therefore the tree has\n        been fully explored.\n        \"\"\"\n        return self.root.is_exhausted\n\n    def generate_novel_prefix(self, random: Random) -> tuple[ChoiceT, ...]:\n        \"\"\"Generate a short random string that (after rewriting) is not\n        a prefix of any choice sequence previously added to the tree.\n\n        The resulting prefix is essentially arbitrary - it would be nice\n        for it to be uniform at random, but previous attempts to do that\n        have proven too expensive.\n        \"\"\"\n        assert not self.is_exhausted\n        prefix = []\n\n        def append_choice(choice_type: ChoiceTypeT, choice: ChoiceT) -> None:\n            if choice_type == \"float\":\n                assert isinstance(choice, int)\n                choice = int_to_float(choice)\n            prefix.append(choice)\n\n        current_node = self.root\n        while True:\n            assert not current_node.is_exhausted\n            for i, (choice_type, constraints, value) in enumerate(\n                zip(\n                    current_node.choice_types,\n                    current_node.constraints,\n                    current_node.values,\n                    strict=True,\n                )\n            ):\n                if i in current_node.forced:\n                    append_choice(choice_type, value)\n                else:\n                    attempts = 0\n                    while True:\n                        if attempts <= 10:\n                            try:\n                                node_value = self._draw(\n                                    choice_type, constraints, random=random\n                                )\n                            except StopTest:  # pragma: no cover\n                                # it is possible that drawing from a fresh data can\n                                # overrun BUFFER_SIZE, due to eg unlucky rejection sampling\n                                # of integer probes. Retry these cases.\n                                attempts += 1\n                                continue\n                        else:\n                            node_value = self._draw_from_cache(\n                                choice_type,\n                                constraints,\n                                key=id(current_node),\n                                random=random,\n                            )\n\n                        if node_value != value:\n                            append_choice(choice_type, node_value)\n                            break\n                        attempts += 1\n                        self._reject_child(\n                            choice_type,\n                            constraints,\n                            child=node_value,\n                            key=id(current_node),\n                        )\n                    # We've now found a value that is allowed to\n                    # vary, so what follows is not fixed.\n                    return tuple(prefix)\n\n            assert not isinstance(current_node.transition, (Conclusion, Killed))\n            if current_node.transition is None:\n                return tuple(prefix)\n            branch = current_node.transition\n            assert isinstance(branch, Branch)\n\n            attempts = 0\n            while True:\n                if attempts <= 10:\n                    try:\n                        node_value = self._draw(\n                            branch.choice_type, branch.constraints, random=random\n                        )\n                    except StopTest:  # pragma: no cover\n                        attempts += 1\n                        continue\n                else:\n                    node_value = self._draw_from_cache(\n                        branch.choice_type,\n                        branch.constraints,\n                        key=id(branch),\n                        random=random,\n                    )\n                try:\n                    child = branch.children[node_value]\n                except KeyError:\n                    append_choice(branch.choice_type, node_value)\n                    return tuple(prefix)\n                if not child.is_exhausted:\n                    append_choice(branch.choice_type, node_value)\n                    current_node = child\n                    break\n                attempts += 1\n                self._reject_child(\n                    branch.choice_type,\n                    branch.constraints,\n                    child=node_value,\n                    key=id(branch),\n                )\n\n                # We don't expect this assertion to ever fire, but coverage\n                # wants the loop inside to run if you have branch checking\n                # on, hence the pragma.\n                assert (  # pragma: no cover\n                    attempts != 1000\n                    or len(branch.children) < branch.max_children\n                    or any(not v.is_exhausted for v in branch.children.values())\n                )\n\n    def rewrite(self, choices):\n        \"\"\"Use previously seen ConjectureData objects to return a tuple of\n        the rewritten choice sequence and the status we would get from running\n        that with the test function. If the status cannot be predicted\n        from the existing values it will be None.\"\"\"\n        data = ConjectureData.for_choices(choices)\n        try:\n            self.simulate_test_function(data)\n            return (data.choices, data.status)\n        except PreviouslyUnseenBehaviour:\n            return (choices, None)\n\n    def simulate_test_function(self, data: ConjectureData) -> None:\n        \"\"\"Run a simulated version of the test function recorded by\n        this tree. Note that this does not currently call ``stop_span``\n        or ``start_span`` as these are not currently recorded in the\n        tree. This will likely change in future.\"\"\"\n        node = self.root\n\n        def draw(choice_type, constraints, *, forced=None, convert_forced=True):\n            if choice_type == \"float\" and forced is not None and convert_forced:\n                forced = int_to_float(forced)\n\n            draw_func = getattr(data, f\"draw_{choice_type}\")\n            value = draw_func(**constraints, forced=forced)\n\n            if choice_type == \"float\":\n                value = float_to_int(value)\n            return value\n\n        try:\n            while True:\n                for i, (choice_type, constraints, previous) in enumerate(\n                    zip(node.choice_types, node.constraints, node.values, strict=True)\n                ):\n                    v = draw(\n                        choice_type,\n                        constraints,\n                        forced=previous if i in node.forced else None,\n                    )\n                    if v != previous:\n                        raise PreviouslyUnseenBehaviour\n                if isinstance(node.transition, Conclusion):\n                    t = node.transition\n                    data.conclude_test(t.status, t.interesting_origin)\n                elif node.transition is None:\n                    raise PreviouslyUnseenBehaviour\n                elif isinstance(node.transition, Branch):\n                    v = draw(node.transition.choice_type, node.transition.constraints)\n                    try:\n                        node = node.transition.children[v]\n                    except KeyError as err:\n                        raise PreviouslyUnseenBehaviour from err\n                else:\n                    assert isinstance(node.transition, Killed)\n                    data.observer.kill_branch()\n                    node = node.transition.next_node\n        except StopTest:\n            pass\n\n    def new_observer(self):\n        return TreeRecordingObserver(self)\n\n    def _draw(\n        self,\n        choice_type: ChoiceTypeT,\n        constraints: ChoiceConstraintsT,\n        *,\n        random: Random,\n    ) -> ChoiceT:\n        from hypothesis.internal.conjecture.data import draw_choice\n\n        value = draw_choice(choice_type, constraints, random=random)\n        # using floats as keys into branch.children breaks things, because\n        # e.g. hash(0.0) == hash(-0.0) would collide as keys when they are\n        # in fact distinct child branches.\n        # To distinguish floats here we'll use their bits representation. This\n        # entails some bookkeeping such that we're careful about when the\n        # float key is in its bits form (as a key into branch.children) and\n        # when it is in its float form (as a value we want to write to the\n        # choice sequence), and converting between the two forms as appropriate.\n        if choice_type == \"float\":\n            assert isinstance(value, float)\n            value = float_to_int(value)\n        return value\n\n    def _get_children_cache(\n        self, choice_type: ChoiceTypeT, constraints: ChoiceConstraintsT, *, key: ChoiceT\n    ) -> ChildrenCacheValueT:\n        # cache the state of the children generator per node/branch (passed as\n        # `key` here), such that we track which children we've already tried\n        # for this branch across draws.\n        # We take advantage of python generators here as one-way iterables,\n        # so each time we iterate we implicitly store our position in the\n        # children generator and don't re-draw children. `children` is the\n        # concrete list of children draw from the generator that we will work\n        # with. Whenever we need to top up this list, we will draw a new value\n        # from the generator.\n        if key not in self._children_cache:\n            generator = all_children(choice_type, constraints)\n            children: list[ChoiceT] = []\n            rejected: set[ChoiceT] = set()\n            self._children_cache[key] = (generator, children, rejected)\n\n        return self._children_cache[key]\n\n    def _draw_from_cache(\n        self,\n        choice_type: ChoiceTypeT,\n        constraints: ChoiceConstraintsT,\n        *,\n        key: ChoiceT,\n        random: Random,\n    ) -> ChoiceT:\n        (generator, children, rejected) = self._get_children_cache(\n            choice_type, constraints, key=key\n        )\n        # Keep a stock of 100 potentially-valid children at all times.\n        # This number is chosen to balance memory/speed vs randomness. Ideally\n        # we would sample uniformly from all not-yet-rejected children, but\n        # computing and storing said children is not free.\n        # no-branch because coverage of the fall-through case here is a bit\n        # annoying.\n        if len(children) < 100:  # pragma: no branch\n            for v in generator:\n                if choice_type == \"float\":\n                    assert isinstance(v, float)\n                    v = float_to_int(v)\n                if v in rejected:\n                    continue\n                children.append(v)\n                if len(children) >= 100:\n                    break\n\n        return random.choice(children)\n\n    def _reject_child(\n        self,\n        choice_type: ChoiceTypeT,\n        constraints: ChoiceConstraintsT,\n        *,\n        child: ChoiceT,\n        key: ChoiceT,\n    ) -> None:\n        (_generator, children, rejected) = self._get_children_cache(\n            choice_type, constraints, key=key\n        )\n        rejected.add(child)\n        # we remove a child from the list of possible children *only* when it is\n        # rejected, and not when it is initially drawn in _draw_from_cache. The\n        # reason is that a child being drawn does not guarantee that child will\n        # be used in a way such that it is written back to the tree, so it needs\n        # to be available for future draws until we are certain it has been\n        # used.\n        #\n        # For instance, if we generated novel prefixes in a loop (but never used\n        # those prefixes to generate new values!) then we don't want to remove\n        # the drawn children from the available pool until they are actually\n        # used.\n        #\n        # This does result in a small inefficiency: we may draw a child,\n        # immediately use it (so we know it cannot be drawn again), but still\n        # wait to draw and reject it here, because DataTree cannot guarantee\n        # the drawn child has been used.\n        if child in children:\n            children.remove(child)\n\n    def _repr_pretty_(self, p: \"RepresentationPrinter\", cycle: bool) -> None:\n        assert cycle is False\n        p.pretty(self.root)\n\n\nclass TreeRecordingObserver(DataObserver):\n    def __init__(self, tree: DataTree):\n        # this attr isn't read, but is very useful for local debugging flaky\n        # errors, with\n        # `from hypothesis.vendor import pretty; print(pretty.pretty(self._root))`\n        self._root = tree.root\n        self._current_node: TreeNode = tree.root\n        self._index_in_current_node: int = 0\n        self._trail: list[TreeNode] = [self._current_node]\n        self.killed: bool = False\n\n    def draw_integer(\n        self, value: int, *, was_forced: bool, constraints: IntegerConstraints\n    ) -> None:\n        self.draw_value(\n            \"integer\", value, was_forced=was_forced, constraints=constraints\n        )\n\n    def draw_float(\n        self, value: float, *, was_forced: bool, constraints: FloatConstraints\n    ) -> None:\n        self.draw_value(\"float\", value, was_forced=was_forced, constraints=constraints)\n\n    def draw_string(\n        self, value: str, *, was_forced: bool, constraints: StringConstraints\n    ) -> None:\n        self.draw_value(\"string\", value, was_forced=was_forced, constraints=constraints)\n\n    def draw_bytes(\n        self, value: bytes, *, was_forced: bool, constraints: BytesConstraints\n    ) -> None:\n        self.draw_value(\"bytes\", value, was_forced=was_forced, constraints=constraints)\n\n    def draw_boolean(\n        self, value: bool, *, was_forced: bool, constraints: BooleanConstraints\n    ) -> None:\n        self.draw_value(\n            \"boolean\", value, was_forced=was_forced, constraints=constraints\n        )\n\n    def draw_value(\n        self,\n        choice_type: ChoiceTypeT,\n        value: ChoiceT,\n        *,\n        was_forced: bool,\n        constraints: ChoiceConstraintsT,\n    ) -> None:\n        i = self._index_in_current_node\n        self._index_in_current_node += 1\n        node = self._current_node\n\n        if isinstance(value, float):\n            value = float_to_int(value)\n\n        assert len(node.constraints) == len(node.values) == len(node.choice_types)\n        if i < len(node.values):\n            if (\n                choice_type != node.choice_types[i]\n                or constraints != node.constraints[i]\n            ):\n                raise FlakyStrategyDefinition(_FLAKY_STRAT_MSG)\n            # Note that we don't check whether a previously\n            # forced value is now free. That will be caught\n            # if we ever split the node there, but otherwise\n            # may pass silently. This is acceptable because it\n            # means we skip a hash set lookup on every\n            # draw and that's a pretty niche failure mode.\n            if was_forced and i not in node.forced:\n                raise FlakyStrategyDefinition(_FLAKY_STRAT_MSG)\n            if value != node.values[i]:\n                node.split_at(i)\n                assert i == len(node.values)\n                new_node = TreeNode()\n                assert isinstance(node.transition, Branch)\n                node.transition.children[value] = new_node\n                self._current_node = new_node\n                self._index_in_current_node = 0\n        else:\n            trans = node.transition\n            if trans is None:\n                node.choice_types.append(choice_type)\n                node.constraints.append(constraints)\n                node.values.append(value)\n                if was_forced:\n                    node.mark_forced(i)\n                # generate_novel_prefix assumes the following invariant: any one\n                # of the series of draws in a particular node can vary, i.e. the\n                # max number of children is at least 2. However, some draws are\n                # pseudo-choices and only have a single value, such as\n                # integers(0, 0).\n                #\n                # Currently, we address this by forcefully splitting such\n                # single-valued nodes into a transition when we see them. An\n                # exception to this is if it was forced: forced pseudo-choices\n                # do not cause the above issue because they inherently cannot\n                # vary, and moreover they trip other invariants about never\n                # splitting forced nodes.\n                #\n                # An alternative is not writing such choices to the tree at\n                # all, and thus guaranteeing that each node has at least 2 max\n                # children.\n                if (\n                    compute_max_children(choice_type, constraints) == 1\n                    and not was_forced\n                ):\n                    node.split_at(i)\n                    assert isinstance(node.transition, Branch)\n                    self._current_node = node.transition.children[value]\n                    self._index_in_current_node = 0\n            elif isinstance(trans, Conclusion):\n                assert trans.status != Status.OVERRUN\n                # We tried to draw where history says we should have\n                # stopped\n                raise FlakyStrategyDefinition(_FLAKY_STRAT_MSG)\n            else:\n                assert isinstance(trans, Branch), trans\n                if choice_type != trans.choice_type or constraints != trans.constraints:\n                    raise FlakyStrategyDefinition(_FLAKY_STRAT_MSG)\n                try:\n                    self._current_node = trans.children[value]\n                except KeyError:\n                    self._current_node = trans.children.setdefault(value, TreeNode())\n                self._index_in_current_node = 0\n        if self._trail[-1] is not self._current_node:\n            self._trail.append(self._current_node)\n\n    def kill_branch(self) -> None:\n        \"\"\"Mark this part of the tree as not worth re-exploring.\"\"\"\n        if self.killed:\n            return\n\n        self.killed = True\n\n        if self._index_in_current_node < len(self._current_node.values) or (\n            self._current_node.transition is not None\n            and not isinstance(self._current_node.transition, Killed)\n        ):\n            raise FlakyStrategyDefinition(_FLAKY_STRAT_MSG)\n\n        if self._current_node.transition is None:\n            self._current_node.transition = Killed(TreeNode())\n            self.__update_exhausted()\n\n        self._current_node = self._current_node.transition.next_node\n        self._index_in_current_node = 0\n        self._trail.append(self._current_node)\n\n    def conclude_test(\n        self, status: Status, interesting_origin: InterestingOrigin | None\n    ) -> None:\n        \"\"\"Says that ``status`` occurred at node ``node``. This updates the\n        node if necessary and checks for consistency.\"\"\"\n        if status == Status.OVERRUN:\n            return\n        i = self._index_in_current_node\n        node = self._current_node\n\n        if i < len(node.values) or isinstance(node.transition, Branch):\n            raise FlakyStrategyDefinition(_FLAKY_STRAT_MSG)\n\n        new_transition = Conclusion(status, interesting_origin)\n\n        if node.transition is not None and node.transition != new_transition:\n            # As an, I'm afraid, horrible bodge, we deliberately ignore flakiness\n            # where tests go from interesting to valid, because it's much easier\n            # to produce good error messages for these further up the stack.\n            if isinstance(node.transition, Conclusion) and (\n                node.transition.status != Status.INTERESTING\n                or new_transition.status != Status.VALID\n            ):\n                old_origin = node.transition.interesting_origin\n                new_origin = new_transition.interesting_origin\n                raise FlakyReplay(\n                    f\"Inconsistent results from replaying a test case!\\n\"\n                    f\"  last: {node.transition.status.name} from {old_origin}\\n\"\n                    f\"  this: {new_transition.status.name} from {new_origin}\",\n                    (old_origin, new_origin),\n                )\n        else:\n            node.transition = new_transition\n\n        assert node is self._trail[-1]\n        node.check_exhausted()\n        assert len(node.values) > 0 or node.check_exhausted()\n\n        if not self.killed:\n            self.__update_exhausted()\n\n    def __update_exhausted(self) -> None:\n        for t in reversed(self._trail):\n            # Any node we've traversed might have now become exhausted.\n            # We check from the right. As soon as we hit a node that\n            # isn't exhausted, this automatically implies that all of\n            # its parents are not exhausted, so we stop.\n            if not t.check_exhausted():\n                break\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/engine.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport importlib\nimport math\nimport threading\nimport time\nfrom collections import defaultdict\nfrom collections.abc import Callable, Generator, Sequence\nfrom contextlib import AbstractContextManager, contextmanager, nullcontext\nfrom dataclasses import dataclass, field\nfrom datetime import timedelta\nfrom enum import Enum\nfrom random import Random\nfrom typing import Literal, NoReturn, cast\n\nfrom hypothesis import HealthCheck, Phase, Verbosity, settings as Settings\nfrom hypothesis._settings import local_settings\nfrom hypothesis.database import ExampleDatabase, choices_from_bytes, choices_to_bytes\nfrom hypothesis.errors import (\n    BackendCannotProceed,\n    FlakyBackendFailure,\n    HypothesisException,\n    InvalidArgument,\n    StopTest,\n)\nfrom hypothesis.internal.cache import LRUReusedCache\nfrom hypothesis.internal.compat import NotRequired, TypedDict, ceil, override\nfrom hypothesis.internal.conjecture.choice import (\n    ChoiceConstraintsT,\n    ChoiceKeyT,\n    ChoiceNode,\n    ChoiceT,\n    ChoiceTemplate,\n    choices_key,\n)\nfrom hypothesis.internal.conjecture.data import (\n    ConjectureData,\n    ConjectureResult,\n    DataObserver,\n    Overrun,\n    Status,\n    _Overrun,\n)\nfrom hypothesis.internal.conjecture.datatree import (\n    DataTree,\n    PreviouslyUnseenBehaviour,\n    TreeRecordingObserver,\n)\nfrom hypothesis.internal.conjecture.junkdrawer import (\n    ensure_free_stackframes,\n    startswith,\n)\nfrom hypothesis.internal.conjecture.pareto import NO_SCORE, ParetoFront, ParetoOptimiser\nfrom hypothesis.internal.conjecture.providers import (\n    AVAILABLE_PROVIDERS,\n    HypothesisProvider,\n    PrimitiveProvider,\n)\nfrom hypothesis.internal.conjecture.shrinker import Shrinker, ShrinkPredicateT, sort_key\nfrom hypothesis.internal.escalation import InterestingOrigin\nfrom hypothesis.internal.healthcheck import fail_health_check\nfrom hypothesis.internal.observability import Observation, with_observability_callback\nfrom hypothesis.reporting import base_report, report, verbose_report\n\n# In most cases, the following constants are all Final. However, we do allow users\n# to monkeypatch all of these variables, which means we cannot annotate them as\n# Final or mypyc will inline them and render monkeypatching useless.\n\n#: The maximum number of times the shrinker will reduce the complexity of a failing\n#: input before giving up. This avoids falling down a trap of exponential (or worse)\n#: complexity, where the shrinker appears to be making progress but will take a\n#: substantially long time to finish completely.\nMAX_SHRINKS: int = 500\n\n# If the shrinking phase takes more than five minutes, abort it early and print\n# a warning.   Many CI systems will kill a build after around ten minutes with\n# no output, and appearing to hang isn't great for interactive use either -\n# showing partially-shrunk examples is better than quitting with no examples!\n# (but make it monkeypatchable, for the rare users who need to keep on shrinking)\n\n#: The maximum total time in seconds that the shrinker will try to shrink a failure\n#: for before giving up. This is across all shrinks for the same failure, so even\n#: if the shrinker successfully reduces the complexity of a single failure several\n#: times, it will stop when it hits |MAX_SHRINKING_SECONDS| of total time taken.\nMAX_SHRINKING_SECONDS: int = 300\n\n#: The maximum amount of entropy a single test case can use before giving up\n#: while making random choices during input generation.\n#:\n#: The \"unit\" of one |BUFFER_SIZE| does not have any defined semantics, and you\n#: should not rely on it, except that a linear increase |BUFFER_SIZE| will linearly\n#: increase the amount of entropy a test case can use during generation.\nBUFFER_SIZE: int = 8 * 1024\nCACHE_SIZE: int = 10000\nMIN_TEST_CALLS: int = 10\n\n# we use this to isolate Hypothesis from interacting with the global random,\n# to make it easier to reason about our global random warning logic easier (see\n# deprecate_random_in_strategy).\n_random = Random()\n\n\ndef shortlex(s):\n    return (len(s), s)\n\n\n@dataclass(slots=True, frozen=False)\nclass HealthCheckState:\n    valid_examples: int = field(default=0)\n    invalid_examples: int = field(default=0)\n    overrun_examples: int = field(default=0)\n    draw_times: defaultdict[str, list[float]] = field(\n        default_factory=lambda: defaultdict(list)\n    )\n\n    @property\n    def total_draw_time(self) -> float:\n        return math.fsum(sum(self.draw_times.values(), start=[]))\n\n    def timing_report(self) -> str:\n        \"\"\"Return a terminal report describing what was slow.\"\"\"\n        if not self.draw_times:\n            return \"\"\n        width = max(\n            len(k.removeprefix(\"generate:\").removesuffix(\": \")) for k in self.draw_times\n        )\n        out = [f\"\\n  {'':^{width}}   count | fraction |    slowest draws (seconds)\"]\n        args_in_order = sorted(self.draw_times.items(), key=lambda kv: -sum(kv[1]))\n        for i, (argname, times) in enumerate(args_in_order):  # pragma: no branch\n            # If we have very many unique keys, which can happen due to interactive\n            # draws with computed labels, we'll skip uninformative rows.\n            if (\n                5 <= i < (len(self.draw_times) - 2)\n                and math.fsum(times) * 20 < self.total_draw_time\n            ):\n                out.append(f\"  (skipped {len(self.draw_times) - i} rows of fast draws)\")\n                break\n            # Compute the row to report, omitting times <1ms to focus on slow draws\n            reprs = [f\"{t:>6.3f},\" for t in sorted(times)[-5:] if t > 5e-4]\n            desc = \" \".join(([\"    -- \"] * 5 + reprs)[-5:]).rstrip(\",\")\n            arg = argname.removeprefix(\"generate:\").removesuffix(\": \")\n            out.append(\n                f\"  {arg:^{width}} | {len(times):>4}  | \"\n                f\"{math.fsum(times)/self.total_draw_time:>7.0%}  |  {desc}\"\n            )\n        return \"\\n\".join(out)\n\n\ndef _invalid_thresholds(*, r: float, c: float) -> tuple[int, int]:\n    base = math.ceil(math.log(1 - c) / math.log(1 - r)) - 1\n    per_p = math.ceil(1 / r)\n    return base, per_p\n\n\n# stop once we're 99% confident the true valid rate is below 1%. See\n# https://github.com/HypothesisWorks/hypothesis/issues/4623#issuecomment-3814681997\n# for how we derived this formula.\nINVALID_THRESHOLD_BASE, INVALID_PER_VALID = _invalid_thresholds(r=0.01, c=0.99)\n\n\nclass ExitReason(Enum):\n    max_examples = \"settings.max_examples={s.max_examples}\"\n    max_iterations = (\n        \"settings.max_examples={s.max_examples}, \"\n        \"but < 1% of examples satisfied assumptions\"\n    )\n    max_shrinks = f\"shrunk example {MAX_SHRINKS} times\"\n    finished = \"nothing left to do\"\n    flaky = \"test was flaky\"\n    very_slow_shrinking = \"shrinking was very slow\"\n\n    def describe(self, settings: Settings) -> str:\n        return self.value.format(s=settings)\n\n\nclass RunIsComplete(Exception):\n    pass\n\n\ndef _get_provider(backend: str) -> PrimitiveProvider | type[PrimitiveProvider]:\n    provider_cls = AVAILABLE_PROVIDERS[backend]\n    if isinstance(provider_cls, str):\n        module_name, class_name = provider_cls.rsplit(\".\", 1)\n        provider_cls = getattr(importlib.import_module(module_name), class_name)\n\n    if provider_cls.lifetime == \"test_function\":\n        return provider_cls(None)\n    elif provider_cls.lifetime == \"test_case\":\n        return provider_cls\n    else:\n        raise InvalidArgument(\n            f\"invalid lifetime {provider_cls.lifetime} for provider {provider_cls.__name__}. \"\n            \"Expected one of 'test_function', 'test_case'.\"\n        )\n\n\nclass CallStats(TypedDict):\n    status: str\n    runtime: float\n    drawtime: float\n    gctime: float\n    events: list[str]\n\n\nPhaseStatistics = TypedDict(\n    \"PhaseStatistics\",\n    {\n        \"duration-seconds\": float,\n        \"test-cases\": list[CallStats],\n        \"distinct-failures\": int,\n        \"shrinks-successful\": int,\n    },\n)\nStatisticsDict = TypedDict(\n    \"StatisticsDict\",\n    {\n        \"generate-phase\": NotRequired[PhaseStatistics],\n        \"reuse-phase\": NotRequired[PhaseStatistics],\n        \"shrink-phase\": NotRequired[PhaseStatistics],\n        \"stopped-because\": NotRequired[str],\n        \"targets\": NotRequired[dict[str, float]],\n        \"nodeid\": NotRequired[str],\n    },\n)\n\n\ndef choice_count(choices: Sequence[ChoiceT | ChoiceTemplate]) -> int | None:\n    count = 0\n    for choice in choices:\n        if isinstance(choice, ChoiceTemplate):\n            if choice.count is None:\n                return None\n            count += choice.count\n        else:\n            count += 1\n    return count\n\n\nclass DiscardObserver(DataObserver):\n    @override\n    def kill_branch(self) -> NoReturn:\n        raise ContainsDiscard\n\n\ndef realize_choices(data: ConjectureData, *, for_failure: bool) -> None:\n    for node in data.nodes:\n        value = data.provider.realize(node.value, for_failure=for_failure)\n        expected_type = {\n            \"string\": str,\n            \"float\": float,\n            \"integer\": int,\n            \"boolean\": bool,\n            \"bytes\": bytes,\n        }[node.type]\n        if type(value) is not expected_type:\n            raise HypothesisException(\n                f\"expected {expected_type} from \"\n                f\"{data.provider.realize.__qualname__}, got {type(value)}\"\n            )\n\n        constraints = cast(\n            ChoiceConstraintsT,\n            {\n                k: data.provider.realize(v, for_failure=for_failure)\n                for k, v in node.constraints.items()\n            },\n        )\n        node.value = value\n        node.constraints = constraints\n\n\nclass ConjectureRunner:\n    def __init__(\n        self,\n        test_function: Callable[[ConjectureData], None],\n        *,\n        settings: Settings | None = None,\n        random: Random | None = None,\n        database_key: bytes | None = None,\n        ignore_limits: bool = False,\n        thread_overlap: dict[int, bool] | None = None,\n    ) -> None:\n        self._test_function: Callable[[ConjectureData], None] = test_function\n        self.settings: Settings = settings or Settings()\n        self.shrinks: int = 0\n        self.finish_shrinking_deadline: float | None = None\n        self.call_count: int = 0\n        self.misaligned_count: int = 0\n        self.valid_examples: int = 0\n        self.invalid_examples: int = 0\n        self.overrun_examples: int = 0\n        self.random: Random = random or Random(_random.getrandbits(128))\n        self.database_key: bytes | None = database_key\n        self.ignore_limits: bool = ignore_limits\n        self.thread_overlap = {} if thread_overlap is None else thread_overlap\n\n        # Global dict of per-phase statistics, and a list of per-call stats\n        # which transfer to the global dict at the end of each phase.\n        self._current_phase: str = \"(not a phase)\"\n        self.statistics: StatisticsDict = {}\n        self.stats_per_test_case: list[CallStats] = []\n\n        self.interesting_examples: dict[InterestingOrigin, ConjectureResult] = {}\n        # We use call_count because there may be few possible valid_examples.\n        self.first_bug_found_at: int | None = None\n        self.last_bug_found_at: int | None = None\n        self.first_bug_found_time: float = math.inf\n\n        self.shrunk_examples: set[InterestingOrigin] = set()\n        self.health_check_state: HealthCheckState | None = None\n        self.tree: DataTree = DataTree()\n        self.provider: PrimitiveProvider | type[PrimitiveProvider] = _get_provider(\n            self.settings.backend\n        )\n\n        self.best_observed_targets: defaultdict[str, float] = defaultdict(\n            lambda: NO_SCORE\n        )\n        self.best_examples_of_observed_targets: dict[str, ConjectureResult] = {}\n\n        # We keep the pareto front in the example database if we have one. This\n        # is only marginally useful at present, but speeds up local development\n        # because it means that large targets will be quickly surfaced in your\n        # testing.\n        self.pareto_front: ParetoFront | None = None\n        if self.database_key is not None and self.settings.database is not None:\n            self.pareto_front = ParetoFront(self.random)\n            self.pareto_front.on_evict(self.on_pareto_evict)\n\n        # We want to be able to get the ConjectureData object that results\n        # from running a choice sequence without recalculating, especially during\n        # shrinking where we need to know about the structure of the\n        # executed test case.\n        self.__data_cache = LRUReusedCache[\n            tuple[ChoiceKeyT, ...], ConjectureResult | _Overrun\n        ](CACHE_SIZE)\n\n        self.reused_previously_shrunk_test_case: bool = False\n\n        self.__pending_call_explanation: str | None = None\n        self._backend_found_failure: bool = False\n        self._backend_exceeded_deadline: bool = False\n        self._backend_discard_count: int = 0\n        # note unsound verification by alt backends\n        self._verified_by_backend: str | None = None\n        self._switch_to_hypothesis_provider: bool = False\n\n    @contextmanager\n    def _with_switch_to_hypothesis_provider(\n        self, value: bool\n    ) -> Generator[None, None, None]:\n        previous = self._switch_to_hypothesis_provider\n        try:\n            self._switch_to_hypothesis_provider = value\n            yield\n        finally:\n            self._switch_to_hypothesis_provider = previous\n\n    @property\n    def using_hypothesis_backend(self) -> bool:\n        return (\n            self.settings.backend == \"hypothesis\" or self._switch_to_hypothesis_provider\n        )\n\n    def explain_next_call_as(self, explanation: str) -> None:\n        self.__pending_call_explanation = explanation\n\n    def clear_call_explanation(self) -> None:\n        self.__pending_call_explanation = None\n\n    @contextmanager\n    def _log_phase_statistics(\n        self, phase: Literal[\"reuse\", \"generate\", \"shrink\"]\n    ) -> Generator[None, None, None]:\n        self.stats_per_test_case.clear()\n        start_time = time.perf_counter()\n        try:\n            self._current_phase = phase\n            yield\n        finally:\n            self.statistics[phase + \"-phase\"] = {  # type: ignore\n                \"duration-seconds\": time.perf_counter() - start_time,\n                \"test-cases\": list(self.stats_per_test_case),\n                \"distinct-failures\": len(self.interesting_examples),\n                \"shrinks-successful\": self.shrinks,\n            }\n\n    @property\n    def should_optimise(self) -> bool:\n        return Phase.target in self.settings.phases\n\n    def __tree_is_exhausted(self) -> bool:\n        return self.tree.is_exhausted and self.using_hypothesis_backend\n\n    def __stoppable_test_function(self, data: ConjectureData) -> None:\n        \"\"\"Run ``self._test_function``, but convert a ``StopTest`` exception\n        into a normal return and avoid raising anything flaky for RecursionErrors.\n        \"\"\"\n        # We ensure that the test has this much stack space remaining, no\n        # matter the size of the stack when called, to de-flake RecursionErrors\n        # (#2494, #3671). Note, this covers the data generation part of the test;\n        # the actual test execution is additionally protected at the call site\n        # in hypothesis.core.execute_once.\n        with ensure_free_stackframes():\n            try:\n                self._test_function(data)\n            except StopTest as e:\n                if e.testcounter == data.testcounter:\n                    # This StopTest has successfully stopped its test, and can now\n                    # be discarded.\n                    pass\n                else:\n                    # This StopTest was raised by a different ConjectureData. We\n                    # need to re-raise it so that it will eventually reach the\n                    # correct engine.\n                    raise\n\n    def _cache_key(self, choices: Sequence[ChoiceT]) -> tuple[ChoiceKeyT, ...]:\n        return choices_key(choices)\n\n    def _cache(self, data: ConjectureData) -> None:\n        result = data.as_result()\n        key = self._cache_key(data.choices)\n        self.__data_cache[key] = result\n\n    def cached_test_function(\n        self,\n        choices: Sequence[ChoiceT | ChoiceTemplate],\n        *,\n        error_on_discard: bool = False,\n        extend: int | Literal[\"full\"] = 0,\n    ) -> ConjectureResult | _Overrun:\n        \"\"\"\n        If ``error_on_discard`` is set to True this will raise ``ContainsDiscard``\n        in preference to running the actual test function. This is to allow us\n        to skip test cases we expect to be redundant in some cases. Note that\n        it may be the case that we don't raise ``ContainsDiscard`` even if the\n        result has discards if we cannot determine from previous runs whether\n        it will have a discard.\n        \"\"\"\n        # node templates represent a not-yet-filled hole and therefore cannot\n        # be cached or retrieved from the cache.\n        if not any(isinstance(choice, ChoiceTemplate) for choice in choices):\n            # this type cast is validated by the isinstance check above (ie, there\n            # are no ChoiceTemplate elements).\n            choices = cast(Sequence[ChoiceT], choices)\n            key = self._cache_key(choices)\n            try:\n                cached = self.__data_cache[key]\n                # if we have a cached overrun for this key, but we're allowing extensions\n                # of the nodes, it could in fact run to a valid data if we try.\n                if extend == 0 or cached.status is not Status.OVERRUN:\n                    return cached\n            except KeyError:\n                pass\n\n        if extend == \"full\":\n            max_length = None\n        elif (count := choice_count(choices)) is None:\n            max_length = None\n        else:\n            max_length = count + extend\n\n        # explicitly use a no-op DataObserver here instead of a TreeRecordingObserver.\n        # The reason is we don't expect simulate_test_function to explore new choices\n        # and write back to the tree, so we don't want the overhead of the\n        # TreeRecordingObserver tracking those calls.\n        trial_observer: DataObserver | None = DataObserver()\n        if error_on_discard:\n            trial_observer = DiscardObserver()\n\n        try:\n            trial_data = self.new_conjecture_data(\n                choices, observer=trial_observer, max_choices=max_length\n            )\n            self.tree.simulate_test_function(trial_data)\n        except PreviouslyUnseenBehaviour:\n            pass\n        else:\n            trial_data.freeze()\n            key = self._cache_key(trial_data.choices)\n            if trial_data.status > Status.OVERRUN:\n                try:\n                    return self.__data_cache[key]\n                except KeyError:\n                    pass\n            else:\n                # if we simulated to an overrun, then we our result is certainly\n                # an overrun; no need to consult the cache. (and we store this result\n                # for simulation-less lookup later).\n                self.__data_cache[key] = Overrun\n                return Overrun\n            try:\n                return self.__data_cache[key]\n            except KeyError:\n                pass\n\n        data = self.new_conjecture_data(choices, max_choices=max_length)\n        # note that calling test_function caches `data` for us.\n        self.test_function(data)\n        return data.as_result()\n\n    def test_function(self, data: ConjectureData) -> None:\n        if self.__pending_call_explanation is not None:\n            self.debug(self.__pending_call_explanation)\n            self.__pending_call_explanation = None\n\n        self.call_count += 1\n        interrupted = False\n\n        def _backend_cannot_proceed(\n            exc: BackendCannotProceed, data: ConjectureData\n        ) -> None:\n            if exc.scope in (\"verified\", \"exhausted\"):\n                self._switch_to_hypothesis_provider = True\n                if exc.scope == \"verified\":\n                    self._verified_by_backend = self.settings.backend\n            elif exc.scope == \"discard_test_case\":\n                self._backend_discard_count += 1\n                if (\n                    self._backend_discard_count > 10\n                    and (self._backend_discard_count / self.call_count) > 0.2\n                ):\n                    verbose_report(\n                        f\"Switching away from backend {self.settings.backend!r} \"\n                        \"to the Hypothesis backend, \"\n                        f\"because {self._backend_discard_count} of {self.call_count} \"\n                        \"attempted test cases \"\n                        f\"({self._backend_discard_count / self.call_count * 100:0.1f}%) \"\n                        f\"were discarded by backend {self.settings.backend!r}\"\n                    )\n                    self._switch_to_hypothesis_provider = True\n\n            # treat all BackendCannotProceed exceptions as invalid. This isn't\n            # great; \"verified\" should really be counted as self.valid_examples += 1.\n            # But we check self.valid_examples == 0 to determine whether to raise\n            # Unsatisfiable, and that would throw this check off.\n            self.invalid_examples += 1\n            data.cannot_proceed_scope = exc.scope\n\n        # this fiddly bit of control flow is to work around `return` being\n        # disallowed in `finally` blocks as of python 3.14. Otherwise, we would\n        # just return in the _backend_cannot_proceed branch.\n        finally_early_return = False\n\n        try:\n            self.__stoppable_test_function(data)\n        except KeyboardInterrupt:\n            interrupted = True\n            raise\n        except BackendCannotProceed as exc:\n            _backend_cannot_proceed(exc, data)\n            # skip the post-test-case tracking; we're pretending this never happened\n            interrupted = True\n            data.freeze()\n            return\n        except BaseException:\n            data.freeze()\n            if self.settings.backend != \"hypothesis\":\n                try:\n                    realize_choices(data, for_failure=True)\n                except BackendCannotProceed as exc:\n                    _backend_cannot_proceed(exc, data)\n                    # skip the post-test-case tracking; we're pretending this\n                    # never happened\n                    interrupted = True\n                    return\n            self.save_choices(data.choices)\n            raise\n        finally:\n            # No branch, because if we're interrupted we always raise\n            # the KeyboardInterrupt, never continue to the code below.\n            if not interrupted:  # pragma: no branch\n                assert data.cannot_proceed_scope is None\n                data.freeze()\n\n                if self.settings.backend != \"hypothesis\":\n                    try:\n                        realize_choices(\n                            data, for_failure=data.status is Status.INTERESTING\n                        )\n                    except BackendCannotProceed as exc:\n                        _backend_cannot_proceed(exc, data)\n                        finally_early_return = True\n\n                if not finally_early_return:\n                    call_stats: CallStats = {\n                        \"status\": data.status.name.lower(),\n                        \"runtime\": data.finish_time - data.start_time,\n                        \"drawtime\": math.fsum(data.draw_times.values()),\n                        \"gctime\": data.gc_finish_time - data.gc_start_time,\n                        \"events\": sorted(\n                            k if v == \"\" else f\"{k}: {v}\"\n                            for k, v in data.events.items()\n                        ),\n                    }\n                    self.stats_per_test_case.append(call_stats)\n\n                    self._cache(data)\n                    if (\n                        data.misaligned_at is not None\n                    ):  # pragma: no branch # coverage bug?\n                        self.misaligned_count += 1\n\n        if finally_early_return:\n            return\n\n        self.debug_data(data)\n\n        if (\n            data.target_observations\n            and self.pareto_front is not None\n            and self.pareto_front.add(data.as_result())\n        ):\n            self.save_choices(data.choices, sub_key=b\"pareto\")\n\n        if data.status >= Status.VALID:\n            for k, v in data.target_observations.items():\n                self.best_observed_targets[k] = max(self.best_observed_targets[k], v)\n\n                if k not in self.best_examples_of_observed_targets:\n                    data_as_result = data.as_result()\n                    assert not isinstance(data_as_result, _Overrun)\n                    self.best_examples_of_observed_targets[k] = data_as_result\n                    continue\n\n                existing_example = self.best_examples_of_observed_targets[k]\n                existing_score = existing_example.target_observations[k]\n\n                if v < existing_score:\n                    continue\n\n                if v > existing_score or sort_key(data.nodes) < sort_key(\n                    existing_example.nodes\n                ):\n                    data_as_result = data.as_result()\n                    assert not isinstance(data_as_result, _Overrun)\n                    self.best_examples_of_observed_targets[k] = data_as_result\n\n        if data.status is Status.VALID:\n            self.valid_examples += 1\n        if data.status is Status.INVALID:\n            self.invalid_examples += 1\n        if data.status is Status.OVERRUN:\n            self.overrun_examples += 1\n\n        if data.status == Status.INTERESTING:\n            if not self.using_hypothesis_backend:\n                # replay this failure on the hypothesis backend to ensure it still\n                # finds a failure. otherwise, it is flaky.\n                initial_exception = data.expected_exception\n                data = ConjectureData.for_choices(data.choices)\n                # we've already going to use the hypothesis provider for this\n                # data, so the verb \"switch\" is a bit misleading here. We're really\n                # setting this to inform our on_observation logic that the observation\n                # generated here was from a hypothesis backend, and shouldn't be\n                # sent to the on_observation of any alternative backend.\n                with self._with_switch_to_hypothesis_provider(True):\n                    self.__stoppable_test_function(data)\n                data.freeze()\n                # TODO: Should same-origin also be checked? (discussion in\n                # https://github.com/HypothesisWorks/hypothesis/pull/4470#discussion_r2217055487)\n                if data.status != Status.INTERESTING:\n                    desc_new_status = {\n                        data.status.VALID: \"passed\",\n                        data.status.INVALID: \"failed filters\",\n                        data.status.OVERRUN: \"overran\",\n                    }[data.status]\n                    raise FlakyBackendFailure(\n                        f\"Inconsistent results from replaying a failing test case! \"\n                        f\"Raised {type(initial_exception).__name__} on \"\n                        f\"backend={self.settings.backend!r}, but \"\n                        f\"{desc_new_status} under backend='hypothesis'.\",\n                        [initial_exception],\n                    )\n\n                self._cache(data)\n\n            assert data.interesting_origin is not None\n            key = data.interesting_origin\n            changed = False\n            try:\n                existing = self.interesting_examples[key]\n            except KeyError:\n                changed = True\n                self.last_bug_found_at = self.call_count\n                if self.first_bug_found_at is None:\n                    self.first_bug_found_at = self.call_count\n                    self.first_bug_found_time = time.monotonic()\n            else:\n                if sort_key(data.nodes) < sort_key(existing.nodes):\n                    self.shrinks += 1\n                    self.downgrade_choices(existing.choices)\n                    self.__data_cache.unpin(self._cache_key(existing.choices))\n                    changed = True\n\n            if changed:\n                self.save_choices(data.choices)\n                self.interesting_examples[key] = data.as_result()  # type: ignore\n                if not self.using_hypothesis_backend:\n                    self._backend_found_failure = True\n                self.__data_cache.pin(self._cache_key(data.choices), data.as_result())\n                self.shrunk_examples.discard(key)\n\n            if self.shrinks >= MAX_SHRINKS:\n                self.exit_with(ExitReason.max_shrinks)\n\n        if (\n            not self.ignore_limits\n            and self.finish_shrinking_deadline is not None\n            and self.finish_shrinking_deadline < time.perf_counter()\n        ):\n            # See https://github.com/HypothesisWorks/hypothesis/issues/2340\n            report(\n                \"WARNING: Hypothesis has spent more than five minutes working to shrink\"\n                \" a failing example, and stopped because it is making very slow\"\n                \" progress.  When you re-run your tests, shrinking will resume and may\"\n                \" take this long before aborting again.\\nPLEASE REPORT THIS if you can\"\n                \" provide a reproducing example, so that we can improve shrinking\"\n                \" performance for everyone.\"\n            )\n            self.exit_with(ExitReason.very_slow_shrinking)\n\n        if not self.interesting_examples:\n            # Note that this logic is reproduced to end the generation phase when\n            # we have interesting examples.  Update that too if you change this!\n            # (The doubled implementation is because here we exit the engine entirely,\n            #  while in the other case below we just want to move on to shrinking.)\n            if self.valid_examples >= self.settings.max_examples:\n                self.exit_with(ExitReason.max_examples)\n            if (self.invalid_examples + self.overrun_examples) > (\n                INVALID_THRESHOLD_BASE + INVALID_PER_VALID * self.valid_examples\n            ):\n                self.exit_with(ExitReason.max_iterations)\n\n        if self.__tree_is_exhausted():\n            self.exit_with(ExitReason.finished)\n\n        self.record_for_health_check(data)\n\n    def on_pareto_evict(self, data: ConjectureResult) -> None:\n        self.settings.database.delete(self.pareto_key, choices_to_bytes(data.choices))\n\n    def generate_novel_prefix(self) -> tuple[ChoiceT, ...]:\n        \"\"\"Uses the tree to proactively generate a starting choice sequence\n        that we haven't explored yet for this test.\n\n        When this method is called, we assume that there must be at\n        least one novel prefix left to find. If there were not, then the\n        test run should have already stopped due to tree exhaustion.\n        \"\"\"\n        return self.tree.generate_novel_prefix(self.random)\n\n    def record_for_health_check(self, data: ConjectureData) -> None:\n        # Once we've actually found a bug, there's no point in trying to run\n        # health checks - they'll just mask the actually important information.\n        if data.status == Status.INTERESTING:\n            self.health_check_state = None\n\n        state = self.health_check_state\n\n        if state is None:\n            return\n\n        for k, v in data.draw_times.items():\n            state.draw_times[k].append(v)\n\n        if data.status == Status.VALID:\n            state.valid_examples += 1\n        elif data.status == Status.INVALID:\n            state.invalid_examples += 1\n        else:\n            assert data.status == Status.OVERRUN\n            state.overrun_examples += 1\n\n        max_valid_draws = 10\n        max_invalid_draws = 50\n        max_overrun_draws = 20\n\n        assert state.valid_examples <= max_valid_draws\n\n        if state.valid_examples == max_valid_draws:\n            self.health_check_state = None\n            return\n\n        if state.overrun_examples == max_overrun_draws:\n            fail_health_check(\n                self.settings,\n                \"Generated inputs routinely consumed more than the maximum \"\n                f\"allowed entropy: {state.valid_examples} inputs were generated \"\n                f\"successfully, while {state.overrun_examples} inputs exceeded the \"\n                f\"maximum allowed entropy during generation.\"\n                \"\\n\\n\"\n                f\"Testing with inputs this large tends to be slow, and to produce \"\n                \"failures that are both difficult to shrink and difficult to understand. \"\n                \"Try decreasing the amount of data generated, for example by \"\n                \"decreasing the minimum size of collection strategies like \"\n                \"st.lists().\"\n                \"\\n\\n\"\n                \"If you expect the average size of your input to be this large, \"\n                \"you can disable this health check with \"\n                \"@settings(suppress_health_check=[HealthCheck.data_too_large]). \"\n                \"See \"\n                \"https://hypothesis.readthedocs.io/en/latest/reference/api.html#hypothesis.HealthCheck \"\n                \"for details.\",\n                HealthCheck.data_too_large,\n            )\n        if state.invalid_examples == max_invalid_draws:\n            fail_health_check(\n                self.settings,\n                \"It looks like this test is filtering out a lot of inputs. \"\n                f\"{state.valid_examples} inputs were generated successfully, \"\n                f\"while {state.invalid_examples} inputs were filtered out. \"\n                \"\\n\\n\"\n                \"An input might be filtered out by calls to assume(), \"\n                \"strategy.filter(...), or occasionally by Hypothesis internals.\"\n                \"\\n\\n\"\n                \"Applying this much filtering makes input generation slow, since \"\n                \"Hypothesis must discard inputs which are filtered out and try \"\n                \"generating it again. It is also possible that applying this much \"\n                \"filtering will distort the domain and/or distribution of the test, \"\n                \"leaving your testing less rigorous than expected.\"\n                \"\\n\\n\"\n                \"If you expect this many inputs to be filtered out during generation, \"\n                \"you can disable this health check with \"\n                \"@settings(suppress_health_check=[HealthCheck.filter_too_much]). See \"\n                \"https://hypothesis.readthedocs.io/en/latest/reference/api.html#hypothesis.HealthCheck \"\n                \"for details.\",\n                HealthCheck.filter_too_much,\n            )\n\n        # Allow at least the greater of one second or 5x the deadline.  If deadline\n        # is None, allow 30s - the user can disable the healthcheck too if desired.\n        draw_time = state.total_draw_time\n        draw_time_limit = 5 * (self.settings.deadline or timedelta(seconds=6))\n        if (\n            draw_time > max(1.0, draw_time_limit.total_seconds())\n            # we disable HealthCheck.too_slow under concurrent threads, since\n            # cpython may switch away from a thread for arbitrarily long.\n            and not self.thread_overlap.get(threading.get_ident(), False)\n        ):\n            extra_str = []\n            if state.invalid_examples:\n                extra_str.append(f\"{state.invalid_examples} invalid inputs\")\n            if state.overrun_examples:\n                extra_str.append(\n                    f\"{state.overrun_examples} inputs which exceeded the \"\n                    \"maximum allowed entropy\"\n                )\n            extra_str = \", and \".join(extra_str)\n            extra_str = f\" ({extra_str})\" if extra_str else \"\"\n\n            fail_health_check(\n                self.settings,\n                \"Input generation is slow: Hypothesis only generated \"\n                f\"{state.valid_examples} valid inputs after {draw_time:.2f} \"\n                f\"seconds{extra_str}.\"\n                \"\\n\" + state.timing_report() + \"\\n\\n\"\n                \"This could be for a few reasons:\"\n                \"\\n\"\n                \"1. This strategy could be generating too much data per input. \"\n                \"Try decreasing the amount of data generated, for example by \"\n                \"decreasing the minimum size of collection strategies like \"\n                \"st.lists().\"\n                \"\\n\"\n                \"2. Some other expensive computation could be running during input \"\n                \"generation. For example, \"\n                \"if @st.composite or st.data() is interspersed with an expensive \"\n                \"computation, HealthCheck.too_slow is likely to trigger. If this \"\n                \"computation is unrelated to input generation, move it elsewhere. \"\n                \"Otherwise, try making it more efficient, or disable this health \"\n                \"check if that is not possible.\"\n                \"\\n\\n\"\n                \"If you expect input generation to take this long, you can disable \"\n                \"this health check with \"\n                \"@settings(suppress_health_check=[HealthCheck.too_slow]). See \"\n                \"https://hypothesis.readthedocs.io/en/latest/reference/api.html#hypothesis.HealthCheck \"\n                \"for details.\",\n                HealthCheck.too_slow,\n            )\n\n    def save_choices(\n        self, choices: Sequence[ChoiceT], sub_key: bytes | None = None\n    ) -> None:\n        if self.settings.database is not None:\n            key = self.sub_key(sub_key)\n            if key is None:\n                return\n            self.settings.database.save(key, choices_to_bytes(choices))\n\n    def downgrade_choices(self, choices: Sequence[ChoiceT]) -> None:\n        buffer = choices_to_bytes(choices)\n        if self.settings.database is not None and self.database_key is not None:\n            self.settings.database.move(self.database_key, self.secondary_key, buffer)\n\n    def sub_key(self, sub_key: bytes | None) -> bytes | None:\n        if self.database_key is None:\n            return None\n        if sub_key is None:\n            return self.database_key\n        return b\".\".join((self.database_key, sub_key))\n\n    @property\n    def secondary_key(self) -> bytes | None:\n        return self.sub_key(b\"secondary\")\n\n    @property\n    def pareto_key(self) -> bytes | None:\n        return self.sub_key(b\"pareto\")\n\n    def debug(self, message: str) -> None:\n        if self.settings.verbosity >= Verbosity.debug:\n            base_report(message)\n\n    @property\n    def report_debug_info(self) -> bool:\n        return self.settings.verbosity >= Verbosity.debug\n\n    def debug_data(self, data: ConjectureData | ConjectureResult) -> None:\n        if not self.report_debug_info:\n            return\n\n        status = repr(data.status)\n        if data.status == Status.INTERESTING:\n            status = f\"{status} ({data.interesting_origin!r})\"\n        elif data.status == Status.INVALID and isinstance(data, ConjectureData):\n            assert isinstance(data, ConjectureData)  # mypy is silly\n            status = f\"{status} ({data.events.get('invalid because', '?')})\"\n\n        newline_tab = \"\\n\\t\"\n        self.debug(\n            f\"{len(data.choices)} choices -> {status}\\n\\t{data.choices}\"\n            f\"{newline_tab + data.output if data.output else ''}\"\n        )\n\n    def observe_for_provider(self) -> AbstractContextManager:\n        def on_observation(observation: Observation) -> None:\n            assert observation.type == \"test_case\"\n            # because lifetime == \"test_function\"\n            assert isinstance(self.provider, PrimitiveProvider)\n            # only fire if we actually used that provider to generate this observation\n            if not self._switch_to_hypothesis_provider:\n                self.provider.on_observation(observation)\n\n        if (\n            self.settings.backend != \"hypothesis\"\n            # only for lifetime = \"test_function\" providers (guaranteed\n            # by this isinstance check)\n            and isinstance(self.provider, PrimitiveProvider)\n            # and the provider opted-in to observations\n            and self.provider.add_observability_callback\n        ):\n            return with_observability_callback(on_observation)\n        return nullcontext()\n\n    def run(self) -> None:\n        with local_settings(self.settings), self.observe_for_provider():\n            try:\n                self._run()\n            except RunIsComplete:\n                pass\n            for v in self.interesting_examples.values():\n                self.debug_data(v)\n            self.debug(\n                f\"Run complete after {self.call_count} examples \"\n                f\"({self.valid_examples} valid) and {self.shrinks} shrinks\"\n            )\n\n    @property\n    def database(self) -> ExampleDatabase | None:\n        if self.database_key is None:\n            return None\n        return self.settings.database\n\n    def has_existing_examples(self) -> bool:\n        return self.database is not None and Phase.reuse in self.settings.phases\n\n    def reuse_existing_examples(self) -> None:\n        \"\"\"If appropriate (we have a database and have been told to use it),\n        try to reload existing examples from the database.\n\n        If there are a lot we don't try all of them. We always try the\n        smallest example in the database (which is guaranteed to be the\n        last failure) and the largest (which is usually the seed example\n        which the last failure came from but we don't enforce that). We\n        then take a random sampling of the remainder and try those. Any\n        examples that are no longer interesting are cleared out.\n        \"\"\"\n        if self.has_existing_examples():\n            self.debug(\"Reusing examples from database\")\n            # We have to do some careful juggling here. We have two database\n            # corpora: The primary and secondary. The primary corpus is a\n            # small set of minimized examples each of which has at one point\n            # demonstrated a distinct bug. We want to retry all of these.\n\n            # We also have a secondary corpus of examples that have at some\n            # point demonstrated interestingness (currently only ones that\n            # were previously non-minimal examples of a bug, but this will\n            # likely expand in future). These are a good source of potentially\n            # interesting examples, but there are a lot of them, so we down\n            # sample the secondary corpus to a more manageable size.\n\n            corpus = sorted(\n                self.settings.database.fetch(self.database_key), key=shortlex\n            )\n            factor = 0.1 if (Phase.generate in self.settings.phases) else 1\n            desired_size = max(2, ceil(factor * self.settings.max_examples))\n            primary_corpus_size = len(corpus)\n\n            if len(corpus) < desired_size:\n                extra_corpus = list(self.settings.database.fetch(self.secondary_key))\n\n                shortfall = desired_size - len(corpus)\n\n                if len(extra_corpus) <= shortfall:\n                    extra = extra_corpus\n                else:\n                    extra = self.random.sample(extra_corpus, shortfall)\n                extra.sort(key=shortlex)\n                corpus.extend(extra)\n\n            # We want a fast path where every primary entry in the database was\n            # interesting.\n            found_interesting_in_primary = False\n            all_interesting_in_primary_were_exact = True\n\n            for i, existing in enumerate(corpus):\n                if i >= primary_corpus_size and found_interesting_in_primary:\n                    break\n                choices = choices_from_bytes(existing)\n                if choices is None:\n                    # clear out any keys which fail deserialization\n                    self.settings.database.delete(self.database_key, existing)\n                    continue\n                data = self.cached_test_function(choices, extend=\"full\")\n                if data.status != Status.INTERESTING:\n                    self.settings.database.delete(self.database_key, existing)\n                    self.settings.database.delete(self.secondary_key, existing)\n                else:\n                    if i < primary_corpus_size:\n                        found_interesting_in_primary = True\n                        assert not isinstance(data, _Overrun)\n                        if choices_key(choices) != choices_key(data.choices):\n                            all_interesting_in_primary_were_exact = False\n                    if not self.settings.report_multiple_bugs:\n                        break\n            if found_interesting_in_primary:\n                if all_interesting_in_primary_were_exact:\n                    self.reused_previously_shrunk_test_case = True\n\n            # Because self.database is not None (because self.has_existing_examples())\n            # and self.database_key is not None (because we fetched using it above),\n            # we can guarantee self.pareto_front is not None\n            assert self.pareto_front is not None\n\n            # If we've not found any interesting examples so far we try some of\n            # the pareto front from the last run.\n            if len(corpus) < desired_size and not self.interesting_examples:\n                desired_extra = desired_size - len(corpus)\n                pareto_corpus = list(self.settings.database.fetch(self.pareto_key))\n                if len(pareto_corpus) > desired_extra:\n                    pareto_corpus = self.random.sample(pareto_corpus, desired_extra)\n                pareto_corpus.sort(key=shortlex)\n\n                for existing in pareto_corpus:\n                    choices = choices_from_bytes(existing)\n                    if choices is None:\n                        self.settings.database.delete(self.pareto_key, existing)\n                        continue\n                    data = self.cached_test_function(choices, extend=\"full\")\n                    if data not in self.pareto_front:\n                        self.settings.database.delete(self.pareto_key, existing)\n                    if data.status == Status.INTERESTING:\n                        break\n\n    def exit_with(self, reason: ExitReason) -> None:\n        if self.ignore_limits:\n            return\n        self.statistics[\"stopped-because\"] = reason.describe(self.settings)\n        if self.best_observed_targets:\n            self.statistics[\"targets\"] = dict(self.best_observed_targets)\n        self.debug(f\"exit_with({reason.name})\")\n        self.exit_reason = reason\n        raise RunIsComplete\n\n    def should_generate_more(self) -> bool:\n        # End the generation phase where we would have ended it if no bugs had\n        # been found.  This reproduces the exit logic in `self.test_function`,\n        # but with the important distinction that this clause will move on to\n        # the shrinking phase having found one or more bugs, while the other\n        # will exit having found zero bugs.\n        invalid_threshold = (\n            INVALID_THRESHOLD_BASE + INVALID_PER_VALID * self.valid_examples\n        )\n        if (\n            self.valid_examples >= self.settings.max_examples\n            or (self.invalid_examples + self.overrun_examples) > invalid_threshold\n        ):  # pragma: no cover\n            return False\n\n        # If we haven't found a bug, keep looking - if we hit any limits on\n        # the number of tests to run that will raise an exception and stop\n        # the run.\n        if not self.interesting_examples:\n            return True\n        # Users who disable shrinking probably want to exit as fast as possible.\n        # If we've found a bug and won't report more than one, stop looking.\n        # If we first saw a bug more than 10 seconds ago, stop looking.\n        elif (\n            Phase.shrink not in self.settings.phases\n            or not self.settings.report_multiple_bugs\n            or time.monotonic() - self.first_bug_found_time > 10\n        ):\n            return False\n        assert isinstance(self.first_bug_found_at, int)\n        assert isinstance(self.last_bug_found_at, int)\n        assert self.first_bug_found_at <= self.last_bug_found_at <= self.call_count\n        # Otherwise, keep searching for between ten and 'a heuristic' calls.\n        # We cap 'calls after first bug' so errors are reported reasonably\n        # soon even for tests that are allowed to run for a very long time,\n        # or sooner if the latest half of our test effort has been fruitless.\n        return self.call_count < MIN_TEST_CALLS or self.call_count < min(\n            self.first_bug_found_at + 1000, self.last_bug_found_at * 2\n        )\n\n    def generate_new_examples(self) -> None:\n        if Phase.generate not in self.settings.phases:\n            return\n        if self.interesting_examples:\n            # The example database has failing examples from a previous run,\n            # so we'd rather report that they're still failing ASAP than take\n            # the time to look for additional failures.\n            return\n\n        self.debug(\"Generating new examples\")\n\n        assert self.should_generate_more()\n        self._switch_to_hypothesis_provider = True\n        zero_data = self.cached_test_function((ChoiceTemplate(\"simplest\", count=None),))\n        if zero_data.status > Status.OVERRUN:\n            assert isinstance(zero_data, ConjectureResult)\n            # if the crosshair backend cannot proceed, it does not (and cannot)\n            # realize the symbolic values, with the intent that Hypothesis will\n            # throw away this test case. We usually do, but if it's the zero data\n            # then we try to pin it here, which requires realizing the symbolics.\n            #\n            # We don't (yet) rely on the zero data being pinned, and so\n            # it's simply a very slight performance loss to simply not pin it\n            # if doing so would error.\n            if zero_data.cannot_proceed_scope is None:  # pragma: no branch\n                self.__data_cache.pin(\n                    self._cache_key(zero_data.choices), zero_data.as_result()\n                )  # Pin forever\n\n        if zero_data.status == Status.OVERRUN or (\n            zero_data.status == Status.VALID\n            and isinstance(zero_data, ConjectureResult)\n            and zero_data.length * 2 > BUFFER_SIZE\n        ):\n            fail_health_check(\n                self.settings,\n                \"The smallest natural input for this test is very \"\n                \"large. This makes it difficult for Hypothesis to generate \"\n                \"good inputs, especially when trying to shrink failing inputs.\"\n                \"\\n\\n\"\n                \"Consider reducing the amount of data generated by the strategy. \"\n                \"Also consider introducing small alternative values for some \"\n                \"strategies. For example, could you \"\n                \"mark some arguments as optional by replacing `some_complex_strategy`\"\n                \"with `st.none() | some_complex_strategy`?\"\n                \"\\n\\n\"\n                \"If you are confident that the size of the smallest natural input \"\n                \"to your test cannot be reduced, you can suppress this health check \"\n                \"with @settings(suppress_health_check=[HealthCheck.large_base_example]). \"\n                \"See \"\n                \"https://hypothesis.readthedocs.io/en/latest/reference/api.html#hypothesis.HealthCheck \"\n                \"for details.\",\n                HealthCheck.large_base_example,\n            )\n\n        self.health_check_state = HealthCheckState()\n\n        # We attempt to use the size of the minimal generated test case starting\n        # from a given novel prefix as a guideline to generate smaller test\n        # cases for an initial period, by restriscting ourselves to test cases\n        # that are not much larger than it.\n        #\n        # Calculating the actual minimal generated test case is hard, so we\n        # take a best guess that zero extending a prefix produces the minimal\n        # test case starting with that prefix (this is true for our built in\n        # strategies). This is only a reasonable thing to do if the resulting\n        # test case is valid. If we regularly run into situations where it is\n        # not valid then this strategy is a waste of time, so we want to\n        # abandon it early. In order to do this we track how many times in a\n        # row it has failed to work, and abort small test case generation when\n        # it has failed too many times in a row.\n        consecutive_zero_extend_is_invalid = 0\n\n        # We control growth during initial example generation, for two\n        # reasons:\n        #\n        # * It gives us an opportunity to find small examples early, which\n        #   gives us a fast path for easy to find bugs.\n        # * It avoids low probability events where we might end up\n        #   generating very large examples during health checks, which\n        #   on slower machines can trigger HealthCheck.too_slow.\n        #\n        # The heuristic we use is that we attempt to estimate the smallest\n        # extension of this prefix, and limit the size to no more than\n        # an order of magnitude larger than that. If we fail to estimate\n        # the size accurately, we skip over this prefix and try again.\n        #\n        # We need to tune the example size based on the initial prefix,\n        # because any fixed size might be too small, and any size based\n        # on the strategy in general can fall afoul of strategies that\n        # have very different sizes for different prefixes.\n        #\n        # We previously set a minimum value of 10 on small_example_cap, with the\n        # reasoning of avoiding flaky health checks. However, some users set a\n        # low max_examples for performance. A hard lower bound in this case biases\n        # the distribution towards small (and less powerful) examples. Flaky\n        # and loud health checks are better than silent performance degradation.\n        small_example_cap = min(self.settings.max_examples // 10, 50)\n        optimise_at = max(self.settings.max_examples // 2, small_example_cap + 1, 10)\n        ran_optimisations = False\n        self._switch_to_hypothesis_provider = False\n\n        while self.should_generate_more():\n            # we don't yet integrate DataTree with backends. Instead of generating\n            # a novel prefix, ask the backend for an input.\n            if not self.using_hypothesis_backend:\n                data = self.new_conjecture_data([])\n                self.test_function(data)\n                continue\n\n            self._current_phase = \"generate\"\n            prefix = self.generate_novel_prefix()\n            if (\n                self.valid_examples <= small_example_cap\n                and self.call_count <= 5 * small_example_cap\n                and not self.interesting_examples\n                and consecutive_zero_extend_is_invalid < 5\n            ):\n                minimal_example = self.cached_test_function(\n                    prefix + (ChoiceTemplate(\"simplest\", count=None),)\n                )\n\n                if minimal_example.status < Status.VALID:\n                    consecutive_zero_extend_is_invalid += 1\n                    continue\n                # Because the Status code is greater than Status.VALID, it cannot be\n                # Status.OVERRUN, which guarantees that the minimal_example is a\n                # ConjectureResult object.\n                assert isinstance(minimal_example, ConjectureResult)\n                consecutive_zero_extend_is_invalid = 0\n                minimal_extension = len(minimal_example.choices) - len(prefix)\n                max_length = len(prefix) + minimal_extension * 5\n\n                # We could end up in a situation where even though the prefix was\n                # novel when we generated it, because we've now tried zero extending\n                # it not all possible continuations of it will be novel. In order to\n                # avoid making redundant test calls, we rerun it in simulation mode\n                # first. If this has a predictable result, then we don't bother\n                # running the test function for real here. If however we encounter\n                # some novel behaviour, we try again with the real test function,\n                # starting from the new novel prefix that has discovered.\n                trial_data = self.new_conjecture_data(prefix, max_choices=max_length)\n                try:\n                    self.tree.simulate_test_function(trial_data)\n                    continue\n                except PreviouslyUnseenBehaviour:\n                    pass\n\n                # If the simulation entered part of the tree that has been killed,\n                # we don't want to run this.\n                assert isinstance(trial_data.observer, TreeRecordingObserver)\n                if trial_data.observer.killed:\n                    continue\n\n                # We might have hit the cap on number of examples we should\n                # run when calculating the minimal example.\n                if not self.should_generate_more():\n                    break\n\n                prefix = trial_data.choices\n            else:\n                max_length = None\n\n            data = self.new_conjecture_data(prefix, max_choices=max_length)\n            self.test_function(data)\n\n            if (\n                data.status is Status.OVERRUN\n                and max_length is not None\n                and \"invalid because\" not in data.events\n            ):\n                data.events[\"invalid because\"] = (\n                    \"reduced max size for early examples (avoids flaky health checks)\"\n                )\n\n            self.generate_mutations_from(data)\n\n            # Although the optimisations are logically a distinct phase, we\n            # actually normally run them as part of example generation. The\n            # reason for this is that we cannot guarantee that optimisation\n            # actually exhausts our budget: It might finish running and we\n            # discover that actually we still could run a bunch more test cases\n            # if we want.\n            if (\n                self.valid_examples >= max(small_example_cap, optimise_at)\n                and not ran_optimisations\n            ):\n                ran_optimisations = True\n                self._current_phase = \"target\"\n                self.optimise_targets()\n\n    def generate_mutations_from(self, data: ConjectureData | ConjectureResult) -> None:\n        # A thing that is often useful but rarely happens by accident is\n        # to generate the same value at multiple different points in the\n        # test case.\n        #\n        # Rather than make this the responsibility of individual strategies\n        # we implement a small mutator that just takes parts of the test\n        # case with the same label and tries replacing one of them with a\n        # copy of the other and tries running it. If we've made a good\n        # guess about what to put where, this will run a similar generated\n        # test case with more duplication.\n        if (\n            # An OVERRUN doesn't have enough information about the test\n            # case to mutate, so we just skip those.\n            data.status >= Status.INVALID\n            # This has a tendency to trigger some weird edge cases during\n            # generation so we don't let it run until we're done with the\n            # health checks.\n            and self.health_check_state is None\n        ):\n            initial_calls = self.call_count\n            failed_mutations = 0\n\n            while (\n                self.should_generate_more()\n                # We implement fairly conservative checks for how long we\n                # we should run mutation for, as it's generally not obvious\n                # how helpful it is for any given test case.\n                and self.call_count <= initial_calls + 5\n                and failed_mutations <= 5\n            ):\n                groups = data.spans.mutator_groups\n                if not groups:\n                    break\n\n                group = self.random.choice(groups)\n                (start1, end1), (start2, end2) = self.random.sample(sorted(group), 2)\n                if start1 > start2:\n                    (start1, end1), (start2, end2) = (start2, end2), (start1, end1)\n\n                if (\n                    start1 <= start2 <= end2 <= end1\n                ):  # pragma: no cover  # flaky on conjecture-cover tests\n                    # One span entirely contains the other. The strategy is very\n                    # likely some kind of tree. e.g. we might have\n                    #\n                    #                   ┌─────┐\n                    #             ┌─────┤  a  ├──────┐\n                    #             │     └─────┘      │\n                    #          ┌──┴──┐            ┌──┴──┐\n                    #       ┌──┤  b  ├──┐      ┌──┤  c  ├──┐\n                    #       │  └──┬──┘  │      │  └──┬──┘  │\n                    #     ┌─┴─┐ ┌─┴─┐ ┌─┴─┐  ┌─┴─┐ ┌─┴─┐ ┌─┴─┐\n                    #     │ d │ │ e │ │ f │  │ g │ │ h │ │ i │\n                    #     └───┘ └───┘ └───┘  └───┘ └───┘ └───┘\n                    #\n                    # where each node is drawn from the same strategy and so\n                    # has the same span label. We might have selected the spans\n                    # corresponding to the a and c nodes, which is the entire\n                    # tree and the subtree of (and including) c respectively.\n                    #\n                    # There are two possible mutations we could apply in this case:\n                    # 1. replace a with c (replace child with parent)\n                    # 2. replace c with a (replace parent with child)\n                    #\n                    # (1) results in multiple partial copies of the\n                    # parent:\n                    #                 ┌─────┐\n                    #           ┌─────┤  a  ├────────────┐\n                    #           │     └─────┘            │\n                    #        ┌──┴──┐                   ┌─┴───┐\n                    #     ┌──┤  b  ├──┐          ┌─────┤  a  ├──────┐\n                    #     │  └──┬──┘  │          │     └─────┘      │\n                    #   ┌─┴─┐ ┌─┴─┐ ┌─┴─┐     ┌──┴──┐            ┌──┴──┐\n                    #   │ d │ │ e │ │ f │  ┌──┤  b  ├──┐      ┌──┤  c  ├──┐\n                    #   └───┘ └───┘ └───┘  │  └──┬──┘  │      │  └──┬──┘  │\n                    #                    ┌─┴─┐ ┌─┴─┐ ┌─┴─┐  ┌─┴─┐ ┌─┴─┐ ┌─┴─┐\n                    #                    │ d │ │ e │ │ f │  │ g │ │ h │ │ i │\n                    #                    └───┘ └───┘ └───┘  └───┘ └───┘ └───┘\n                    #\n                    # While (2) results in truncating part of the parent:\n                    #\n                    #                    ┌─────┐\n                    #                 ┌──┤  c  ├──┐\n                    #                 │  └──┬──┘  │\n                    #               ┌─┴─┐ ┌─┴─┐ ┌─┴─┐\n                    #               │ g │ │ h │ │ i │\n                    #               └───┘ └───┘ └───┘\n                    #\n                    # (1) is the same as Example IV.4. in Nautilus (NDSS '19)\n                    # (https://wcventure.github.io/FuzzingPaper/Paper/NDSS19_Nautilus.pdf),\n                    # except we do not repeat the replacement additional times\n                    # (the paper repeats it once for a total of two copies).\n                    #\n                    # We currently only apply mutation (1), and ignore mutation\n                    # (2). The reason is that the attempt generated from (2) is\n                    # always something that Hypothesis could easily have generated\n                    # itself, by simply not making various choices. Whereas\n                    # duplicating the exact value + structure of particular choices\n                    # in (1) would have been hard for Hypothesis to generate by\n                    # chance.\n                    #\n                    # TODO: an extension of this mutation might repeat (1) on\n                    # a geometric distribution between 0 and ~10 times. We would\n                    # need to find the corresponding span to recurse on in the new\n                    # choices, probably just by using the choices index.\n\n                    # case (1): duplicate the choices in start1:start2.\n                    attempt = data.choices[:start2] + data.choices[start1:]\n                else:\n                    start, end = self.random.choice([(start1, end1), (start2, end2)])\n                    replacement = data.choices[start:end]\n                    # We attempt to replace both the examples with\n                    # whichever choice we made. Note that this might end\n                    # up messing up and getting the example boundaries\n                    # wrong - labels matching are only a best guess as to\n                    # whether the two are equivalent - but it doesn't\n                    # really matter. It may not achieve the desired result,\n                    # but it's still a perfectly acceptable choice sequence\n                    # to try.\n                    attempt = (\n                        data.choices[:start1]\n                        + replacement\n                        + data.choices[end1:start2]\n                        + replacement\n                        + data.choices[end2:]\n                    )\n\n                try:\n                    new_data = self.cached_test_function(\n                        attempt,\n                        # We set error_on_discard so that we don't end up\n                        # entering parts of the tree we consider redundant\n                        # and not worth exploring.\n                        error_on_discard=True,\n                    )\n                except ContainsDiscard:\n                    failed_mutations += 1\n                    continue\n\n                if new_data is Overrun:\n                    failed_mutations += 1  # pragma: no cover # annoying case\n                else:\n                    assert isinstance(new_data, ConjectureResult)\n                    if (\n                        new_data.status >= data.status\n                        and choices_key(data.choices) != choices_key(new_data.choices)\n                        and all(\n                            k in new_data.target_observations\n                            and new_data.target_observations[k] >= v\n                            for k, v in data.target_observations.items()\n                        )\n                    ):\n                        data = new_data\n                        failed_mutations = 0\n                    else:\n                        failed_mutations += 1\n\n    def optimise_targets(self) -> None:\n        \"\"\"If any target observations have been made, attempt to optimise them\n        all.\"\"\"\n        if not self.should_optimise:\n            return\n        from hypothesis.internal.conjecture.optimiser import Optimiser\n\n        # We want to avoid running the optimiser for too long in case we hit\n        # an unbounded target score. We start this off fairly conservatively\n        # in case interesting examples are easy to find and then ramp it up\n        # on an exponential schedule so we don't hamper the optimiser too much\n        # if it needs a long time to find good enough improvements.\n        max_improvements = 10\n        while True:\n            prev_calls = self.call_count\n\n            any_improvements = False\n\n            for target, data in list(self.best_examples_of_observed_targets.items()):\n                optimiser = Optimiser(\n                    self, data, target, max_improvements=max_improvements\n                )\n                optimiser.run()\n                if optimiser.improvements > 0:\n                    any_improvements = True\n\n            if self.interesting_examples:\n                break\n\n            max_improvements *= 2\n\n            if any_improvements:\n                continue\n\n            if self.best_observed_targets:\n                self.pareto_optimise()\n\n            if prev_calls == self.call_count:\n                break\n\n    def pareto_optimise(self) -> None:\n        if self.pareto_front is not None:\n            ParetoOptimiser(self).run()\n\n    def _run(self) -> None:\n        # have to use the primitive provider to interpret database bits...\n        self._switch_to_hypothesis_provider = True\n        with self._log_phase_statistics(\"reuse\"):\n            self.reuse_existing_examples()\n        # Fast path for development: If the database gave us interesting\n        # examples from the previously stored primary key, don't try\n        # shrinking it again as it's unlikely to work.\n        if self.reused_previously_shrunk_test_case:\n            self.exit_with(ExitReason.finished)\n        # ...but we should use the supplied provider when generating...\n        self._switch_to_hypothesis_provider = False\n        with self._log_phase_statistics(\"generate\"):\n            self.generate_new_examples()\n            # We normally run the targeting phase mixed in with the generate phase,\n            # but if we've been asked to run it but not generation then we have to\n            # run it explicitly on its own here.\n            if Phase.generate not in self.settings.phases:\n                self._current_phase = \"target\"\n                self.optimise_targets()\n        # ...and back to the primitive provider when shrinking.\n        self._switch_to_hypothesis_provider = True\n        with self._log_phase_statistics(\"shrink\"):\n            self.shrink_interesting_examples()\n        self.exit_with(ExitReason.finished)\n\n    def new_conjecture_data(\n        self,\n        prefix: Sequence[ChoiceT | ChoiceTemplate],\n        *,\n        observer: DataObserver | None = None,\n        max_choices: int | None = None,\n    ) -> ConjectureData:\n        provider = (\n            HypothesisProvider if self._switch_to_hypothesis_provider else self.provider\n        )\n        observer = observer or self.tree.new_observer()\n        if not self.using_hypothesis_backend:\n            observer = DataObserver()\n\n        return ConjectureData(\n            prefix=prefix,\n            observer=observer,\n            provider=provider,\n            max_choices=max_choices,\n            random=self.random,\n        )\n\n    def shrink_interesting_examples(self) -> None:\n        \"\"\"If we've found interesting examples, try to replace each of them\n        with a minimal interesting example with the same interesting_origin.\n\n        We may find one or more examples with a new interesting_origin\n        during the shrink process. If so we shrink these too.\n        \"\"\"\n        if Phase.shrink not in self.settings.phases or not self.interesting_examples:\n            return\n\n        self.debug(\"Shrinking interesting examples\")\n        self.finish_shrinking_deadline = time.perf_counter() + MAX_SHRINKING_SECONDS\n\n        for prev_data in sorted(\n            self.interesting_examples.values(), key=lambda d: sort_key(d.nodes)\n        ):\n            assert prev_data.status == Status.INTERESTING\n            data = self.new_conjecture_data(prev_data.choices)\n            self.test_function(data)\n            if data.status != Status.INTERESTING:\n                self.exit_with(ExitReason.flaky)\n\n        self.clear_secondary_key()\n\n        while len(self.shrunk_examples) < len(self.interesting_examples):\n            target, example = min(\n                (\n                    (k, v)\n                    for k, v in self.interesting_examples.items()\n                    if k not in self.shrunk_examples\n                ),\n                key=lambda kv: (sort_key(kv[1].nodes), shortlex(repr(kv[0]))),\n            )\n            self.debug(f\"Shrinking {target!r}: {example.choices}\")\n\n            if not self.settings.report_multiple_bugs:\n                # If multi-bug reporting is disabled, we shrink our currently-minimal\n                # failure, allowing 'slips' to any bug with a smaller minimal example.\n                self.shrink(example, lambda d: d.status == Status.INTERESTING)\n                return\n\n            def predicate(d: ConjectureResult | _Overrun) -> bool:\n                if d.status < Status.INTERESTING:\n                    return False\n                d = cast(ConjectureResult, d)\n                return d.interesting_origin == target\n\n            self.shrink(example, predicate)\n\n            self.shrunk_examples.add(target)\n\n    def clear_secondary_key(self) -> None:\n        if self.has_existing_examples():\n            # If we have any smaller examples in the secondary corpus, now is\n            # a good time to try them to see if they work as shrinks. They\n            # probably won't, but it's worth a shot and gives us a good\n            # opportunity to clear out the database.\n\n            # It's not worth trying the primary corpus because we already\n            # tried all of those in the initial phase.\n            corpus = sorted(\n                self.settings.database.fetch(self.secondary_key), key=shortlex\n            )\n            for c in corpus:\n                choices = choices_from_bytes(c)\n                if choices is None:\n                    self.settings.database.delete(self.secondary_key, c)\n                    continue\n                primary = {\n                    choices_to_bytes(v.choices)\n                    for v in self.interesting_examples.values()\n                }\n                if shortlex(c) > max(map(shortlex, primary)):\n                    break\n\n                self.cached_test_function(choices)\n                # We unconditionally remove c from the secondary key as it\n                # is either now primary or worse than our primary example\n                # of this reason for interestingness.\n                self.settings.database.delete(self.secondary_key, c)\n\n    def shrink(\n        self,\n        example: ConjectureData | ConjectureResult,\n        predicate: ShrinkPredicateT | None = None,\n        allow_transition: (\n            Callable[[ConjectureData | ConjectureResult, ConjectureData], bool] | None\n        ) = None,\n    ) -> ConjectureData | ConjectureResult:\n        s = self.new_shrinker(example, predicate, allow_transition)\n        s.shrink()\n        return s.shrink_target\n\n    def new_shrinker(\n        self,\n        example: ConjectureData | ConjectureResult,\n        predicate: ShrinkPredicateT | None = None,\n        allow_transition: (\n            Callable[[ConjectureData | ConjectureResult, ConjectureData], bool] | None\n        ) = None,\n    ) -> Shrinker:\n        return Shrinker(\n            self,\n            example,\n            predicate,\n            allow_transition=allow_transition,\n            explain=Phase.explain in self.settings.phases,\n            in_target_phase=self._current_phase == \"target\",\n        )\n\n    def passing_choice_sequences(\n        self, prefix: Sequence[ChoiceNode] = ()\n    ) -> frozenset[tuple[ChoiceNode, ...]]:\n        \"\"\"Return a collection of choice sequence nodes which cause the test to pass.\n        Optionally restrict this by a certain prefix, which is useful for explain mode.\n        \"\"\"\n        return frozenset(\n            cast(ConjectureResult, result).nodes\n            for key in self.__data_cache\n            if (result := self.__data_cache[key]).status is Status.VALID\n            and startswith(cast(ConjectureResult, result).nodes, prefix)\n        )\n\n\nclass ContainsDiscard(Exception):\n    pass\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/floats.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom array import array\n\nfrom hypothesis.internal.floats import float_to_int, int_to_float\n\n\"\"\"\nThis module implements support for arbitrary floating point numbers in\nConjecture. It doesn't make any attempt to get a good distribution, only to\nget a format that will shrink well.\n\nIt works by defining an encoding of non-negative floating point numbers\n(including NaN values with a zero sign bit) that has good lexical shrinking\nproperties.\n\nThis encoding is a tagged union of two separate encodings for floating point\nnumbers, with the tag being the first bit of 64 and the remaining 63-bits being\nthe payload.\n\nIf the tag bit is 0, the next 7 bits are ignored, and the remaining 7 bytes are\ninterpreted as a 7 byte integer in big-endian order and then converted to a\nfloat (there is some redundancy here, as 7 * 8 = 56, which is larger than the\nlargest integer that floating point numbers can represent exactly, so multiple\nencodings may map to the same float).\n\nIf the tag bit is 1, we instead use something that is closer to the normal\nrepresentation of floats (and can represent every non-negative float exactly)\nbut has a better ordering:\n\n1. NaNs are ordered after everything else.\n2. Infinity is ordered after every finite number.\n3. The sign is ignored unless two floating point numbers are identical in\n   absolute magnitude. In that case, the positive is ordered before the\n   negative.\n4. Positive floating point numbers are ordered first by int(x) where\n   encoding(x) < encoding(y) if int(x) < int(y).\n5. If int(x) == int(y) then x and y are sorted towards lower denominators of\n   their fractional parts.\n\nThe format of this encoding of floating point goes as follows:\n\n    [exponent] [mantissa]\n\nEach of these is the same size their equivalent in IEEE floating point, but are\nin a different format.\n\nWe translate exponents as follows:\n\n    1. The maximum exponent (2 ** 11 - 1) is left unchanged.\n    2. We reorder the remaining exponents so that all of the positive exponents\n       are first, in increasing order, followed by all of the negative\n       exponents in decreasing order (where positive/negative is done by the\n       unbiased exponent e - 1023).\n\nWe translate the mantissa as follows:\n\n    1. If the unbiased exponent is <= 0 we reverse it bitwise.\n    2. If the unbiased exponent is >= 52 we leave it alone.\n    3. If the unbiased exponent is in the range [1, 51] then we reverse the\n       low k bits, where k is 52 - unbiased exponent.\n\nThe low bits correspond to the fractional part of the floating point number.\nReversing it bitwise means that we try to minimize the low bits, which kills\noff the higher powers of 2 in the fraction first.\n\"\"\"\n\n\nMAX_EXPONENT = 0x7FF\n\nBIAS = 1023\nMAX_POSITIVE_EXPONENT = MAX_EXPONENT - 1 - BIAS\n\n\ndef exponent_key(e: int) -> float:\n    if e == MAX_EXPONENT:\n        return float(\"inf\")\n    unbiased = e - BIAS\n    if unbiased < 0:\n        return 10000 - unbiased\n    else:\n        return unbiased\n\n\nENCODING_TABLE = array(\"H\", sorted(range(MAX_EXPONENT + 1), key=exponent_key))\nDECODING_TABLE = array(\"H\", [0]) * len(ENCODING_TABLE)\n\nfor i, b in enumerate(ENCODING_TABLE):\n    DECODING_TABLE[b] = i\n\ndel i, b\n\n\ndef decode_exponent(e: int) -> int:\n    \"\"\"Take an integer and turn it into a suitable floating point exponent\n    such that lexicographically simpler leads to simpler floats.\"\"\"\n    assert 0 <= e <= MAX_EXPONENT\n    return ENCODING_TABLE[e]\n\n\ndef encode_exponent(e: int) -> int:\n    \"\"\"Take a floating point exponent and turn it back into the equivalent\n    result from conjecture.\"\"\"\n    assert 0 <= e <= MAX_EXPONENT\n    return DECODING_TABLE[e]\n\n\ndef reverse_byte(b: int) -> int:\n    result = 0\n    for _ in range(8):\n        result <<= 1\n        result |= b & 1\n        b >>= 1\n    return result\n\n\n# Table mapping individual bytes to the equivalent byte with the bits of the\n# byte reversed. e.g. 1=0b1 is mapped to 0xb10000000=0x80=128. We use this\n# precalculated table to simplify calculating the bitwise reversal of a longer\n# integer.\nREVERSE_BITS_TABLE = bytearray(map(reverse_byte, range(256)))\n\n\ndef reverse64(v: int) -> int:\n    \"\"\"Reverse a 64-bit integer bitwise.\n\n    We do this by breaking it up into 8 bytes. The 64-bit integer is then the\n    concatenation of each of these bytes. We reverse it by reversing each byte\n    on its own using the REVERSE_BITS_TABLE above, and then concatenating the\n    reversed bytes.\n\n    In this case concatenating consists of shifting them into the right\n    position for the word and then oring the bits together.\n    \"\"\"\n    assert v.bit_length() <= 64\n    return (\n        (REVERSE_BITS_TABLE[(v >> 0) & 0xFF] << 56)\n        | (REVERSE_BITS_TABLE[(v >> 8) & 0xFF] << 48)\n        | (REVERSE_BITS_TABLE[(v >> 16) & 0xFF] << 40)\n        | (REVERSE_BITS_TABLE[(v >> 24) & 0xFF] << 32)\n        | (REVERSE_BITS_TABLE[(v >> 32) & 0xFF] << 24)\n        | (REVERSE_BITS_TABLE[(v >> 40) & 0xFF] << 16)\n        | (REVERSE_BITS_TABLE[(v >> 48) & 0xFF] << 8)\n        | (REVERSE_BITS_TABLE[(v >> 56) & 0xFF] << 0)\n    )\n\n\nMANTISSA_MASK = (1 << 52) - 1\n\n\ndef reverse_bits(x: int, n: int) -> int:\n    assert x.bit_length() <= n <= 64\n    x = reverse64(x)\n    x >>= 64 - n\n    return x\n\n\ndef update_mantissa(unbiased_exponent: int, mantissa: int) -> int:\n    if unbiased_exponent <= 0:\n        mantissa = reverse_bits(mantissa, 52)\n    elif unbiased_exponent <= 51:\n        n_fractional_bits = 52 - unbiased_exponent\n        fractional_part = mantissa & ((1 << n_fractional_bits) - 1)\n        mantissa ^= fractional_part\n        mantissa |= reverse_bits(fractional_part, n_fractional_bits)\n    return mantissa\n\n\ndef lex_to_float(i: int) -> float:\n    assert i.bit_length() <= 64\n    has_fractional_part = i >> 63\n    if has_fractional_part:\n        exponent = (i >> 52) & ((1 << 11) - 1)\n        exponent = decode_exponent(exponent)\n        mantissa = i & MANTISSA_MASK\n        mantissa = update_mantissa(exponent - BIAS, mantissa)\n\n        assert mantissa.bit_length() <= 52\n\n        return int_to_float((exponent << 52) | mantissa)\n    else:\n        integral_part = i & ((1 << 56) - 1)\n        return float(integral_part)\n\n\ndef float_to_lex(f: float) -> int:\n    if is_simple(f):\n        assert f >= 0\n        return int(f)\n    return base_float_to_lex(f)\n\n\ndef base_float_to_lex(f: float) -> int:\n    i = float_to_int(f)\n    i &= (1 << 63) - 1\n    exponent = i >> 52\n    mantissa = i & MANTISSA_MASK\n    mantissa = update_mantissa(exponent - BIAS, mantissa)\n    exponent = encode_exponent(exponent)\n\n    assert mantissa.bit_length() <= 52\n    return (1 << 63) | (exponent << 52) | mantissa\n\n\ndef is_simple(f: float) -> int:\n    try:\n        i = int(f)\n    except (ValueError, OverflowError):\n        return False\n    if i != f:\n        return False\n    return i.bit_length() <= 56\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/junkdrawer.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"A module for miscellaneous useful bits and bobs that don't\nobviously belong anywhere else. If you spot a better home for\nanything that lives here, please move it.\"\"\"\n\nimport array\nimport gc\nimport itertools\nimport sys\nimport time\nimport warnings\nfrom array import ArrayType\nfrom collections.abc import Callable, Iterable, Iterator, Sequence\nfrom threading import Lock\nfrom typing import (\n    Any,\n    ClassVar,\n    Generic,\n    Literal,\n    TypeVar,\n    Union,\n    overload,\n)\n\nfrom sortedcontainers import SortedList\n\nfrom hypothesis.errors import HypothesisWarning\n\nT = TypeVar(\"T\")\n\n\ndef replace_all(\n    ls: Sequence[T],\n    replacements: Iterable[tuple[int, int, Sequence[T]]],\n) -> list[T]:\n    \"\"\"Substitute multiple replacement values into a list.\n\n    Replacements is a list of (start, end, value) triples.\n    \"\"\"\n\n    result: list[T] = []\n    prev = 0\n    offset = 0\n    for u, v, r in replacements:\n        result.extend(ls[prev:u])\n        result.extend(r)\n        prev = v\n        offset += len(r) - (v - u)\n    result.extend(ls[prev:])\n    assert len(result) == len(ls) + offset\n    return result\n\n\nclass IntList(Sequence[int]):\n    \"\"\"Class for storing a list of non-negative integers compactly.\n\n    We store them as the smallest size integer array we can get\n    away with. When we try to add an integer that is too large,\n    we upgrade the array to the smallest word size needed to store\n    the new value.\"\"\"\n\n    ARRAY_CODES: ClassVar[list[str]] = [\"B\", \"H\", \"I\", \"L\", \"Q\", \"O\"]\n    NEXT_ARRAY_CODE: ClassVar[dict[str, str]] = dict(itertools.pairwise(ARRAY_CODES))\n\n    __slots__ = (\"__underlying\",)\n\n    def __init__(self, values: Sequence[int] = ()):\n        for code in self.ARRAY_CODES:\n            try:\n                underlying = self._array_or_list(code, values)\n                break\n            except OverflowError:\n                pass\n        else:  # pragma: no cover\n            raise AssertionError(f\"Could not create storage for {values!r}\")\n        if isinstance(underlying, list):\n            for v in underlying:\n                if not isinstance(v, int) or v < 0:\n                    raise ValueError(f\"Could not create IntList for {values!r}\")\n        self.__underlying: list[int] | ArrayType[int] = underlying\n\n    @classmethod\n    def of_length(cls, n: int) -> \"IntList\":\n        return cls(array.array(\"B\", [0]) * n)\n\n    @staticmethod\n    def _array_or_list(\n        code: str, contents: Iterable[int]\n    ) -> Union[list[int], \"ArrayType[int]\"]:\n        if code == \"O\":\n            return list(contents)\n        return array.array(code, contents)\n\n    def count(self, value: int) -> int:\n        return self.__underlying.count(value)\n\n    def __repr__(self) -> str:\n        return f\"IntList({list(self.__underlying)!r})\"\n\n    def __len__(self) -> int:\n        return len(self.__underlying)\n\n    @overload\n    def __getitem__(self, i: int) -> int: ...  # pragma: no cover\n\n    @overload\n    def __getitem__(\n        self, i: slice\n    ) -> \"list[int] | ArrayType[int]\": ...  # pragma: no cover\n\n    def __getitem__(self, i: int | slice) -> \"int | list[int] | ArrayType[int]\":\n        return self.__underlying[i]\n\n    def __delitem__(self, i: int | slice) -> None:\n        del self.__underlying[i]\n\n    def insert(self, i: int, v: int) -> None:\n        self.__underlying.insert(i, v)\n\n    def __iter__(self) -> Iterator[int]:\n        return iter(self.__underlying)\n\n    def __eq__(self, other: object) -> bool:\n        if self is other:\n            return True\n        if not isinstance(other, IntList):\n            return NotImplemented\n        return self.__underlying == other.__underlying\n\n    def __ne__(self, other: object) -> bool:\n        if self is other:\n            return False\n        if not isinstance(other, IntList):\n            return NotImplemented\n        return self.__underlying != other.__underlying\n\n    def append(self, n: int) -> None:\n        # try the fast path of appending n first. If this overflows, use the\n        # __setitem__ path, which will upgrade the underlying array.\n        try:\n            self.__underlying.append(n)\n        except OverflowError:\n            i = len(self.__underlying)\n            self.__underlying.append(0)\n            self[i] = n\n\n    def __setitem__(self, i: int, n: int) -> None:\n        while True:\n            try:\n                self.__underlying[i] = n\n                return\n            except OverflowError:\n                assert n > 0\n                self.__upgrade()\n\n    def extend(self, ls: Iterable[int]) -> None:\n        for n in ls:\n            self.append(n)\n\n    def __upgrade(self) -> None:\n        assert isinstance(self.__underlying, array.array)\n        code = self.NEXT_ARRAY_CODE[self.__underlying.typecode]\n        self.__underlying = self._array_or_list(code, self.__underlying)\n\n\ndef binary_search(lo: int, hi: int, f: Callable[[int], bool]) -> int:\n    \"\"\"Binary searches in [lo , hi) to find\n    n such that f(n) == f(lo) but f(n + 1) != f(lo).\n    It is implicitly assumed and will not be checked\n    that f(hi) != f(lo).\n    \"\"\"\n\n    reference = f(lo)\n\n    while lo + 1 < hi:\n        mid = (lo + hi) // 2\n        if f(mid) == reference:\n            lo = mid\n        else:\n            hi = mid\n    return lo\n\n\nclass LazySequenceCopy(Generic[T]):\n    \"\"\"A \"copy\" of a sequence that works by inserting a mask in front\n    of the underlying sequence, so that you can mutate it without changing\n    the underlying sequence. Effectively behaves as if you could do list(x)\n    in O(1) time. The full list API is not supported yet but there's no reason\n    in principle it couldn't be.\"\"\"\n\n    def __init__(self, values: Sequence[T]):\n        self.__values = values\n        self.__len = len(values)\n        self.__mask: dict[int, T] | None = None\n        self.__popped_indices: SortedList[int] | None = None\n\n    def __len__(self) -> int:\n        if self.__popped_indices is None:\n            return self.__len\n        return self.__len - len(self.__popped_indices)\n\n    def pop(self, i: int = -1) -> T:\n        if len(self) == 0:\n            raise IndexError(\"Cannot pop from empty list\")\n        i = self.__underlying_index(i)\n\n        v = None\n        if self.__mask is not None:\n            v = self.__mask.pop(i, None)\n        if v is None:\n            v = self.__values[i]\n\n        if self.__popped_indices is None:\n            self.__popped_indices = SortedList()\n        self.__popped_indices.add(i)\n        return v\n\n    def swap(self, i: int, j: int) -> None:\n        \"\"\"Swap the elements ls[i], ls[j].\"\"\"\n        if i == j:\n            return\n        self[i], self[j] = self[j], self[i]\n\n    def __getitem__(self, i: int) -> T:\n        i = self.__underlying_index(i)\n\n        default = self.__values[i]\n        if self.__mask is None:\n            return default\n        else:\n            return self.__mask.get(i, default)\n\n    def __setitem__(self, i: int, v: T) -> None:\n        i = self.__underlying_index(i)\n        if self.__mask is None:\n            self.__mask = {}\n        self.__mask[i] = v\n\n    def __underlying_index(self, i: int) -> int:\n        n = len(self)\n        if i < -n or i >= n:\n            raise IndexError(f\"Index {i} out of range [0, {n})\")\n        if i < 0:\n            i += n\n        assert 0 <= i < n\n\n        if self.__popped_indices is not None:\n            # given an index i in the popped representation of the list, compute\n            # its corresponding index in the underlying list. given\n            #   l = [1, 4, 2, 10, 188]\n            #   l.pop(3)\n            #   l.pop(1)\n            #   assert l == [1, 2, 188]\n            #\n            # we want l[i] == self.__values[f(i)], where f is this function.\n            assert len(self.__popped_indices) <= len(self.__values)\n\n            for idx in self.__popped_indices:\n                if idx > i:\n                    break\n                i += 1\n        return i\n\n    # even though we have len + getitem, mypyc requires iter.\n    def __iter__(self) -> Iterable[T]:\n        for i in range(len(self)):\n            yield self[i]\n\n\ndef stack_depth_of_caller() -> int:\n    \"\"\"Get stack size for caller's frame.\n\n    From https://stackoverflow.com/a/47956089/9297601 , this is a simple\n    but much faster alternative to `len(inspect.stack(0))`.  We use it\n    with get/set recursionlimit to make stack overflows non-flaky; see\n    https://github.com/HypothesisWorks/hypothesis/issues/2494 for details.\n    \"\"\"\n    frame = sys._getframe(2)\n    size = 1\n    while frame:\n        frame = frame.f_back  # type: ignore[assignment]\n        size += 1\n    return size\n\n\nclass StackframeLimiter:\n    # StackframeLimiter is used to make the recursion limit warning issued via\n    # ensure_free_stackframes thread-safe. We track the known values we have\n    # passed to sys.setrecursionlimit in _known_limits, and only issue a warning\n    # if sys.getrecursionlimit is not in _known_limits.\n    #\n    # This will always be an under-approximation of when we would ideally issue\n    # this warning, since a non-hypothesis caller could coincidentaly set the\n    # recursion limit to one of our known limits. Currently, StackframeLimiter\n    # resets _known_limits whenever all of the ensure_free_stackframes contexts\n    # have exited. We could increase the power of the warning by tracking a\n    # refcount for each limit, and removing it as soon as the refcount hits zero.\n    # I didn't think this extra complexity is worth the minor power increase for\n    # what is already only a \"nice to have\" warning.\n\n    def __init__(self):\n        self._active_contexts = 0\n        self._known_limits: set[int] = set()\n        self._original_limit: int | None = None\n\n    def _setrecursionlimit(self, new_limit: int, *, check: bool = True) -> None:\n        if (\n            check\n            and (current_limit := sys.getrecursionlimit()) not in self._known_limits\n        ):\n            warnings.warn(\n                \"The recursion limit will not be reset, since it was changed \"\n                f\"during test execution (from {self._original_limit} to {current_limit}).\",\n                HypothesisWarning,\n                stacklevel=4,\n            )\n            return\n\n        self._known_limits.add(new_limit)\n        sys.setrecursionlimit(new_limit)\n\n    def enter_context(self, new_limit: int, *, current_limit: int) -> None:\n        if self._active_contexts == 0:\n            # this is the first context on the stack. Record the true original\n            # limit, to restore later.\n            assert self._original_limit is None\n            self._original_limit = current_limit\n            self._known_limits.add(self._original_limit)\n\n        self._active_contexts += 1\n        self._setrecursionlimit(new_limit)\n\n    def exit_context(self, new_limit: int, *, check: bool = True) -> None:\n        assert self._active_contexts > 0\n        self._active_contexts -= 1\n\n        if self._active_contexts == 0:\n            # this is the last context to exit. Restore the true original\n            # limit and clear our known limits.\n            original_limit = self._original_limit\n            assert original_limit is not None\n            try:\n                self._setrecursionlimit(original_limit, check=check)\n            finally:\n                self._original_limit = None\n                # we want to clear the known limits, but preserve the limit\n                # we just set it to as known.\n                self._known_limits = {original_limit}\n        else:\n            self._setrecursionlimit(new_limit, check=check)\n\n\n_stackframe_limiter = StackframeLimiter()\n_stackframe_limiter_lock = Lock()\n\n\nclass ensure_free_stackframes:\n    \"\"\"Context manager that ensures there are at least N free stackframes (for\n    a reasonable value of N).\n    \"\"\"\n\n    def __enter__(self) -> None:\n        cur_depth = stack_depth_of_caller()\n        with _stackframe_limiter_lock:\n            self.old_limit = sys.getrecursionlimit()\n            # The default CPython recursionlimit is 1000, but pytest seems to bump\n            # it to 3000 during test execution. Let's make it something reasonable:\n            self.new_limit = cur_depth + 2000\n            # Because we add to the recursion limit, to be good citizens we also\n            # add a check for unbounded recursion.  The default limit is typically\n            # 1000/3000, so this can only ever trigger if something really strange\n            # is happening and it's hard to imagine an\n            # intentionally-deeply-recursive use of this code.\n            assert cur_depth <= 1000, (\n                \"Hypothesis would usually add %d to the stack depth of %d here, \"\n                \"but we are already much deeper than expected.  Aborting now, to \"\n                \"avoid extending the stack limit in an infinite loop...\"\n                % (self.new_limit - self.old_limit, self.old_limit)\n            )\n            try:\n                _stackframe_limiter.enter_context(\n                    self.new_limit, current_limit=self.old_limit\n                )\n            except Exception:\n                # if the stackframe limiter raises a HypothesisWarning (under eg\n                # -Werror), __exit__ is not called, since we errored in __enter__.\n                # Preserve the state of the stackframe limiter by exiting, and\n                # avoid showing a duplicate warning with check=False.\n                _stackframe_limiter.exit_context(self.old_limit, check=False)\n                raise\n\n    def __exit__(self, *args, **kwargs):\n        with _stackframe_limiter_lock:\n            _stackframe_limiter.exit_context(self.old_limit)\n\n\ndef find_integer(f: Callable[[int], bool]) -> int:\n    \"\"\"Finds a (hopefully large) integer such that f(n) is True and f(n + 1) is\n    False.\n\n    f(0) is assumed to be True and will not be checked.\n    \"\"\"\n    # We first do a linear scan over the small numbers and only start to do\n    # anything intelligent if f(4) is true. This is because it's very hard to\n    # win big when the result is small. If the result is 0 and we try 2 first\n    # then we've done twice as much work as we needed to!\n    for i in range(1, 5):\n        if not f(i):\n            return i - 1\n\n    # We now know that f(4) is true. We want to find some number for which\n    # f(n) is *not* true.\n    # lo is the largest number for which we know that f(lo) is true.\n    lo = 4\n\n    # Exponential probe upwards until we find some value hi such that f(hi)\n    # is not true. Subsequently we maintain the invariant that hi is the\n    # smallest number for which we know that f(hi) is not true.\n    hi = 5\n    while f(hi):\n        lo = hi\n        hi *= 2\n\n    # Now binary search until lo + 1 = hi. At that point we have f(lo) and not\n    # f(lo + 1), as desired..\n    while lo + 1 < hi:\n        mid = (lo + hi) // 2\n        if f(mid):\n            lo = mid\n        else:\n            hi = mid\n    return lo\n\n\n_gc_initialized = False\n_gc_start: float = 0\n_gc_cumulative_time: float = 0\n\n# Since gc_callback potentially runs in test context, and perf_counter\n# might be monkeypatched, we store a reference to the real one.\n_perf_counter = time.perf_counter\n\n\ndef gc_cumulative_time() -> float:\n    global _gc_initialized\n\n    # I don't believe we need a lock for the _gc_cumulative_time increment here,\n    # since afaik each gc callback is only executed once when the garbage collector\n    # runs, by the thread which initiated the gc.\n\n    if not _gc_initialized:\n        if hasattr(gc, \"callbacks\"):\n            # CPython\n            def gc_callback(\n                phase: Literal[\"start\", \"stop\"], info: dict[str, int]\n            ) -> None:\n                global _gc_start, _gc_cumulative_time\n                try:\n                    now = _perf_counter()\n                    if phase == \"start\":\n                        _gc_start = now\n                    elif phase == \"stop\" and _gc_start > 0:\n                        _gc_cumulative_time += now - _gc_start  # pragma: no cover # ??\n                except RecursionError:  # pragma: no cover\n                    # Avoid flakiness via UnraisableException, which is caught and\n                    # warned by pytest. The actual callback (this function) is\n                    # validated to never trigger a RecursionError itself when\n                    # when called by gc.collect.\n                    # Anyway, we should hit the same error on \"start\"\n                    # and \"stop\", but to ensure we don't get out of sync we just\n                    # signal that there is no matching start.\n                    _gc_start = 0\n                    return\n\n            gc.callbacks.insert(0, gc_callback)\n        elif hasattr(gc, \"hooks\"):  # pragma: no cover  # pypy only\n            # PyPy\n            def hook(stats: Any) -> None:\n                global _gc_cumulative_time\n                try:\n                    _gc_cumulative_time += stats.duration\n                except RecursionError:\n                    pass\n\n            if gc.hooks.on_gc_minor is None:\n                gc.hooks.on_gc_minor = hook\n            if gc.hooks.on_gc_collect_step is None:\n                gc.hooks.on_gc_collect_step = hook\n\n        _gc_initialized = True\n\n    return _gc_cumulative_time\n\n\ndef startswith(l1: Sequence[T], l2: Sequence[T]) -> bool:\n    if len(l1) < len(l2):\n        return False\n    return all(v1 == v2 for v1, v2 in zip(l1[: len(l2)], l2, strict=False))\n\n\ndef endswith(l1: Sequence[T], l2: Sequence[T]) -> bool:\n    if len(l1) < len(l2):\n        return False\n    return all(v1 == v2 for v1, v2 in zip(l1[-len(l2) :], l2, strict=False))\n\n\ndef bits_to_bytes(n: int) -> int:\n    \"\"\"The number of bytes required to represent an n-bit number.\n    Equivalent to (n + 7) // 8, but slightly faster. This really is\n    called enough times that that matters.\"\"\"\n    return (n + 7) >> 3\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/optimiser.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.internal.compat import int_from_bytes, int_to_bytes\nfrom hypothesis.internal.conjecture.choice import ChoiceT, choice_permitted\nfrom hypothesis.internal.conjecture.data import ConjectureResult, Status, _Overrun\nfrom hypothesis.internal.conjecture.engine import ConjectureRunner\nfrom hypothesis.internal.conjecture.junkdrawer import bits_to_bytes, find_integer\nfrom hypothesis.internal.conjecture.pareto import NO_SCORE\n\n\nclass Optimiser:\n    \"\"\"A fairly basic optimiser designed to increase the value of scores for\n    targeted property-based testing.\n\n    This implements a fairly naive hill climbing algorithm based on randomly\n    regenerating parts of the test case to attempt to improve the result. It is\n    not expected to produce amazing results, because it is designed to be run\n    in a fairly small testing budget, so it prioritises finding easy wins and\n    bailing out quickly if that doesn't work.\n\n    For more information about targeted property-based testing, see\n    Löscher, Andreas, and Konstantinos Sagonas. \"Targeted property-based\n    testing.\" Proceedings of the 26th ACM SIGSOFT International Symposium on\n    Software Testing and Analysis. ACM, 2017.\n    \"\"\"\n\n    def __init__(\n        self,\n        engine: ConjectureRunner,\n        data: ConjectureResult,\n        target: str,\n        max_improvements: int = 100,\n    ) -> None:\n        \"\"\"Optimise ``target`` starting from ``data``. Will stop either when\n        we seem to have found a local maximum or when the target score has\n        been improved ``max_improvements`` times. This limit is in place to\n        deal with the fact that the target score may not be bounded above.\"\"\"\n        self.engine = engine\n        self.current_data = data\n        self.target = target\n        self.max_improvements = max_improvements\n        self.improvements = 0\n\n    def run(self) -> None:\n        self.hill_climb()\n\n    def score_function(self, data: ConjectureResult) -> float:\n        return data.target_observations.get(self.target, NO_SCORE)\n\n    @property\n    def current_score(self) -> float:\n        return self.score_function(self.current_data)\n\n    def consider_new_data(self, data: ConjectureResult | _Overrun) -> bool:\n        \"\"\"Consider a new data object as a candidate target. If it is better\n        than the current one, return True.\"\"\"\n        if data.status < Status.VALID:\n            return False\n        assert isinstance(data, ConjectureResult)\n        score = self.score_function(data)\n        if score < self.current_score:\n            return False\n        if score > self.current_score:\n            self.improvements += 1\n            self.current_data = data\n            return True\n        assert score == self.current_score\n        # We allow transitions that leave the score unchanged as long as they\n        # don't increase the number of nodes. This gives us a certain amount of\n        # freedom for lateral moves that will take us out of local maxima.\n        if len(data.nodes) <= len(self.current_data.nodes):\n            self.current_data = data\n            return True\n        return False\n\n    def hill_climb(self) -> None:\n        \"\"\"The main hill climbing loop where we actually do the work: Take\n        data, and attempt to improve its score for target. select_example takes\n        a data object and returns an index to an example where we should focus\n        our efforts.\"\"\"\n\n        nodes_examined = set()\n\n        prev: ConjectureResult | None = None\n        i = len(self.current_data.nodes) - 1\n        while i >= 0 and self.improvements <= self.max_improvements:\n            if prev is not self.current_data:\n                i = len(self.current_data.nodes) - 1\n                prev = self.current_data\n\n            if i in nodes_examined:\n                i -= 1\n                continue\n\n            nodes_examined.add(i)\n            node = self.current_data.nodes[i]\n            assert node.index is not None\n            # we can only (sensibly & easily) define hill climbing for\n            # numeric-style nodes. It's not clear hill-climbing a string is\n            # useful, for instance.\n            if node.type not in {\"integer\", \"float\", \"bytes\", \"boolean\"}:\n                continue\n\n            def attempt_replace(k: int) -> bool:\n                \"\"\"\n                Try replacing the current node in the current best test case\n                with a value which is \"k times larger\", where the exact notion\n                of \"larger\" depends on the choice_type.\n\n                Note that we use the *current* best and not the one we started with.\n                This helps ensure that if we luck into a good draw when making\n                random choices we get to keep the good bits.\n                \"\"\"\n                # we don't want to infinitely drive up an unbounded score.\n                if abs(k) > 2**20:\n                    return False\n\n                node = self.current_data.nodes[i]\n                assert node.index is not None\n                if node.was_forced:\n                    return False  # pragma: no cover\n\n                new_choice: ChoiceT\n                if node.type in {\"integer\", \"float\"}:\n                    assert isinstance(node.value, (int, float))\n                    new_choice = node.value + k\n                elif node.type == \"boolean\":\n                    assert isinstance(node.value, bool)\n                    if abs(k) > 1:\n                        return False\n                    if k == -1:\n                        new_choice = False\n                    if k == 1:\n                        new_choice = True\n                    if k == 0:  # pragma: no cover\n                        new_choice = node.value\n                else:\n                    assert node.type == \"bytes\"\n                    assert isinstance(node.value, bytes)\n                    v = int_from_bytes(node.value)\n                    # can't go below zero for bytes\n                    if v + k < 0:\n                        return False\n                    v += k\n                    # allow adding k to increase the number of bytes. we don't want\n                    # to decrease so that b\"01\" doesn't turn into b\"1\".\n                    size = max(len(node.value), bits_to_bytes(v.bit_length()))\n                    new_choice = int_to_bytes(v, size)\n\n                if not choice_permitted(new_choice, node.constraints):\n                    return False\n\n                for _ in range(3):\n                    choices = self.current_data.choices\n                    attempt_choices = (\n                        choices[: node.index]\n                        + (new_choice,)\n                        + choices[node.index + 1 :]\n                    )\n                    attempt = self.engine.cached_test_function(\n                        attempt_choices, extend=\"full\"\n                    )\n\n                    if self.consider_new_data(attempt):\n                        return True\n\n                    if attempt.status is Status.OVERRUN:\n                        return False\n\n                    assert isinstance(attempt, ConjectureResult)\n                    if len(attempt.nodes) == len(self.current_data.nodes):\n                        return False\n\n                    for j, ex in enumerate(self.current_data.spans):\n                        if ex.start >= node.index + 1:\n                            break  # pragma: no cover\n                        if ex.end <= node.index:\n                            continue\n                        ex_attempt = attempt.spans[j]\n                        if ex.choice_count == ex_attempt.choice_count:\n                            continue  # pragma: no cover\n                        replacement = attempt.choices[ex_attempt.start : ex_attempt.end]\n                        if self.consider_new_data(\n                            self.engine.cached_test_function(\n                                choices[: node.index]\n                                + replacement\n                                + self.current_data.choices[ex.end :]\n                            )\n                        ):\n                            return True\n                return False\n\n            # we don't know whether a target score increases or decreases with\n            # respect to the value of some node, so try both directions.\n            find_integer(lambda k: attempt_replace(k))\n            find_integer(lambda k: attempt_replace(-k))\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/pareto.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections.abc import Callable, Iterator\nfrom enum import Enum\nfrom random import Random\nfrom typing import TYPE_CHECKING\n\nfrom sortedcontainers import SortedList\n\nfrom hypothesis.internal.conjecture.choice import choices_key\nfrom hypothesis.internal.conjecture.data import (\n    ConjectureData,\n    ConjectureResult,\n    Status,\n    _Overrun,\n)\nfrom hypothesis.internal.conjecture.junkdrawer import LazySequenceCopy\nfrom hypothesis.internal.conjecture.shrinker import sort_key\n\nNO_SCORE = float(\"-inf\")\n\nif TYPE_CHECKING:\n    from hypothesis.internal.conjecture.engine import ConjectureRunner\n\n\nclass DominanceRelation(Enum):\n    NO_DOMINANCE = 0\n    EQUAL = 1\n    LEFT_DOMINATES = 2\n    RIGHT_DOMINATES = 3\n\n\ndef dominance(left: ConjectureResult, right: ConjectureResult) -> DominanceRelation:\n    \"\"\"Returns the dominance relation between ``left`` and ``right``, according\n    to the rules that one ConjectureResult dominates another if and only if it\n    is better in every way.\n\n    The things we currently consider to be \"better\" are:\n\n        * Something that is smaller in shrinking order is better.\n        * Something that has higher status is better.\n        * Each ``interesting_origin`` is treated as its own score, so if two\n          interesting examples have different origins then neither dominates\n          the other.\n        * For each target observation, a higher score is better.\n\n    In \"normal\" operation where there are no bugs or target observations, the\n    pareto front only has one element (the smallest valid test case), but for\n    more structured or failing tests it can be useful to track, and future work\n    will depend on it more.\"\"\"\n\n    left_key = sort_key(left.nodes)\n    right_key = sort_key(right.nodes)\n    if left_key == right_key:\n        return DominanceRelation.EQUAL\n\n    if right_key < left_key:\n        result = dominance(left=right, right=left)\n        if result == DominanceRelation.LEFT_DOMINATES:\n            return DominanceRelation.RIGHT_DOMINATES\n        else:\n            # Because we have sort_key(left) < sort_key(right) the only options\n            # are that right is better than left or that the two are\n            # incomparable.\n            assert result == DominanceRelation.NO_DOMINANCE\n            return result\n\n    # Either left is better or there is no dominance relationship.\n    assert left_key < right_key\n\n    # The right is more interesting\n    if left.status < right.status:\n        return DominanceRelation.NO_DOMINANCE\n\n    if not right.tags.issubset(left.tags):\n        return DominanceRelation.NO_DOMINANCE\n\n    # Things that are interesting for different reasons are incomparable in\n    # the dominance relationship.\n    if (\n        left.status == Status.INTERESTING\n        and right.interesting_origin is not None\n        and left.interesting_origin != right.interesting_origin\n    ):\n        return DominanceRelation.NO_DOMINANCE\n\n    for target in set(left.target_observations) | set(right.target_observations):\n        left_score = left.target_observations.get(target, NO_SCORE)\n        right_score = right.target_observations.get(target, NO_SCORE)\n        if right_score > left_score:\n            return DominanceRelation.NO_DOMINANCE\n\n    return DominanceRelation.LEFT_DOMINATES\n\n\nclass ParetoFront:\n    \"\"\"Maintains an approximate pareto front of ConjectureData objects. That\n    is, we try to maintain a collection of objects such that no element of the\n    collection is pareto dominated by any other. In practice we don't quite\n    manage that, because doing so is computationally very expensive. Instead\n    we maintain a random sample of data objects that are \"rarely\" dominated by\n    any other element of the collection (roughly, no more than about 10%).\n\n    Only valid test cases are considered to belong to the pareto front - any\n    test case with a status less than valid is discarded.\n\n    Note that the pareto front is potentially quite large, and currently this\n    will store the entire front in memory. This is bounded by the number of\n    valid examples we run, which is max_examples in normal execution, and\n    currently we do not support workflows with large max_examples which have\n    large values of max_examples very well anyway, so this isn't a major issue.\n    In future we may weish to implement some sort of paging out to disk so that\n    we can work with larger fronts.\n\n    Additionally, because this is only an approximate pareto front, there are\n    scenarios where it can be much larger than the actual pareto front. There\n    isn't a huge amount we can do about this - checking an exact pareto front\n    is intrinsically quadratic.\n\n    \"Most\" of the time we should be relatively close to the true pareto front,\n    say within an order of magnitude, but it's not hard to construct scenarios\n    where this is not the case. e.g. suppose we enumerate all valid test cases\n    in increasing shortlex order as s_1, ..., s_n, ... and have scores f and\n    g such that f(s_i) = min(i, N) and g(s_i) = 1 if i >= N, then the pareto\n    front is the set {s_1, ..., S_N}, but the only element of the front that\n    will dominate s_i when i > N is S_N, which we select with probability\n    1 / N. A better data structure could solve this, but at the cost of more\n    expensive operations and higher per element memory use, so we'll wait to\n    see how much of a problem this is in practice before we try that.\n    \"\"\"\n\n    def __init__(self, random: Random) -> None:\n        self.__random = random\n        self.__eviction_listeners: list[Callable[[ConjectureResult], None]] = []\n\n        self.front: SortedList[ConjectureResult] = SortedList(\n            key=lambda d: sort_key(d.nodes)\n        )\n        self.__pending: ConjectureResult | None = None\n\n    def add(self, data: ConjectureData | ConjectureResult | _Overrun) -> bool:\n        \"\"\"Attempts to add ``data`` to the pareto front. Returns True if\n        ``data`` is now in the front, including if data is already in the\n        collection, and False otherwise\"\"\"\n        if data.status < Status.VALID:\n            return False\n\n        assert not isinstance(data, _Overrun)\n        data = data.as_result()\n        assert not isinstance(data, _Overrun)\n\n        if not self.front:\n            self.front.add(data)\n            return True\n\n        if data in self.front:\n            return True\n\n        # We add data to the pareto front by adding it unconditionally and then\n        # doing a certain amount of randomized \"clear down\" - testing a random\n        # set of elements (currently 10) to see if they are dominated by\n        # something else in the collection. If they are, we remove them.\n        self.front.add(data)\n        assert self.__pending is None\n        try:\n            self.__pending = data\n\n            # We maintain a set of the current exact pareto front of the\n            # values we've sampled so far. When we sample a new element we\n            # either add it to this exact pareto front or remove it from the\n            # collection entirely.\n            front = LazySequenceCopy(self.front)\n\n            # We track which values we are going to remove and remove them all\n            # at the end so the shape of the front doesn't change while we're\n            # using it.\n            to_remove: list[ConjectureResult] = []\n\n            # We now iteratively sample elements from the approximate pareto\n            # front to check whether they should be retained. When the set of\n            # dominators gets too large we have sampled at least 10 elements\n            # and it gets too expensive to continue, so we consider that enough\n            # due diligence.\n            i = self.front.index(data)\n\n            # First we attempt to look for values that must be removed by the\n            # addition of the data. These are necessarily to the right of it\n            # in the list.\n\n            failures = 0\n            while i + 1 < len(front) and failures < 10:\n                j = self.__random.randrange(i + 1, len(front))\n                candidate = front.pop(j)\n                dom = dominance(data, candidate)\n                assert dom != DominanceRelation.RIGHT_DOMINATES\n                if dom == DominanceRelation.LEFT_DOMINATES:\n                    to_remove.append(candidate)\n                    failures = 0\n                else:\n                    failures += 1\n\n            # Now we look at the points up to where we put data in to see if\n            # it is dominated. While we're here we spend some time looking for\n            # anything else that might be dominated too, compacting down parts\n            # of the list.\n\n            dominators = [data]\n\n            while i >= 0 and len(dominators) < 10:\n                front.swap(i, self.__random.randint(0, i))\n\n                candidate = front[i]\n\n                already_replaced = False\n                j = 0\n                while j < len(dominators):\n                    v = dominators[j]\n\n                    dom = dominance(candidate, v)\n                    if dom == DominanceRelation.LEFT_DOMINATES:\n                        if not already_replaced:\n                            already_replaced = True\n                            dominators[j] = candidate\n                            j += 1\n                        else:  # pragma: no cover # flaky, by test_database_contains_only_pareto_front\n                            dominators[j], dominators[-1] = (\n                                dominators[-1],\n                                dominators[j],\n                            )\n                            dominators.pop()\n                        to_remove.append(v)\n                    elif dom == DominanceRelation.RIGHT_DOMINATES:\n                        to_remove.append(candidate)\n                        break\n                    elif dom == DominanceRelation.EQUAL:\n                        break\n                    else:\n                        j += 1\n                else:\n                    dominators.append(candidate)\n                i -= 1\n\n            for v in to_remove:\n                self._remove(v)\n            return data in self.front\n        finally:\n            self.__pending = None\n\n    def on_evict(self, f: Callable[[ConjectureResult], None]) -> None:\n        \"\"\"Register a listener function that will be called with data when it\n        gets removed from the front because something else dominates it.\"\"\"\n        self.__eviction_listeners.append(f)\n\n    def __contains__(self, data: object) -> bool:\n        if not isinstance(data, (ConjectureData, ConjectureResult)):\n            return False\n\n        result = data.as_result()\n        if isinstance(result, _Overrun):\n            return False\n\n        return result in self.front\n\n    def __iter__(self) -> Iterator[ConjectureResult]:\n        return iter(self.front)\n\n    def __getitem__(self, i: int) -> ConjectureResult:\n        return self.front[i]\n\n    def __len__(self) -> int:\n        return len(self.front)\n\n    def _remove(self, data: ConjectureResult) -> None:\n        try:\n            self.front.remove(data)\n        except ValueError:\n            return\n        if data is not self.__pending:\n            for f in self.__eviction_listeners:\n                f(data)\n\n\nclass ParetoOptimiser:\n    \"\"\"Class for managing optimisation of the pareto front. That is, given the\n    current best known pareto front, this class runs an optimisation process\n    that attempts to bring it closer to the actual pareto front.\n\n    Currently this is fairly basic and only handles pareto optimisation that\n    works by reducing the test case in the shortlex order. We expect it will\n    grow more powerful over time.\n    \"\"\"\n\n    def __init__(self, engine: \"ConjectureRunner\") -> None:\n        self.__engine = engine\n        assert self.__engine.pareto_front is not None\n        self.front: ParetoFront = self.__engine.pareto_front\n\n    def run(self) -> None:\n        seen = set()\n\n        # We iterate backwards through the pareto front, using the shrinker to\n        # (hopefully) replace each example with a smaller one. Note that it's\n        # important that we start from the end for two reasons: Firstly, by\n        # doing it this way we ensure that any new front members we discover\n        # during optimisation will also get optimised (because they will be\n        # inserted into the part of the front that we haven't visited yet),\n        # and secondly we generally expect that we will not finish this process\n        # in a single run, because it's relatively expensive in terms of our\n        # example budget, and by starting from the end we ensure that each time\n        # we run the tests we improve the pareto front because we work on the\n        # bits that we haven't covered yet.\n        i = len(self.front) - 1\n        prev = None\n        while i >= 0 and not self.__engine.interesting_examples:\n            assert self.front\n            i = min(i, len(self.front) - 1)\n            target = self.front[i]\n            if choices_key(target.choices) in seen:\n                i -= 1\n                continue\n            assert target is not prev\n            prev = target\n\n            def allow_transition(source, destination):\n                \"\"\"Shrink to data that strictly pareto dominates the current\n                best value we've seen, which is the current target of the\n                shrinker.\n\n                Note that during shrinking we may discover other smaller\n                examples that this function will reject and will get added to\n                the front. This is fine, because they will be processed on\n                later iterations of this loop.\"\"\"\n                if dominance(destination, source) == DominanceRelation.LEFT_DOMINATES:\n                    # If ``destination`` dominates ``source`` then ``source``\n                    # must be dominated in the front - either ``destination`` is in\n                    # the front, or it was not added to it because it was\n                    # dominated by something in it.\n                    self.front._remove(source)\n                    return True\n                return False\n\n            shrunk = self.__engine.shrink(target, allow_transition=allow_transition)\n            seen.add(choices_key(shrunk.choices))\n\n            # Note that the front may have changed shape arbitrarily when\n            # we ran the shrinker. If it didn't change shape then this is\n            # i - 1. If it did change shape then this is the largest value\n            # in the front which is smaller than the previous target, so\n            # is the correct place to resume from. In particular note that the\n            # size of the front might have grown because of slippage during the\n            # shrink, but all of the newly introduced elements will be smaller\n            # than `target`, so will be covered by this iteration.\n            i = self.front.front.bisect_left(target)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/provider_conformance.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nimport sys\nfrom collections.abc import Collection, Iterable, Sequence\nfrom typing import Any\n\nfrom hypothesis import (\n    HealthCheck,\n    assume,\n    note,\n    settings as Settings,\n    strategies as st,\n)\nfrom hypothesis.errors import BackendCannotProceed\nfrom hypothesis.internal.compat import batched\nfrom hypothesis.internal.conjecture.choice import (\n    ChoiceTypeT,\n    choice_permitted,\n)\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.conjecture.providers import (\n    COLLECTION_DEFAULT_MAX_SIZE,\n    HypothesisProvider,\n    PrimitiveProvider,\n    with_register_backend,\n)\nfrom hypothesis.internal.floats import SMALLEST_SUBNORMAL, sign_aware_lte\nfrom hypothesis.internal.intervalsets import IntervalSet\nfrom hypothesis.stateful import RuleBasedStateMachine, initialize, precondition, rule\nfrom hypothesis.strategies import DrawFn, SearchStrategy\nfrom hypothesis.strategies._internal.strings import OneCharStringStrategy, TextStrategy\n\n\ndef build_intervals(intervals: list[int]) -> list[tuple[int, int]]:\n    if len(intervals) % 2:\n        intervals = intervals[:-1]\n    intervals.sort()\n    # help mypy infer tuple[int, ...] -> tuple[int, int]\n    return list(batched(intervals, 2, strict=True))  # type: ignore\n\n\ndef interval_lists(\n    *, min_codepoint: int = 0, max_codepoint: int = sys.maxunicode, min_size: int = 0\n) -> SearchStrategy[Iterable[Sequence[int]]]:\n    return (\n        st.lists(\n            st.integers(min_codepoint, max_codepoint),\n            unique=True,\n            min_size=min_size * 2,\n        )\n        .map(sorted)\n        .map(build_intervals)\n    )\n\n\ndef intervals(\n    *, min_codepoint: int = 0, max_codepoint: int = sys.maxunicode, min_size: int = 0\n) -> SearchStrategy[IntervalSet]:\n    return st.builds(\n        IntervalSet,\n        interval_lists(\n            min_codepoint=min_codepoint, max_codepoint=max_codepoint, min_size=min_size\n        ),\n    )\n\n\n@st.composite\ndef integer_weights(\n    draw: DrawFn, min_value: int | None = None, max_value: int | None = None\n) -> dict[int, float]:\n    # Sampler doesn't play well with super small floats, so exclude them\n    weights = draw(\n        st.dictionaries(\n            st.integers(min_value=min_value, max_value=max_value),\n            st.floats(0.001, 1),\n            min_size=1,\n            max_size=255,\n        )\n    )\n    # invalid to have a weighting that disallows all possibilities\n    assume(sum(weights.values()) != 0)\n    # re-normalize probabilities to sum to some arbitrary target < 1\n    target = draw(st.floats(0.001, 0.999))\n    factor = target / sum(weights.values())\n    weights = {k: v * factor for k, v in weights.items()}\n    # float rounding error can cause this to fail.\n    assume(0.001 <= sum(weights.values()) <= 0.999)\n    return weights\n\n\n@st.composite\ndef integer_constraints(\n    draw,\n    *,\n    use_min_value=None,\n    use_max_value=None,\n    use_shrink_towards=None,\n    use_weights=None,\n    use_forced=False,\n):\n    min_value = None\n    max_value = None\n    shrink_towards = 0\n    weights = None\n\n    if use_min_value is None:\n        use_min_value = draw(st.booleans())\n    if use_max_value is None:\n        use_max_value = draw(st.booleans())\n    use_shrink_towards = draw(st.booleans())\n    if use_weights is None:\n        use_weights = (\n            draw(st.booleans()) if (use_min_value and use_max_value) else False\n        )\n\n    # Invariants:\n    # (1) min_value <= forced <= max_value\n    # (2) sum(weights.values()) < 1\n    # (3) len(weights) <= 255\n\n    if use_shrink_towards:\n        shrink_towards = draw(st.integers())\n\n    forced = draw(st.integers()) if use_forced else None\n    if use_weights:\n        assert use_max_value\n        assert use_min_value\n\n        min_value = draw(st.integers(max_value=forced))\n        min_val = max(min_value, forced) if forced is not None else min_value\n        max_value = draw(st.integers(min_value=min_val))\n\n        weights = draw(integer_weights(min_value, max_value))\n    else:\n        if use_min_value:\n            min_value = draw(st.integers(max_value=forced))\n        if use_max_value:\n            min_vals = []\n            if min_value is not None:\n                min_vals.append(min_value)\n            if forced is not None:\n                min_vals.append(forced)\n            min_val = max(min_vals) if min_vals else None\n            max_value = draw(st.integers(min_value=min_val))\n\n    if forced is not None:\n        assume((forced - shrink_towards).bit_length() < 128)\n\n    return {\n        \"min_value\": min_value,\n        \"max_value\": max_value,\n        \"shrink_towards\": shrink_towards,\n        \"weights\": weights,\n        \"forced\": forced,\n    }\n\n\n@st.composite\ndef _collection_constraints(\n    draw: DrawFn,\n    *,\n    forced: Any | None,\n    use_min_size: bool | None = None,\n    use_max_size: bool | None = None,\n) -> dict[str, int]:\n    min_size = 0\n    max_size = COLLECTION_DEFAULT_MAX_SIZE\n    # collections are quite expensive in entropy. cap to avoid overruns.\n    cap = 50\n\n    if use_min_size is None:\n        use_min_size = draw(st.booleans())\n    if use_max_size is None:\n        use_max_size = draw(st.booleans())\n\n    if use_min_size:\n        min_size = draw(\n            st.integers(0, min(len(forced), cap) if forced is not None else cap)\n        )\n\n    if use_max_size:\n        max_size = draw(\n            st.integers(\n                min_value=min_size if forced is None else max(min_size, len(forced))\n            )\n        )\n        if forced is None:\n            # cap to some reasonable max size to avoid overruns.\n            max_size = min(max_size, min_size + 100)\n\n    return {\"min_size\": min_size, \"max_size\": max_size}\n\n\n@st.composite\ndef string_constraints(\n    draw: DrawFn,\n    *,\n    use_min_size: bool | None = None,\n    use_max_size: bool | None = None,\n    use_forced: bool = False,\n) -> Any:\n    interval_set = draw(intervals())\n    forced = (\n        draw(TextStrategy(OneCharStringStrategy(interval_set))) if use_forced else None\n    )\n    constraints = draw(\n        _collection_constraints(\n            forced=forced, use_min_size=use_min_size, use_max_size=use_max_size\n        )\n    )\n    # if the intervalset is empty, then the min size must be zero, because the\n    # only valid value is the empty string.\n    if len(interval_set) == 0:\n        constraints[\"min_size\"] = 0\n\n    return {\"intervals\": interval_set, \"forced\": forced, **constraints}\n\n\n@st.composite\ndef bytes_constraints(\n    draw: DrawFn,\n    *,\n    use_min_size: bool | None = None,\n    use_max_size: bool | None = None,\n    use_forced: bool = False,\n) -> Any:\n    forced = draw(st.binary()) if use_forced else None\n\n    constraints = draw(\n        _collection_constraints(\n            forced=forced, use_min_size=use_min_size, use_max_size=use_max_size\n        )\n    )\n    return {\"forced\": forced, **constraints}\n\n\n@st.composite\ndef float_constraints(\n    draw,\n    *,\n    use_min_value=None,\n    use_max_value=None,\n    use_forced=False,\n):\n    if use_min_value is None:\n        use_min_value = draw(st.booleans())\n    if use_max_value is None:\n        use_max_value = draw(st.booleans())\n\n    forced = draw(st.floats()) if use_forced else None\n    pivot = forced if (use_forced and not math.isnan(forced)) else None\n    min_value = -math.inf\n    max_value = math.inf\n    smallest_nonzero_magnitude = SMALLEST_SUBNORMAL\n    allow_nan = True if (use_forced and math.isnan(forced)) else draw(st.booleans())\n\n    if use_min_value:\n        min_value = draw(st.floats(max_value=pivot, allow_nan=False))\n\n    if use_max_value:\n        if pivot is None:\n            min_val = min_value\n        else:\n            min_val = pivot if sign_aware_lte(min_value, pivot) else min_value\n        max_value = draw(st.floats(min_value=min_val, allow_nan=False))\n\n    largest_magnitude = max(abs(min_value), abs(max_value))\n    # can't force something smaller than our smallest magnitude.\n    if pivot is not None and pivot != 0.0:\n        largest_magnitude = min(largest_magnitude, pivot)\n\n    # avoid drawing from an empty range\n    if largest_magnitude > 0:\n        smallest_nonzero_magnitude = draw(\n            st.floats(\n                min_value=0,\n                # smallest_nonzero_magnitude breaks internal clamper invariants if\n                # it is allowed to be larger than the magnitude of {min, max}_value.\n                #\n                # Let's also be reasonable here; smallest_nonzero_magnitude is used\n                # for subnormals, so we will never provide a number above 1 in practice.\n                max_value=min(largest_magnitude, 1.0),\n                exclude_min=True,\n            )\n        )\n\n    assert sign_aware_lte(min_value, max_value)\n    return {\n        \"min_value\": min_value,\n        \"max_value\": max_value,\n        \"forced\": forced,\n        \"allow_nan\": allow_nan,\n        \"smallest_nonzero_magnitude\": smallest_nonzero_magnitude,\n    }\n\n\n@st.composite\ndef boolean_constraints(draw: DrawFn, *, use_forced: bool = False) -> Any:\n    forced = draw(st.booleans()) if use_forced else None\n    # avoid invalid forced combinations\n    p = draw(st.floats(0, 1, exclude_min=forced is True, exclude_max=forced is False))\n\n    return {\"p\": p, \"forced\": forced}\n\n\ndef constraints_strategy(choice_type, strategy_constraints=None, *, use_forced=False):\n    strategy = {\n        \"boolean\": boolean_constraints,\n        \"integer\": integer_constraints,\n        \"float\": float_constraints,\n        \"bytes\": bytes_constraints,\n        \"string\": string_constraints,\n    }[choice_type]\n    if strategy_constraints is None:\n        strategy_constraints = {}\n    return strategy(**strategy_constraints.get(choice_type, {}), use_forced=use_forced)\n\n\ndef choice_types_constraints(strategy_constraints=None, *, use_forced=False):\n    options: list[ChoiceTypeT] = [\"boolean\", \"integer\", \"float\", \"bytes\", \"string\"]\n    return st.one_of(\n        st.tuples(\n            st.just(name),\n            constraints_strategy(name, strategy_constraints, use_forced=use_forced),\n        )\n        for name in options\n    )\n\n\ndef run_conformance_test(\n    Provider: type[PrimitiveProvider],\n    *,\n    context_manager_exceptions: Collection[type[BaseException]] = (),\n    settings: Settings | None = None,\n    _realize_objects: SearchStrategy[Any] = (\n        st.from_type(object) | st.from_type(type).flatmap(st.from_type)\n    ),\n) -> None:\n    \"\"\"\n    Test that the given ``Provider`` class conforms to the |PrimitiveProvider|\n    interface.\n\n    For instance, this tests that ``Provider`` does not return out of bounds\n    choices from any of the ``draw_*`` methods, or violate other invariants\n    which Hypothesis depends on.\n\n    This function is intended to be called at test-time, not at runtime. It is\n    provided by Hypothesis to make it easy for third-party backend authors to\n    test their provider. Backend authors wishing to test their provider should\n    include a test similar to the following in their test suite:\n\n    .. code-block:: python\n\n        from hypothesis.internal.conjecture.provider_conformance import run_conformance_test\n\n        def test_conformance():\n            run_conformance_test(MyProvider)\n\n    If your provider can raise control flow exceptions inside one of the five\n    ``draw_*`` methods that are handled by your provider's\n    ``per_test_case_context_manager``, pass a list of these exceptions types to\n    ``context_manager_exceptions``. Otherwise, ``run_conformance_test`` will\n    treat those exceptions as fatal errors.\n    \"\"\"\n\n    class CopiesRealizationProvider(HypothesisProvider):\n        avoid_realization = Provider.avoid_realization\n\n    with with_register_backend(\"copies_realization\", CopiesRealizationProvider):\n\n        @Settings(\n            settings,\n            suppress_health_check=[HealthCheck.too_slow],\n            backend=\"copies_realization\",\n        )\n        class ProviderConformanceTest(RuleBasedStateMachine):\n            def __init__(self):\n                super().__init__()\n\n            @initialize(random=st.randoms())\n            def setup(self, random):\n                if Provider.lifetime == \"test_case\":\n                    data = ConjectureData(random=random, provider=Provider)\n                    self.provider = data.provider\n                else:\n                    self.provider = Provider(None)\n\n                self.context_manager = self.provider.per_test_case_context_manager()\n                self.context_manager.__enter__()\n                self.frozen = False\n\n            def _draw(self, choice_type, constraints):\n                del constraints[\"forced\"]\n                draw_func = getattr(self.provider, f\"draw_{choice_type}\")\n\n                try:\n                    choice = draw_func(**constraints)\n                    note(f\"drew {choice_type} {choice}\")\n                    expected_type = {\n                        \"integer\": int,\n                        \"float\": float,\n                        \"bytes\": bytes,\n                        \"string\": str,\n                        \"boolean\": bool,\n                    }[choice_type]\n                    assert isinstance(choice, expected_type)\n                    assert choice_permitted(choice, constraints)\n                except context_manager_exceptions as e:\n                    note(\n                        f\"caught exception {type(e)} in context_manager_exceptions: {e}\"\n                    )\n                    try:\n                        self.context_manager.__exit__(type(e), e, None)\n                    except BackendCannotProceed:\n                        self.frozen = True\n                        return None\n\n                return choice\n\n            @precondition(lambda self: not self.frozen)\n            @rule(constraints=integer_constraints())\n            def draw_integer(self, constraints):\n                self._draw(\"integer\", constraints)\n\n            @precondition(lambda self: not self.frozen)\n            @rule(constraints=float_constraints())\n            def draw_float(self, constraints):\n                self._draw(\"float\", constraints)\n\n            @precondition(lambda self: not self.frozen)\n            @rule(constraints=bytes_constraints())\n            def draw_bytes(self, constraints):\n                self._draw(\"bytes\", constraints)\n\n            @precondition(lambda self: not self.frozen)\n            @rule(constraints=string_constraints())\n            def draw_string(self, constraints):\n                self._draw(\"string\", constraints)\n\n            @precondition(lambda self: not self.frozen)\n            @rule(constraints=boolean_constraints())\n            def draw_boolean(self, constraints):\n                self._draw(\"boolean\", constraints)\n\n            @precondition(lambda self: not self.frozen)\n            @rule(label=st.integers())\n            def span_start(self, label):\n                self.provider.span_start(label)\n\n            @precondition(lambda self: not self.frozen)\n            @rule(discard=st.booleans())\n            def span_end(self, discard):\n                self.provider.span_end(discard)\n\n            @precondition(lambda self: not self.frozen)\n            @rule()\n            def freeze(self):\n                # phase-transition, mimicking data.freeze() at the end of a test case.\n                self.frozen = True\n                self.context_manager.__exit__(None, None, None)\n\n            @precondition(lambda self: self.frozen)\n            @rule(value=_realize_objects)\n            def realize(self, value):\n                # filter out nans and weirder things\n                try:\n                    assume(value == value)\n                except Exception:\n                    # e.g. value = Decimal('-sNaN')\n                    assume(False)\n\n                # if `value` is non-symbolic, the provider should return it as-is.\n                assert self.provider.realize(value) == value\n\n            @precondition(lambda self: self.frozen)\n            @rule()\n            def observe_test_case(self):\n                observations = self.provider.observe_test_case()\n                assert isinstance(observations, dict)\n\n            @precondition(lambda self: self.frozen)\n            @rule(lifetime=st.sampled_from([\"test_function\", \"test_case\"]))\n            def observe_information_messages(self, lifetime):\n                observations = self.provider.observe_information_messages(\n                    lifetime=lifetime\n                )\n                for observation in observations:\n                    assert isinstance(observation, dict)\n\n            def teardown(self):\n                if not self.frozen:\n                    self.context_manager.__exit__(None, None, None)\n\n        ProviderConformanceTest.TestCase().runTest()\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/providers.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport abc\nimport contextlib\nimport math\nimport sys\nimport warnings\nfrom collections.abc import Iterable\nfrom contextlib import AbstractContextManager, contextmanager\nfrom functools import cached_property\nfrom random import Random\nfrom sys import float_info\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    ClassVar,\n    Literal,\n    Optional,\n    TypeAlias,\n    TypedDict,\n    TypeVar,\n)\n\nfrom sortedcontainers import SortedSet\n\nfrom hypothesis.errors import HypothesisWarning\nfrom hypothesis.internal.cache import LRUCache\nfrom hypothesis.internal.compat import WINDOWS, int_from_bytes\nfrom hypothesis.internal.conjecture.choice import (\n    ChoiceConstraintsT,\n    ChoiceT,\n    ChoiceTypeT,\n    FloatConstraints,\n    choice_constraints_key,\n    choice_permitted,\n)\nfrom hypothesis.internal.conjecture.floats import lex_to_float\nfrom hypothesis.internal.conjecture.junkdrawer import bits_to_bytes\nfrom hypothesis.internal.conjecture.utils import (\n    INT_SIZES,\n    INT_SIZES_SAMPLER,\n    Sampler,\n    many,\n)\nfrom hypothesis.internal.constants_ast import (\n    Constants,\n    constants_from_module,\n    is_local_module_file,\n)\nfrom hypothesis.internal.floats import (\n    SIGNALING_NAN,\n    float_to_int,\n    make_float_clamper,\n    next_down,\n    next_up,\n)\nfrom hypothesis.internal.intervalsets import IntervalSet\nfrom hypothesis.internal.observability import InfoObservationType, TestCaseObservation\n\nif TYPE_CHECKING:\n    from hypothesis.internal.conjecture.data import ConjectureData\n    from hypothesis.internal.constants_ast import ConstantT\n\nT = TypeVar(\"T\")\nLifetimeT: TypeAlias = Literal[\"test_case\", \"test_function\"]\nCOLLECTION_DEFAULT_MAX_SIZE = 10**10  # \"arbitrarily large\"\n\n\n#: Registered Hypothesis backends. This is a dictionary where keys are the name\n#: to be used in |settings.backend|. The value of a key can be either:\n#:\n#: * A string corresponding to an importable absolute path of a\n#:   |PrimitiveProvider| subclass\n#: * A |PrimitiveProvider| subclass (the class itself, not an instance of the\n#:   class)\n#:\n#: Hypothesis will instantiate the corresponding |PrimitiveProvider| subclass\n#: when the backend is requested by a test's |settings.backend| value.\n#:\n#: For example, the default Hypothesis backend is registered as:\n#:\n#: .. code-block:: python\n#:\n#:    from hypothesis.internal.conjecture.providers import AVAILABLE_PROVIDERS\n#:\n#:    AVAILABLE_PROVIDERS[\"hypothesis\"] = \"hypothesis.internal.conjecture.providers.HypothesisProvider\"\n#:    # or\n#:    AVAILABLE_PROVIDERS[\"hypothesis\"] = HypothesisProvider\n#:\n#: And can be used with:\n#:\n#: .. code-block:: python\n#:\n#:     from hypothesis import given, settings, strategies as st\n#:\n#:     @given(st.integers())\n#:     @settings(backend=\"hypothesis\")\n#:     def f(n):\n#:         pass\n#:\n#: Though, as ``backend=\"hypothesis\"`` is the default setting, the above would\n#: typically not have any effect.\n#:\n#: For third-party backend authors, we strongly encourage ensuring that\n#: ``import hypothesis`` does not automatically import the expensive parts of\n#: your package, by:\n#:\n#: - setting a string path here, instead of a provider class\n#: - ensuring the registered hypothesis plugin path references a path which just\n#:   sets AVAILABLE_PROVIDERS and does not import your package\nAVAILABLE_PROVIDERS: dict[str, str | type[\"PrimitiveProvider\"]] = {\n    \"hypothesis\": \"hypothesis.internal.conjecture.providers.HypothesisProvider\",\n    \"hypothesis-urandom\": \"hypothesis.internal.conjecture.providers.URandomProvider\",\n}\n# cache the choice_permitted constants for a particular set of constraints.\nCacheKeyT: TypeAlias = tuple[ChoiceTypeT, tuple[Any, ...]]\nCacheValueT: TypeAlias = tuple[tuple[\"ConstantT\", ...], tuple[\"ConstantT\", ...]]\nCONSTANTS_CACHE: LRUCache[CacheKeyT, CacheValueT] = LRUCache(1024)\n\n\n_constants_integers = (\n    # powers of 2\n    [2**n for n in range(16, 66)]\n    # powers of 10\n    + [10**n for n in range(5, 20)]\n    # factorials\n    + [math.factorial(n) for n in range(9, 21)]\n    # a few primorial numbers https://en.wikipedia.org/wiki/Primorial\n    + [\n        510510,\n        6469693230,\n        304250263527210,\n        32589158477190044730,\n    ]\n)\n_constants_integers.extend(\n    [n - 1 for n in _constants_integers] + [n + 1 for n in _constants_integers]\n)\n_constants_integers.extend([-x for x in _constants_integers])\n\n# arbitrary cutoffs to keep our list bounded\nassert all(50_000 <= abs(n) <= 2**66 for n in _constants_integers)\n\n_constant_floats = (\n    [\n        0.5,\n        1.1,\n        1.5,\n        1.9,\n        1.0 / 3,\n        10e6,\n        10e-6,\n        1.175494351e-38,\n        next_up(0.0),\n        float_info.min,\n        float_info.max,\n        3.402823466e38,\n        9007199254740992.0,\n        1 - 10e-6,\n        2 + 10e-6,\n        1.192092896e-07,\n        2.2204460492503131e-016,\n    ]\n    + [2.0**-n for n in (24, 14, 149, 126)]  # minimum (sub)normals for float16,32\n    + [float_info.min / n for n in (2, 10, 1000, 100_000)]  # subnormal in float64\n)\n_constant_floats.extend([-x for x in _constant_floats])\nassert all(isinstance(f, float) for f in _constant_floats)\n\n_constant_strings = {\n    # strings which can be interpreted as code / logic\n    \"undefined\",\n    \"null\",\n    \"NULL\",\n    \"nil\",\n    \"NIL\",\n    \"true\",\n    \"false\",\n    \"True\",\n    \"False\",\n    \"TRUE\",\n    \"FALSE\",\n    \"None\",\n    \"none\",\n    \"if\",\n    \"then\",\n    \"else\",\n    \"__dict__\",\n    \"__proto__\",  # javascript\n    # strings which can be interpreted as a number\n    \"0\",\n    \"1e100\",\n    \"0..0\",\n    \"0/0\",\n    \"1/0\",\n    \"+0.0\",\n    \"Infinity\",\n    \"-Infinity\",\n    \"Inf\",\n    \"INF\",\n    \"NaN\",\n    \"9\" * 30,\n    # common ascii characters\n    \",./;'[]\\\\-=<>?:\\\"{}|_+!@#$%^&*()`~\",\n    # common unicode characters\n    \"Ω≈ç√∫˜µ≤≥÷åß∂ƒ©˙∆˚¬…æœ∑´®†¥¨ˆøπ“‘¡™£¢∞§¶•ªº–≠¸˛Ç◊ı˜Â¯˘¿ÅÍÎÏ˝ÓÔÒÚÆ☃Œ„´‰ˇÁ¨ˆØ∏”’`⁄€‹›ﬁﬂ‡°·‚—±\",\n    # characters which increase in length when lowercased\n    \"Ⱥ\",\n    \"Ⱦ\",\n    # ligatures\n    \"æœÆŒﬀʤʨß\",\n    # emoticons\n    \"(╯°□°）╯︵ ┻━┻)\",\n    # emojis\n    \"😍\",\n    \"🇺🇸\",\n    # emoji modifiers\n    \"🏻\",  # U+1F3FB Light Skin Tone,\n    \"👍🏻\",  # 👍 followed by U+1F3FB\n    # RTL text\n    \"الكل في المجمو عة\",\n    # Ogham text, which contains the only character in the Space Separators\n    # unicode category (Zs) that isn't visually blank:  .  # noqa: RUF003\n    \"᚛ᚄᚓᚐᚋᚒᚄ ᚑᚄᚂᚑᚏᚅ᚜\",\n    # readable variations on text (bolt/italic/script)\n    \"𝐓𝐡𝐞 𝐪𝐮𝐢𝐜𝐤 𝐛𝐫𝐨𝐰𝐧 𝐟𝐨𝐱 𝐣𝐮𝐦𝐩𝐬 𝐨𝐯𝐞𝐫 𝐭𝐡𝐞 𝐥𝐚𝐳𝐲 𝐝𝐨𝐠\",\n    \"𝕿𝖍𝖊 𝖖𝖚𝖎𝖈𝖐 𝖇𝖗𝖔𝖜𝖓 𝖋𝖔𝖝 𝖏𝖚𝖒𝖕𝖘 𝖔𝖛𝖊𝖗 𝖙𝖍𝖊 𝖑𝖆𝖟𝖞 𝖉𝖔𝖌\",\n    \"𝑻𝒉𝒆 𝒒𝒖𝒊𝒄𝒌 𝒃𝒓𝒐𝒘𝒏 𝒇𝒐𝒙 𝒋𝒖𝒎𝒑𝒔 𝒐𝒗𝒆𝒓 𝒕𝒉𝒆 𝒍𝒂𝒛𝒚 𝒅𝒐𝒈\",\n    \"𝓣𝓱𝓮 𝓺𝓾𝓲𝓬𝓴 𝓫𝓻𝓸𝔀𝓷 𝓯𝓸𝔁 𝓳𝓾𝓶𝓹𝓼 𝓸𝓿𝓮𝓻 𝓽𝓱𝓮 𝓵𝓪𝔃𝔂 𝓭𝓸𝓰\",\n    \"𝕋𝕙𝕖 𝕢𝕦𝕚𝕔𝕜 𝕓𝕣𝕠𝕨𝕟 𝕗𝕠𝕩 𝕛𝕦𝕞𝕡𝕤 𝕠𝕧𝕖𝕣 𝕥𝕙𝕖 𝕝𝕒𝕫𝕪 𝕕𝕠𝕘\",\n    # upsidown text\n    \"ʇǝɯɐ ʇᴉs ɹolop ɯnsdᴉ ɯǝɹo˥\",\n    # reserved strings in windows\n    \"NUL\",\n    \"COM1\",\n    \"LPT1\",\n    # scunthorpe problem\n    \"Scunthorpe\",\n    # zalgo text\n    \"Ṱ̺̺̕o͞ ̷i̲̬͇̪͙n̝̗͕v̟̜̘̦͟o̶̙̰̠kè͚̮̺̪̹̱̤ ̖t̝͕̳̣̻̪͞h̼͓̲̦̳̘̲e͇̣̰̦̬͎ ̢̼̻̱̘h͚͎͙̜̣̲ͅi̦̲̣̰̤v̻͍e̺̭̳̪̰-m̢iͅn̖̺̞̲̯̰d̵̼̟͙̩̼̘̳ ̞̥̱̳̭r̛̗̘e͙p͠r̼̞̻̭̗e̺̠̣͟s̘͇̳͍̝͉e͉̥̯̞̲͚̬͜ǹ̬͎͎̟̖͇̤t͍̬̤͓̼̭͘ͅi̪̱n͠g̴͉ ͏͉ͅc̬̟h͡a̫̻̯͘o̫̟̖͍̙̝͉s̗̦̲.̨̹͈̣\",\n    #\n    # examples from https://faultlore.com/blah/text-hates-you/\n    \"मनीष منش\",\n    \"पन्ह पन्ह त्र र्च कृकृ ड्ड न्हृे إلا بسم الله\",\n    \"lorem لا بسم الله ipsum 你好1234你好\",\n}\n\n\n# we don't actually care what order the constants are sorted in, just that the\n# ordering is deterministic.\nGLOBAL_CONSTANTS = Constants(\n    integers=SortedSet(_constants_integers),\n    floats=SortedSet(_constant_floats, key=float_to_int),\n    bytes=SortedSet(),\n    strings=SortedSet(_constant_strings),\n)\n\n_local_constants = Constants(\n    integers=SortedSet(),\n    floats=SortedSet(key=float_to_int),\n    bytes=SortedSet(),\n    strings=SortedSet(),\n)\n# modules that we've already seen and processed for local constants. These are\n# are all modules, not necessarily local ones. This lets us quickly see which\n# modules are new without an expensive path.resolve() or is_local_module_file\n# cache lookup.\n# We track by module object when hashable, falling back to the module name\n# (str key in sys.modules) for unhashable entries like SimpleNamespace.\n_seen_modules: set = set()\n_sys_modules_len: int | None = None\n\n\ndef _get_local_constants() -> Constants:\n    global _sys_modules_len, _local_constants\n\n    if sys.platform == \"emscripten\":  # pragma: no cover\n        # pyodide builds bundle the stdlib in a nonstandard location, like\n        # `/lib/python312.zip/heapq.py`. To avoid identifying the entirety of\n        # the stdlib as local code and slowing down on emscripten, instead return\n        # that nothing is local.\n        #\n        # pyodide may provide some way to distinguish stdlib/third-party/local\n        # code. I haven't looked into it. If they do, we should correctly implement\n        # ModuleLocation for pyodide instead of this.\n        return _local_constants\n\n    count_constants = len(_local_constants)\n    # We call this function once per HypothesisProvider instance, i.e. once per\n    # input, so it needs to be performant. The logic here is more complicated\n    # than necessary because of this.\n    #\n    # First, we check whether there are any new modules with a very cheap length\n    # check. This check can be fooled if a module is added while another module is\n    # removed, but the more correct check against tuple(sys.modules.keys()) is\n    # substantially more expensive. Such a new module would eventually be discovered\n    # if / when the length changes again in the future.\n    #\n    # If the length has changed, we find just modules we haven't seen before. Of\n    # those, we find the ones which correspond to local modules, and extract their\n    # constants.\n\n    # careful: store sys.modules length when we first check to avoid race conditions\n    # with other threads loading a module before we set _sys_modules_len.\n    if (sys_modules_len := len(sys.modules)) != _sys_modules_len:\n        new_modules = []\n        for name, module in list(sys.modules.items()):\n            try:\n                seen = module in _seen_modules\n            except TypeError:\n                # unhashable module (e.g. SimpleNamespace); fall back to name\n                seen = name in _seen_modules\n            if not seen:\n                new_modules.append((name, module))\n        # Repeated SortedSet unions are expensive. Do the initial unions on a\n        # set(), then do a one-time union with _local_constants after.\n        new_constants = Constants()\n        for name, module in new_modules:\n            if (\n                module_file := getattr(module, \"__file__\", None)\n            ) is not None and is_local_module_file(module_file):\n                new_constants |= constants_from_module(module)\n            try:\n                _seen_modules.add(module)\n            except TypeError:\n                _seen_modules.add(name)\n        _local_constants |= new_constants\n        _sys_modules_len = sys_modules_len\n\n    # if we add any new constant, invalidate the constant cache for permitted values.\n    # A more efficient approach would be invalidating just the keys with this\n    # choice_type.\n    if len(_local_constants) > count_constants:\n        CONSTANTS_CACHE.cache.clear()\n\n    return _local_constants\n\n\n@contextmanager\ndef with_register_backend(name, provider_cls):\n    try:\n        AVAILABLE_PROVIDERS[name] = provider_cls\n        yield\n    finally:\n        del AVAILABLE_PROVIDERS[name]\n\n\nclass _BackendInfoMsg(TypedDict):\n    type: InfoObservationType\n    title: str\n    content: str | dict[str, Any]\n\n\n# TODO_DOCS: link to choice sequence explanation page\n\n\nclass PrimitiveProvider(abc.ABC):\n    \"\"\"\n    |PrimitiveProvider| is the implementation interface of a\n    :ref:`Hypothesis backend <alternative-backends>`.\n\n    A |PrimitiveProvider| is required to implement the following five\n    ``draw_*`` methods:\n\n    * |PrimitiveProvider.draw_integer|\n    * |PrimitiveProvider.draw_boolean|\n    * |PrimitiveProvider.draw_float|\n    * |PrimitiveProvider.draw_string|\n    * |PrimitiveProvider.draw_bytes|\n\n    Each strategy in Hypothesis generates values by drawing a series of choices\n    from these five methods. By overriding them, a |PrimitiveProvider| can control\n    the distribution of inputs generated by Hypothesis.\n\n    For example, :pypi:`hypothesis-crosshair` implements a |PrimitiveProvider|\n    which uses an SMT solver to generate inputs that uncover new branches.\n\n    Once you implement a |PrimitiveProvider|, you can make it available for use\n    through |AVAILABLE_PROVIDERS|.\n    \"\"\"\n\n    #: The lifetime of a |PrimitiveProvider| instance. Either ``test_function``\n    #: or ``test_case``.\n    #:\n    #: If ``test_function`` (the default), a single provider instance will be\n    #: instantiated and used for the entirety of each test function (i.e., roughly\n    #: one provider per |@given| annotation). This can be useful for tracking state\n    #: over the entirety of a test function.\n    #:\n    #: If ``test_case``, a new provider instance will be instantiated and used for\n    #: each input Hypothesis generates.\n    #:\n    #: The ``conjecturedata`` argument to ``PrimitiveProvider.__init__`` will\n    #: be ``None`` for a lifetime of ``test_function``, and an instance of\n    #: ``ConjectureData`` for a lifetime of ``test_case``.\n    #:\n    #: Third-party providers likely want to set a lifetime of ``test_function``.\n    lifetime: ClassVar[LifetimeT] = \"test_function\"\n\n    #: Solver-based backends such as ``hypothesis-crosshair`` use symbolic values\n    #: which record operations performed on them in order to discover new paths.\n    #: If ``avoid_realization`` is set to ``True``, hypothesis will avoid interacting\n    #: with symbolic choices returned by the provider in any way that would force\n    #: the solver to narrow the range of possible values for that symbolic.\n    #:\n    #: Setting this to ``True`` disables some hypothesis features and optimizations.\n    #: Only set this to ``True`` if it is necessary for your backend.\n    avoid_realization: ClassVar[bool] = False\n\n    #: If ``True``, |PrimitiveProvider.on_observation| will be added as a\n    #: callback via |add_observability_callback|, enabling observability during\n    # the lifetime of this provider. If ``False``, |PrimitiveProvider.on_observation|\n    #: will never be called by Hypothesis.\n    #:\n    #: The opt-in behavior of observability is because enabling observability\n    #: might increase runtime or memory usage.\n    add_observability_callback: ClassVar[bool] = False\n\n    def __init__(self, conjecturedata: Optional[\"ConjectureData\"], /) -> None:\n        self._cd = conjecturedata\n\n    @abc.abstractmethod\n    def draw_boolean(\n        self,\n        p: float = 0.5,\n    ) -> bool:\n        \"\"\"\n        Draw a boolean choice.\n\n        Parameters\n        ----------\n        p: float\n            The probability of returning ``True``. Between 0 and 1 inclusive.\n\n            Except for ``0`` and ``1``, the value of ``p`` is a hint provided by\n            Hypothesis, and may be ignored by the backend.\n\n            If ``0``, the provider must return ``False``. If ``1``, the provider\n            must return ``True``.\n        \"\"\"\n        raise NotImplementedError\n\n    @abc.abstractmethod\n    def draw_integer(\n        self,\n        min_value: int | None = None,\n        max_value: int | None = None,\n        *,\n        weights: dict[int, float] | None = None,\n        shrink_towards: int = 0,\n    ) -> int:\n        \"\"\"\n        Draw an integer choice.\n\n        Parameters\n        ----------\n        min_value : int | None\n            (Inclusive) lower bound on the integer value. If ``None``, there is\n            no lower bound.\n        max_value : int | None\n            (Inclusive) upper bound on the integer value. If ``None``, there is\n            no upper bound.\n        weights: dict[int, float] | None\n            Maps keys in the range [``min_value``, ``max_value``] to the probability\n            of returning that key.\n        shrink_towards: int\n            The integer to shrink towards. This is not used during generation and\n            can be ignored by backends.\n        \"\"\"\n        raise NotImplementedError\n\n    @abc.abstractmethod\n    def draw_float(\n        self,\n        *,\n        min_value: float = -math.inf,\n        max_value: float = math.inf,\n        allow_nan: bool = True,\n        smallest_nonzero_magnitude: float,\n    ) -> float:\n        \"\"\"\n        Draw a float choice.\n\n        Parameters\n        ----------\n        min_value : float\n            (Inclusive) lower bound on the float value.\n        max_value : float\n            (Inclusive) upper bound on the float value.\n        allow_nan : bool\n            If ``False``, it is invalid to return ``math.nan``.\n        smallest_nonzero_magnitude : float\n            The smallest allowed nonzero magnitude. ``draw_float`` should not\n            return a float ``f`` if ``abs(f) < smallest_nonzero_magnitude``.\n        \"\"\"\n        raise NotImplementedError\n\n    @abc.abstractmethod\n    def draw_string(\n        self,\n        intervals: IntervalSet,\n        *,\n        min_size: int = 0,\n        max_size: int = COLLECTION_DEFAULT_MAX_SIZE,\n    ) -> str:\n        \"\"\"\n        Draw a string choice.\n\n        Parameters\n        ----------\n        intervals : IntervalSet\n            The set of codepoints to sample from.\n        min_size : int\n            (Inclusive) lower bound on the string length.\n        max_size : int\n            (Inclusive) upper bound on the string length.\n        \"\"\"\n        raise NotImplementedError\n\n    @abc.abstractmethod\n    def draw_bytes(\n        self,\n        min_size: int = 0,\n        max_size: int = COLLECTION_DEFAULT_MAX_SIZE,\n    ) -> bytes:\n        \"\"\"\n        Draw a bytes choice.\n\n        Parameters\n        ----------\n        min_size : int\n            (Inclusive) lower bound on the bytes length.\n        max_size : int\n            (Inclusive) upper bound on the bytes length.\n        \"\"\"\n        raise NotImplementedError\n\n    def per_test_case_context_manager(self) -> AbstractContextManager:\n        \"\"\"\n        Returns a context manager which will be entered each time Hypothesis\n        starts generating and executing one test case, and exited when that test\n        case finishes generating and executing, including if any exception is\n        thrown.\n\n        In the lifecycle of a Hypothesis test, this is called before\n        generating strategy values for each test case. This is just before any\n        :ref:`custom executor <custom-function-execution>` is called.\n\n        Even if not returning a custom context manager, |PrimitiveProvider|\n        subclasses are welcome to override this method to know when Hypothesis\n        starts and ends the execution of a single test case.\n        \"\"\"\n        return contextlib.nullcontext()\n\n    def realize(self, value: T, *, for_failure: bool = False) -> T:\n        \"\"\"\n        Called whenever hypothesis requires a concrete (non-symbolic) value from\n        a potentially symbolic value. Hypothesis will not check that ``value`` is\n        symbolic before calling ``realize``, so you should handle the case where\n        ``value`` is non-symbolic.\n\n        The returned value should be non-symbolic.  If you cannot provide a value,\n        raise |BackendCannotProceed| with a value of ``\"discard_test_case\"``.\n\n        If ``for_failure`` is ``True``, the value is associated with a failing example.\n        In this case, the backend should spend substantially more effort when\n        attempting to realize the value, since it is important to avoid discarding\n        failing examples. Backends may still raise |BackendCannotProceed| when\n        ``for_failure`` is ``True``, if realization is truly impossible or if\n        realization takes significantly longer than expected (say, 5 minutes).\n        \"\"\"\n        return value\n\n    def replay_choices(self, choices: tuple[ChoiceT, ...]) -> None:\n        \"\"\"\n        Called when Hypothesis has discovered a choice sequence which the provider\n        may wish to enqueue to replay under its own instrumentation when we next\n        ask to generate a test case, rather than generating one from scratch.\n\n        This is used to e.g. warm-start :pypi:`hypothesis-crosshair` with a corpus\n        of high-code-coverage inputs discovered by\n        `HypoFuzz <https://hypofuzz.com/>`_.\n        \"\"\"\n        return None\n\n    def observe_test_case(self) -> dict[str, Any]:\n        \"\"\"Called at the end of the test case when :ref:`observability\n        <observability>` is enabled.\n\n        The return value should be a non-symbolic json-encodable dictionary,\n        and will be included in observations as ``observation[\"metadata\"][\"backend\"]``.\n        \"\"\"\n        return {}\n\n    def observe_information_messages(\n        self, *, lifetime: LifetimeT\n    ) -> Iterable[_BackendInfoMsg]:\n        \"\"\"Called at the end of each test case and again at end of the test function.\n\n        Return an iterable of ``{type: info/alert/error, title: str, content: str | dict}``\n        dictionaries to be delivered as individual information messages. Hypothesis\n        adds the ``run_start`` timestamp and ``property`` name for you.\n        \"\"\"\n        assert lifetime in (\"test_case\", \"test_function\")\n        yield from []\n\n    def on_observation(self, observation: TestCaseObservation) -> None:  # noqa: B027\n        \"\"\"\n        Called at the end of each test case which uses this provider, with the same\n        ``observation[\"type\"] == \"test_case\"`` observation that is passed to\n        other callbacks added via |add_observability_callback|. This method is not\n        called with ``observation[\"type\"] in {\"info\", \"alert\", \"error\"}``\n        observations.\n\n        .. important::\n\n            For |PrimitiveProvider.on_observation| to be called by Hypothesis,\n            |PrimitiveProvider.add_observability_callback| must be set to ``True``.\n\n            |PrimitiveProvider.on_observation| is explicitly opt-in, as enabling\n            observability might increase runtime or memory usage.\n\n        Calls to this method are guaranteed to alternate with calls to\n        |PrimitiveProvider.per_test_case_context_manager|. For example:\n\n        .. code-block:: python\n\n            # test function starts\n            per_test_case_context_manager()\n            on_observation()\n            per_test_case_context_manager()\n            on_observation()\n            ...\n            # test function ends\n\n        Note that |PrimitiveProvider.on_observation| will not be called for test\n        cases which did not use this provider during generation, for example\n        during |Phase.reuse| or |Phase.shrink|, or because Hypothesis switched\n        to the standard Hypothesis backend after this backend raised too many\n        |BackendCannotProceed| exceptions.\n        \"\"\"\n\n    def span_start(self, label: int, /) -> None:  # noqa: B027  # non-abstract noop\n        \"\"\"Marks the beginning of a semantically meaningful span of choices.\n\n        Spans are a depth-first tree structure. A span is opened by a call to\n        |PrimitiveProvider.span_start|, and a call to |PrimitiveProvider.span_end|\n        closes the most recently opened span. So the following sequence of calls:\n\n        .. code-block:: python\n\n            span_start(label=1)\n            n1 = draw_integer()\n            span_start(label=2)\n            b1 = draw_boolean()\n            n2 = draw_integer()\n            span_end()\n            f1 = draw_float()\n            span_end()\n\n        produces the following two spans of choices:\n\n        .. code-block::\n\n            1: [n1, b1, n2, f1]\n            2: [b1, n2]\n\n        Hypothesis uses spans to denote \"semantically meaningful\" sequences of\n        choices. For instance, Hypothesis opens a span for the sequence of choices\n        made while drawing from each strategy. Not every span corresponds to a\n        strategy; the generation of e.g. each element in |st.lists| is also marked\n        with a span, among others.\n\n        ``label`` is an opaque integer, which has no defined semantics.\n        The only guarantee made by Hypothesis is that all spans with the same\n        \"meaning\" will share the same ``label``. So all spans from the same\n        strategy will share the same label, as will e.g. the spans for |st.lists|\n        elements.\n\n        Providers can track calls to |PrimitiveProvider.span_start| and\n        |PrimitiveProvider.span_end| to learn something about the semantics of\n        the test's choice sequence. For instance, a provider could track the depth\n        of the span tree, or the number of unique labels, which says something about\n        the complexity of the choices being generated. Or a provider could track\n        the span tree across test cases in order to determine what strategies are\n        being used in what contexts.\n\n        It is possible for Hypothesis to start and immediately stop a span,\n        without calling a ``draw_*`` method in between. These spans contain zero\n        choices.\n\n        Hypothesis will always balance the number of calls to\n        |PrimitiveProvider.span_start| and |PrimitiveProvider.span_end|. A call\n        to |PrimitiveProvider.span_start| will always be followed by a call to\n        |PrimitiveProvider.span_end| before the end of the test case.\n\n        |PrimitiveProvider.span_start| is called from ``ConjectureData.start_span()``\n        internally.\n        \"\"\"\n\n    def span_end(self, discard: bool, /) -> None:  # noqa: B027\n        \"\"\"Marks the end of a semantically meaningful span of choices.\n\n        ``discard`` is ``True`` when the draw was filtered out or otherwise marked\n        as unlikely to contribute to the input data as seen by the user's test.\n        Note however that side effects can make this determination unsound.\n\n        |PrimitiveProvider.span_end| is called from ``ConjectureData.stop_span()``\n        internally.\n        \"\"\"\n\n\nclass HypothesisProvider(PrimitiveProvider):\n    lifetime = \"test_case\"\n\n    def __init__(self, conjecturedata: Optional[\"ConjectureData\"], /):\n        super().__init__(conjecturedata)\n        self._random = None if self._cd is None else self._cd._random\n\n    @cached_property\n    def _local_constants(self):\n        # defer computation of local constants until/if we need it\n        return _get_local_constants()\n\n    def _maybe_draw_constant(\n        self,\n        choice_type: ChoiceTypeT,\n        constraints: ChoiceConstraintsT,\n        *,\n        p: float = 0.05,\n    ) -> Optional[\"ConstantT\"]:\n        assert self._random is not None\n        assert choice_type != \"boolean\"\n        # check whether we even want a constant before spending time computing\n        # and caching the allowed constants.\n        if self._random.random() > p:\n            return None\n\n        # note: this property access results in computation being done\n        assert self._local_constants is not None\n\n        key = (choice_type, choice_constraints_key(choice_type, constraints))\n        if key not in CONSTANTS_CACHE:\n            CONSTANTS_CACHE[key] = (\n                tuple(\n                    choice\n                    for choice in GLOBAL_CONSTANTS.set_for_type(choice_type)\n                    if choice_permitted(choice, constraints)\n                ),\n                tuple(\n                    choice\n                    for choice in self._local_constants.set_for_type(choice_type)\n                    if choice_permitted(choice, constraints)\n                ),\n            )\n\n        # split constants into two pools, so we still have a good chance to draw\n        # global constants even if there are many local constants.\n        global_constants, local_constants = CONSTANTS_CACHE[key]\n        constants_lists = ([global_constants] if global_constants else []) + (\n            [local_constants] if local_constants else []\n        )\n        if not constants_lists:\n            return None\n\n        # At this point, we've decided to use a constant. Now we select which pool\n        # to draw that constant from.\n        #\n        # Note that this approach has a different probability distribution than\n        # attempting a random.random for both global_constants and local_constants.\n        constants = self._random.choice(constants_lists)\n        return self._random.choice(constants)\n\n    def draw_boolean(\n        self,\n        p: float = 0.5,\n    ) -> bool:\n        assert self._random is not None\n\n        if p <= 0:\n            return False\n        if p >= 1:\n            return True\n\n        return self._random.random() < p\n\n    def draw_integer(\n        self,\n        min_value: int | None = None,\n        max_value: int | None = None,\n        *,\n        weights: dict[int, float] | None = None,\n        shrink_towards: int = 0,\n    ) -> int:\n        assert self._cd is not None\n        if (\n            constant := self._maybe_draw_constant(\n                \"integer\",\n                {\n                    \"min_value\": min_value,\n                    \"max_value\": max_value,\n                    \"weights\": weights,\n                    \"shrink_towards\": shrink_towards,\n                },\n            )\n        ) is not None:\n            assert isinstance(constant, int)\n            return constant\n\n        center = 0\n        if min_value is not None:\n            center = max(min_value, center)\n        if max_value is not None:\n            center = min(max_value, center)\n\n        if weights is not None:\n            assert min_value is not None\n            assert max_value is not None\n\n            # format of weights is a mapping of ints to p, where sum(p) < 1.\n            # The remaining probability mass is uniformly distributed over\n            # *all* ints (not just the unmapped ones; this is somewhat undesirable,\n            # but simplifies things).\n            #\n            # We assert that sum(p) is strictly less than 1 because it simplifies\n            # handling forced values when we can force into the unmapped probability\n            # mass. We should eventually remove this restriction.\n            sampler = Sampler(\n                [1 - sum(weights.values()), *weights.values()], observe=False\n            )\n            # if we're forcing, it's easiest to force into the unmapped probability\n            # mass and then force the drawn value after.\n            idx = sampler.sample(self._cd)\n\n            if idx == 0:\n                return self._draw_bounded_integer(min_value, max_value)\n            # implicit reliance on dicts being sorted for determinism\n            return list(weights)[idx - 1]\n\n        if min_value is None and max_value is None:\n            return self._draw_unbounded_integer()\n\n        if min_value is None:\n            assert max_value is not None\n            probe = max_value + 1\n            while max_value < probe:\n                probe = center + self._draw_unbounded_integer()\n            return probe\n\n        if max_value is None:\n            assert min_value is not None\n            probe = min_value - 1\n            while probe < min_value:\n                probe = center + self._draw_unbounded_integer()\n            return probe\n\n        return self._draw_bounded_integer(min_value, max_value)\n\n    def draw_float(\n        self,\n        *,\n        min_value: float = -math.inf,\n        max_value: float = math.inf,\n        allow_nan: bool = True,\n        smallest_nonzero_magnitude: float,\n    ) -> float:\n        assert self._random is not None\n\n        constraints: FloatConstraints = {\n            \"min_value\": min_value,\n            \"max_value\": max_value,\n            \"allow_nan\": allow_nan,\n            \"smallest_nonzero_magnitude\": smallest_nonzero_magnitude,\n        }\n        if (\n            constant := self._maybe_draw_constant(\"float\", constraints, p=0.15)\n        ) is not None:\n            assert isinstance(constant, float)\n            return constant\n\n        # on top of the probability to draw a constant float, we independently\n        # upweight 0.0/-0.0, math.inf, -math.inf, nans, and boundary values.\n        weird_floats = [\n            f\n            for f in [\n                0.0,\n                -0.0,\n                math.inf,\n                -math.inf,\n                math.nan,\n                -math.nan,\n                SIGNALING_NAN,\n                -SIGNALING_NAN,\n                min_value,\n                next_up(min_value),\n                min_value + 1,\n                max_value - 1,\n                next_down(max_value),\n                max_value,\n            ]\n            if choice_permitted(f, constraints)\n        ]\n\n        if weird_floats and self._random.random() < 0.05:\n            return self._random.choice(weird_floats)\n\n        clamper = make_float_clamper(\n            min_value,\n            max_value,\n            smallest_nonzero_magnitude=smallest_nonzero_magnitude,\n            allow_nan=allow_nan,\n        )\n\n        result = self._draw_float()\n        if allow_nan and math.isnan(result):\n            clamped = result  # pragma: no cover\n        else:\n            clamped = clamper(result)\n        if float_to_int(clamped) != float_to_int(result) and not (\n            math.isnan(result) and allow_nan\n        ):\n            result = clamped\n        return result\n\n    def draw_string(\n        self,\n        intervals: IntervalSet,\n        *,\n        min_size: int = 0,\n        max_size: int = COLLECTION_DEFAULT_MAX_SIZE,\n    ) -> str:\n        assert self._cd is not None\n        assert self._random is not None\n\n        if len(intervals) == 0:\n            return \"\"\n\n        if (\n            constant := self._maybe_draw_constant(\n                \"string\",\n                {\"intervals\": intervals, \"min_size\": min_size, \"max_size\": max_size},\n            )\n        ) is not None:\n            assert isinstance(constant, str)\n            return constant\n\n        average_size = min(\n            max(min_size * 2, min_size + 5),\n            0.5 * (min_size + max_size),\n        )\n\n        chars = []\n        elements = many(\n            self._cd,\n            min_size=min_size,\n            max_size=max_size,\n            average_size=average_size,\n            observe=False,\n        )\n        while elements.more():\n            if len(intervals) > 256:\n                if self.draw_boolean(0.2):\n                    i = self._random.randint(256, len(intervals) - 1)\n                else:\n                    i = self._random.randint(0, 255)\n            else:\n                i = self._random.randint(0, len(intervals) - 1)\n\n            chars.append(intervals.char_in_shrink_order(i))\n\n        return \"\".join(chars)\n\n    def draw_bytes(\n        self,\n        min_size: int = 0,\n        max_size: int = COLLECTION_DEFAULT_MAX_SIZE,\n    ) -> bytes:\n        assert self._cd is not None\n        assert self._random is not None\n\n        if (\n            constant := self._maybe_draw_constant(\n                \"bytes\", {\"min_size\": min_size, \"max_size\": max_size}\n            )\n        ) is not None:\n            assert isinstance(constant, bytes)\n            return constant\n\n        buf = bytearray()\n        average_size = min(\n            max(min_size * 2, min_size + 5),\n            0.5 * (min_size + max_size),\n        )\n        elements = many(\n            self._cd,\n            min_size=min_size,\n            max_size=max_size,\n            average_size=average_size,\n            observe=False,\n        )\n        while elements.more():\n            buf += self._random.randbytes(1)\n\n        return bytes(buf)\n\n    def _draw_float(self) -> float:\n        assert self._random is not None\n\n        f = lex_to_float(self._random.getrandbits(64))\n        sign = 1 if self._random.getrandbits(1) else -1\n        return sign * f\n\n    def _draw_unbounded_integer(self) -> int:\n        assert self._cd is not None\n        assert self._random is not None\n\n        size = INT_SIZES[INT_SIZES_SAMPLER.sample(self._cd)]\n\n        r = self._random.getrandbits(size)\n        sign = r & 1\n        r >>= 1\n        if sign:\n            r = -r\n        return r\n\n    def _draw_bounded_integer(\n        self,\n        lower: int,\n        upper: int,\n        *,\n        vary_size: bool = True,\n    ) -> int:\n        assert lower <= upper\n        assert self._cd is not None\n        assert self._random is not None\n\n        if lower == upper:\n            return lower\n\n        bits = (upper - lower).bit_length()\n        if bits > 24 and vary_size and self._random.random() < 7 / 8:\n            # For large ranges, we combine the uniform random distribution\n            # with a weighting scheme with moderate chance.  Cutoff at 2 ** 24 so that our\n            # choice of unicode characters is uniform but the 32bit distribution is not.\n            idx = INT_SIZES_SAMPLER.sample(self._cd)\n            cap_bits = min(bits, INT_SIZES[idx])\n            upper = min(upper, lower + 2**cap_bits - 1)\n            return self._random.randint(lower, upper)\n\n        return self._random.randint(lower, upper)\n\n\n# Masks for masking off the first byte of an n-bit buffer.\n# The appropriate mask is stored at position n % 8.\nBYTE_MASKS = [(1 << n) - 1 for n in range(8)]\nBYTE_MASKS[0] = 255\n\n\nclass BytestringProvider(PrimitiveProvider):\n    lifetime = \"test_case\"\n\n    def __init__(\n        self, conjecturedata: Optional[\"ConjectureData\"], /, *, bytestring: bytes\n    ):\n        super().__init__(conjecturedata)\n        self.bytestring = bytestring\n        self.index = 0\n        self.drawn = bytearray()\n\n    def _draw_bits(self, n):\n        if n == 0:  # pragma: no cover\n            return 0\n        n_bytes = bits_to_bytes(n)\n        if self.index + n_bytes > len(self.bytestring):\n            self._cd.mark_overrun()\n        buf = bytearray(self.bytestring[self.index : self.index + n_bytes])\n        self.index += n_bytes\n\n        buf[0] &= BYTE_MASKS[n % 8]\n        buf = bytes(buf)\n        self.drawn += buf\n        return int_from_bytes(buf)\n\n    def draw_boolean(\n        self,\n        p: float = 0.5,\n    ) -> bool:\n        if p <= 0:\n            return False\n        if p >= 1:\n            return True\n\n        # always use one byte for booleans to maintain constant draw size.\n        # If a probability requires more than 8 bits to represent precisely,\n        # the result will be slightly biased, but not badly.\n        bits = 8\n        size = 2**bits\n        # always leave at least one value that can be true, even for very small\n        # p.\n        falsey = max(1, math.floor(size * (1 - p)))\n        n = self._draw_bits(bits)\n        return n >= falsey\n\n    def draw_integer(\n        self,\n        min_value: int | None = None,\n        max_value: int | None = None,\n        *,\n        weights: dict[int, float] | None = None,\n        shrink_towards: int = 0,\n    ) -> int:\n        assert self._cd is not None\n\n        # we explicitly ignore integer weights for now, as they are likely net\n        # negative on fuzzer performance.\n\n        if min_value is None and max_value is None:\n            min_value = -(2**127)\n            max_value = 2**127 - 1\n        elif min_value is None:\n            assert max_value is not None\n            min_value = max_value - 2**64\n        elif max_value is None:\n            assert min_value is not None\n            max_value = min_value + 2**64\n\n        if min_value == max_value:\n            return min_value\n\n        bits = (max_value - min_value).bit_length()\n        value = self._draw_bits(bits)\n        while not (min_value <= value <= max_value):\n            value = self._draw_bits(bits)\n        return value\n\n    def draw_float(\n        self,\n        *,\n        min_value: float = -math.inf,\n        max_value: float = math.inf,\n        allow_nan: bool = True,\n        smallest_nonzero_magnitude: float,\n    ) -> float:\n        n = self._draw_bits(64)\n        sign = -1 if n >> 64 else 1\n        f = sign * lex_to_float(n & ((1 << 64) - 1))\n        clamper = make_float_clamper(\n            min_value,\n            max_value,\n            smallest_nonzero_magnitude=smallest_nonzero_magnitude,\n            allow_nan=allow_nan,\n        )\n        return clamper(f)\n\n    def _draw_collection(self, min_size, max_size, *, alphabet_size):\n        average_size = min(\n            max(min_size * 2, min_size + 5),\n            0.5 * (min_size + max_size),\n        )\n        elements = many(\n            self._cd,\n            min_size=min_size,\n            max_size=max_size,\n            average_size=average_size,\n            observe=False,\n        )\n        values = []\n        while elements.more():\n            values.append(self.draw_integer(0, alphabet_size - 1))\n        return values\n\n    def draw_string(\n        self,\n        intervals: IntervalSet,\n        *,\n        min_size: int = 0,\n        max_size: int = COLLECTION_DEFAULT_MAX_SIZE,\n    ) -> str:\n        values = self._draw_collection(min_size, max_size, alphabet_size=len(intervals))\n        return \"\".join(chr(intervals[v]) for v in values)\n\n    def draw_bytes(\n        self,\n        min_size: int = 0,\n        max_size: int = COLLECTION_DEFAULT_MAX_SIZE,\n    ) -> bytes:\n        values = self._draw_collection(min_size, max_size, alphabet_size=2**8)\n        return bytes(values)\n\n\nclass URandom(Random):\n    # we reimplement a Random instance instead of using SystemRandom, because\n    # os.urandom is not guaranteed to read from /dev/urandom.\n\n    @staticmethod\n    def _urandom(size: int) -> bytes:\n        with open(\"/dev/urandom\", \"rb\") as f:\n            return f.read(size)\n\n    def getrandbits(self, k: int) -> int:\n        assert k >= 0\n        size = bits_to_bytes(k)\n        n = int_from_bytes(self._urandom(size))\n        # trim excess bits\n        return n >> (size * 8 - k)\n\n    def random(self) -> float:\n        # adapted from random.SystemRandom.random\n        return (int_from_bytes(self._urandom(7)) >> 3) * (2**-53)\n\n\nclass URandomProvider(HypothesisProvider):\n    # A provider which reads directly from /dev/urandom as its source of randomness.\n    # This provider exists to provide better Hypothesis integration with Antithesis\n    # (https://antithesis.com/), which interprets calls to /dev/urandom as the\n    # randomness to mutate. This effectively gives Antithesis control over\n    # the choices made by the URandomProvider.\n    #\n    # If you are not using Antithesis, you probably don't want to use this\n    # provider.\n\n    def __init__(self, conjecturedata: Optional[\"ConjectureData\"], /):\n        super().__init__(conjecturedata)\n        if WINDOWS:  # pragma: no cover\n            warnings.warn(\n                \"/dev/urandom is not available on windows. Falling back to \"\n                'standard PRNG generation (equivalent to backend=\"hypothesis\").',\n                HypothesisWarning,\n                stacklevel=1,\n            )\n            # don't overwrite the HypothesisProvider self._random attribute in\n            # this case\n        else:\n            self._random = URandom()\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/shrinker.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nfrom collections import defaultdict\nfrom collections.abc import Callable, Sequence\nfrom dataclasses import dataclass\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    Literal,\n    TypeAlias,\n    cast,\n)\n\nfrom hypothesis.internal.conjecture.choice import (\n    ChoiceNode,\n    ChoiceT,\n    choice_equal,\n    choice_from_index,\n    choice_key,\n    choice_permitted,\n    choice_to_index,\n)\nfrom hypothesis.internal.conjecture.data import (\n    ConjectureData,\n    ConjectureResult,\n    Spans,\n    Status,\n    _Overrun,\n    draw_choice,\n)\nfrom hypothesis.internal.conjecture.junkdrawer import (\n    endswith,\n    find_integer,\n    replace_all,\n    startswith,\n)\nfrom hypothesis.internal.conjecture.shrinking import (\n    Bytes,\n    Float,\n    Integer,\n    Ordering,\n    String,\n)\nfrom hypothesis.internal.conjecture.shrinking.choicetree import (\n    ChoiceTree,\n    prefix_selection_order,\n    random_selection_order,\n)\nfrom hypothesis.internal.floats import MAX_PRECISE_INTEGER\n\nif TYPE_CHECKING:\n    from random import Random\n\n    from hypothesis.internal.conjecture.engine import ConjectureRunner\n\nShrinkPredicateT: TypeAlias = Callable[[ConjectureResult | _Overrun], bool]\n\n\ndef sort_key(nodes: Sequence[ChoiceNode]) -> tuple[int, tuple[int, ...]]:\n    \"\"\"Returns a sort key such that \"simpler\" choice sequences are smaller than\n    \"more complicated\" ones.\n\n    We define sort_key so that x is simpler than y if x is shorter than y or if\n    they have the same length and map(choice_to_index, x) < map(choice_to_index, y).\n\n    The reason for using this ordering is:\n\n    1. If x is shorter than y then that means we had to make fewer decisions\n       in constructing the test case when we ran x than we did when we ran y.\n    2. If x is the same length as y then replacing a choice with a lower index\n       choice corresponds to replacing it with a simpler/smaller choice.\n    3. Because choices drawn early in generation potentially get used in more\n       places they potentially have a more significant impact on the final\n       result, so it makes sense to prioritise reducing earlier choices over\n       later ones.\n    \"\"\"\n    return (\n        len(nodes),\n        tuple(choice_to_index(node.value, node.constraints) for node in nodes),\n    )\n\n\n@dataclass(slots=True, frozen=False)\nclass ShrinkPass:\n    function: Any\n    name: str | None = None\n    last_prefix: Any = ()\n\n    # some execution statistics\n    calls: int = 0\n    misaligned: int = 0\n    shrinks: int = 0\n    deletions: int = 0\n\n    def __post_init__(self):\n        if self.name is None:\n            self.name = self.function.__name__\n\n    def __hash__(self):\n        return hash(self.name)\n\n\nclass StopShrinking(Exception):\n    pass\n\n\nclass Shrinker:\n    \"\"\"A shrinker is a child object of a ConjectureRunner which is designed to\n    manage the associated state of a particular shrink problem. That is, we\n    have some initial ConjectureData object and some property of interest\n    that it satisfies, and we want to find a ConjectureData object with a\n    shortlex (see sort_key above) smaller choice sequence that exhibits the same\n    property.\n\n    Currently the only property of interest we use is that the status is\n    INTERESTING and the interesting_origin takes on some fixed value, but we\n    may potentially be interested in other use cases later.\n    However we assume that data with a status < VALID never satisfies the predicate.\n\n    The shrinker keeps track of a value shrink_target which represents the\n    current best known ConjectureData object satisfying the predicate.\n    It refines this value by repeatedly running *shrink passes*, which are\n    methods that perform a series of transformations to the current shrink_target\n    and evaluate the underlying test function to find new ConjectureData\n    objects. If any of these satisfy the predicate, the shrink_target\n    is updated automatically. Shrinking runs until no shrink pass can\n    improve the shrink_target, at which point it stops. It may also be\n    terminated if the underlying engine throws RunIsComplete, but that\n    is handled by the calling code rather than the Shrinker.\n\n    =======================\n    Designing Shrink Passes\n    =======================\n\n    Generally a shrink pass is just any function that calls\n    cached_test_function and/or consider_new_nodes a number of times,\n    but there are a couple of useful things to bear in mind.\n\n    A shrink pass *makes progress* if running it changes self.shrink_target\n    (i.e. it tries a shortlex smaller ConjectureData object satisfying\n    the predicate). The desired end state of shrinking is to find a\n    value such that no shrink pass can make progress, i.e. that we\n    are at a local minimum for each shrink pass.\n\n    In aid of this goal, the main invariant that a shrink pass much\n    satisfy is that whether it makes progress must be deterministic.\n    It is fine (encouraged even) for the specific progress it makes\n    to be non-deterministic, but if you run a shrink pass, it makes\n    no progress, and then you immediately run it again, it should\n    never succeed on the second time. This allows us to stop as soon\n    as we have run each shrink pass and seen no progress on any of\n    them.\n\n    This means that e.g. it's fine to try each of N deletions\n    or replacements in a random order, but it's not OK to try N random\n    deletions (unless you have already shrunk at least once, though we\n    don't currently take advantage of this loophole).\n\n    Shrink passes need to be written so as to be robust against\n    change in the underlying shrink target. It is generally safe\n    to assume that the shrink target does not change prior to the\n    point of first modification - e.g. if you change no bytes at\n    index ``i``, all spans whose start is ``<= i`` still exist,\n    as do all blocks, and the data object is still of length\n    ``>= i + 1``. This can only be violated by bad user code which\n    relies on an external source of non-determinism.\n\n    When the underlying shrink_target changes, shrink\n    passes should not run substantially more test_function calls\n    on success than they do on failure. Say, no more than a constant\n    factor more. In particular shrink passes should not iterate to a\n    fixed point.\n\n    This means that shrink passes are often written with loops that\n    are carefully designed to do the right thing in the case that no\n    shrinks occurred and try to adapt to any changes to do a reasonable\n    job. e.g. say we wanted to write a shrink pass that tried deleting\n    each individual choice (this isn't an especially good pass,\n    but it leads to a simple illustrative example), we might do it\n    by iterating over the choice sequence like so:\n\n    .. code-block:: python\n\n        i = 0\n        while i < len(self.shrink_target.nodes):\n            if not self.consider_new_nodes(\n                self.shrink_target.nodes[:i] + self.shrink_target.nodes[i + 1 :]\n            ):\n                i += 1\n\n    The reason for writing the loop this way is that i is always a\n    valid index into the current choice sequence, even if the current sequence\n    changes as a result of our actions. When the choice sequence changes,\n    we leave the index where it is rather than restarting from the\n    beginning, and carry on. This means that the number of steps we\n    run in this case is always bounded above by the number of steps\n    we would run if nothing works.\n\n    Another thing to bear in mind about shrink pass design is that\n    they should prioritise *progress*. If you have N operations that\n    you need to run, you should try to order them in such a way as\n    to avoid stalling, where you have long periods of test function\n    invocations where no shrinks happen. This is bad because whenever\n    we shrink we reduce the amount of work the shrinker has to do\n    in future, and often speed up the test function, so we ideally\n    wanted those shrinks to happen much earlier in the process.\n\n    Sometimes stalls are inevitable of course - e.g. if the pass\n    makes no progress, then the entire thing is just one long stall,\n    but it's helpful to design it so that stalls are less likely\n    in typical behaviour.\n\n    The two easiest ways to do this are:\n\n    * Just run the N steps in random order. As long as a\n      reasonably large proportion of the operations succeed, this\n      guarantees the expected stall length is quite short. The\n      book keeping for making sure this does the right thing when\n      it succeeds can be quite annoying.\n    * When you have any sort of nested loop, loop in such a way\n      that both loop variables change each time. This prevents\n      stalls which occur when one particular value for the outer\n      loop is impossible to make progress on, rendering the entire\n      inner loop into a stall.\n\n    However, although progress is good, too much progress can be\n    a bad sign! If you're *only* seeing successful reductions,\n    that's probably a sign that you are making changes that are\n    too timid. Two useful things to offset this:\n\n    * It's worth writing shrink passes which are *adaptive*, in\n      the sense that when operations seem to be working really\n      well we try to bundle multiple of them together. This can\n      often be used to turn what would be O(m) successful calls\n      into O(log(m)).\n    * It's often worth trying one or two special minimal values\n      before trying anything more fine grained (e.g. replacing\n      the whole thing with zero).\n\n    \"\"\"\n\n    def derived_value(fn):\n        \"\"\"It's useful during shrinking to have access to derived values of\n        the current shrink target.\n\n        This decorator allows you to define these as cached properties. They\n        are calculated once, then cached until the shrink target changes, then\n        recalculated the next time they are used.\"\"\"\n\n        def accept(self):\n            try:\n                return self.__derived_values[fn.__name__]\n            except KeyError:\n                return self.__derived_values.setdefault(fn.__name__, fn(self))\n\n        accept.__name__ = fn.__name__\n        return property(accept)\n\n    def __init__(\n        self,\n        engine: \"ConjectureRunner\",\n        initial: ConjectureData | ConjectureResult,\n        predicate: ShrinkPredicateT | None,\n        *,\n        allow_transition: (\n            Callable[[ConjectureData | ConjectureResult, ConjectureData], bool] | None\n        ),\n        explain: bool,\n        in_target_phase: bool = False,\n    ):\n        \"\"\"Create a shrinker for a particular engine, with a given starting\n        point and predicate. When shrink() is called it will attempt to find an\n        example for which predicate is True and which is strictly smaller than\n        initial.\n\n        Note that initial is a ConjectureData object, and predicate\n        takes ConjectureData objects.\n        \"\"\"\n        assert predicate is not None or allow_transition is not None\n        self.engine = engine\n        self.__predicate = predicate or (lambda data: True)\n        self.__allow_transition = allow_transition or (lambda source, destination: True)\n        self.__derived_values: dict = {}\n\n        self.initial_size = len(initial.choices)\n        # We keep track of the current best example on the shrink_target\n        # attribute.\n        self.shrink_target = initial\n        self.clear_change_tracking()\n        self.shrinks = 0\n\n        # We terminate shrinks that seem to have reached their logical\n        # conclusion: If we've called the underlying test function at\n        # least self.max_stall times since the last time we shrunk,\n        # it's time to stop shrinking.\n        self.max_stall = 200\n        self.initial_calls = self.engine.call_count\n        self.initial_misaligned = self.engine.misaligned_count\n        self.calls_at_last_shrink = self.initial_calls\n\n        self.shrink_passes: list[ShrinkPass] = [\n            ShrinkPass(self.try_trivial_spans),\n            self.node_program(\"X\" * 5),\n            self.node_program(\"X\" * 4),\n            self.node_program(\"X\" * 3),\n            self.node_program(\"X\" * 2),\n            self.node_program(\"X\" * 1),\n            ShrinkPass(self.pass_to_descendant),\n            ShrinkPass(self.reorder_spans),\n            ShrinkPass(self.minimize_duplicated_choices),\n            ShrinkPass(self.minimize_individual_choices),\n            ShrinkPass(self.redistribute_numeric_pairs),\n            ShrinkPass(self.lower_integers_together),\n            ShrinkPass(self.lower_duplicated_characters),\n        ]\n\n        # Because the shrinker is also used to `pareto_optimise` in the target phase,\n        # we sometimes want to allow extending buffers instead of aborting at the end.\n        self.__extend: Literal[\"full\"] | int = \"full\" if in_target_phase else 0\n        self.should_explain = explain\n\n    @derived_value  # type: ignore\n    def cached_calculations(self):\n        return {}\n\n    def cached(self, *keys):\n        def accept(f):\n            cache_key = (f.__name__, *keys)\n            try:\n                return self.cached_calculations[cache_key]\n            except KeyError:\n                return self.cached_calculations.setdefault(cache_key, f())\n\n        return accept\n\n    @property\n    def calls(self) -> int:\n        \"\"\"Return the number of calls that have been made to the underlying\n        test function.\"\"\"\n        return self.engine.call_count\n\n    @property\n    def misaligned(self) -> int:\n        return self.engine.misaligned_count\n\n    def check_calls(self) -> None:\n        if self.calls - self.calls_at_last_shrink >= self.max_stall:\n            raise StopShrinking\n\n    def cached_test_function(\n        self, nodes: Sequence[ChoiceNode]\n    ) -> tuple[bool, ConjectureResult | _Overrun | None]:\n        nodes = nodes[: len(self.nodes)]\n\n        if startswith(nodes, self.nodes):\n            return (True, None)\n\n        if sort_key(self.nodes) < sort_key(nodes):\n            return (False, None)\n\n        # sometimes our shrinking passes try obviously invalid things. We handle\n        # discarding them in one place here.\n        if any(not choice_permitted(node.value, node.constraints) for node in nodes):\n            return (False, None)\n\n        result = self.engine.cached_test_function(\n            [n.value for n in nodes], extend=self.__extend\n        )\n        previous = self.shrink_target\n        self.incorporate_test_data(result)\n        self.check_calls()\n        return (previous is not self.shrink_target, result)\n\n    def consider_new_nodes(self, nodes: Sequence[ChoiceNode]) -> bool:\n        return self.cached_test_function(nodes)[0]\n\n    def incorporate_test_data(self, data):\n        \"\"\"Takes a ConjectureData or Overrun object updates the current\n        shrink_target if this data represents an improvement over it.\"\"\"\n        if data.status < Status.VALID or data is self.shrink_target:\n            return\n        if (\n            self.__predicate(data)\n            and sort_key(data.nodes) < sort_key(self.shrink_target.nodes)\n            and self.__allow_transition(self.shrink_target, data)\n        ):\n            self.update_shrink_target(data)\n\n    def debug(self, msg: str) -> None:\n        self.engine.debug(msg)\n\n    @property\n    def random(self) -> \"Random\":\n        return self.engine.random\n\n    def shrink(self) -> None:\n        \"\"\"Run the full set of shrinks and update shrink_target.\n\n        This method is \"mostly idempotent\" - calling it twice is unlikely to\n        have any effect, though it has a non-zero probability of doing so.\n        \"\"\"\n\n        try:\n            self.initial_coarse_reduction()\n            self.greedy_shrink()\n        except StopShrinking:\n            # If we stopped shrinking because we're making slow progress (instead of\n            # reaching a local optimum), don't run the explain-phase logic.\n            self.should_explain = False\n        finally:\n            if self.engine.report_debug_info:\n\n                def s(n):\n                    return \"s\" if n != 1 else \"\"\n\n                total_deleted = self.initial_size - len(self.shrink_target.choices)\n                calls = self.engine.call_count - self.initial_calls\n                misaligned = self.engine.misaligned_count - self.initial_misaligned\n\n                self.debug(\n                    \"---------------------\\n\"\n                    \"Shrink pass profiling\\n\"\n                    \"---------------------\\n\\n\"\n                    f\"Shrinking made a total of {calls} call{s(calls)} of which \"\n                    f\"{self.shrinks} shrank and {misaligned} were misaligned. This \"\n                    f\"deleted {total_deleted} choices out of {self.initial_size}.\"\n                )\n                for useful in [True, False]:\n                    self.debug(\"\")\n                    if useful:\n                        self.debug(\"Useful passes:\")\n                    else:\n                        self.debug(\"Useless passes:\")\n                    self.debug(\"\")\n                    for pass_ in sorted(\n                        self.shrink_passes,\n                        key=lambda t: (-t.calls, t.deletions, t.shrinks),\n                    ):\n                        if pass_.calls == 0:\n                            continue\n                        if (pass_.shrinks != 0) != useful:\n                            continue\n\n                        self.debug(\n                            f\"  * {pass_.name} made {pass_.calls} call{s(pass_.calls)} of which \"\n                            f\"{pass_.shrinks} shrank and {pass_.misaligned} were misaligned, \"\n                            f\"deleting {pass_.deletions} choice{s(pass_.deletions)}.\"\n                        )\n                self.debug(\"\")\n        self.explain()\n\n    def explain(self) -> None:\n\n        if not self.should_explain or not self.shrink_target.arg_slices:\n            return\n\n        self.max_stall = 2**100\n        shrink_target = self.shrink_target\n        nodes = self.nodes\n        choices = self.choices\n        chunks: dict[tuple[int, int], list[tuple[ChoiceT, ...]]] = defaultdict(list)\n\n        # Before we start running experiments, let's check for known inputs which would\n        # make them redundant.  The shrinking process means that we've already tried many\n        # variations on the minimal example, so this can save a lot of time.\n        seen_passing_seq = self.engine.passing_choice_sequences(\n            prefix=self.nodes[: min(self.shrink_target.arg_slices)[0]]\n        )\n\n        # Now that we've shrunk to a minimal failing example, it's time to try\n        # varying each part that we've noted will go in the final report.  Consider\n        # slices in largest-first order\n        for start, end in sorted(\n            self.shrink_target.arg_slices, key=lambda x: (-(x[1] - x[0]), x)\n        ):\n            # Check for any previous examples that match the prefix and suffix,\n            # so we can skip if we found a passing example while shrinking.\n            if any(\n                startswith(seen, nodes[:start]) and endswith(seen, nodes[end:])\n                for seen in seen_passing_seq\n            ):\n                continue\n\n            # Skip slices that are subsets of already-explained slices.\n            # If a larger slice can vary freely, so can its sub-slices.\n            # Note: (0, 0) is a special marker for the \"together\" comment that\n            # applies to the whole test, not a specific slice, so we exclude it.\n            if any(\n                s <= start and end <= e\n                for s, e in self.shrink_target.slice_comments\n                if (s, e) != (0, 0)\n            ):\n                continue\n\n            # Run our experiments\n            n_same_failures = 0\n            note = \"or any other generated value\"\n            # TODO: is 100 same-failures out of 500 attempts a good heuristic?\n            for n_attempt in range(500):  # pragma: no branch\n                # no-branch here because we don't coverage-test the abort-at-500 logic.\n\n                if n_attempt - 10 > n_same_failures * 5:\n                    # stop early if we're seeing mostly invalid examples\n                    break  # pragma: no cover\n\n                # replace start:end with random values\n                replacement = []\n                for i in range(start, end):\n                    node = nodes[i]\n                    if not node.was_forced:\n                        value = draw_choice(\n                            node.type, node.constraints, random=self.random\n                        )\n                        node = node.copy(with_value=value)\n                    replacement.append(node.value)\n\n                attempt = choices[:start] + tuple(replacement) + choices[end:]\n                result = self.engine.cached_test_function(attempt, extend=\"full\")\n\n                if result.status is Status.OVERRUN:\n                    continue  # pragma: no cover  # flakily covered\n                result = cast(ConjectureResult, result)\n                if not (\n                    len(attempt) == len(result.choices)\n                    and endswith(result.nodes, nodes[end:])\n                ):\n                    # Turns out this was a variable-length part, so grab the infix...\n                    for span1, span2 in zip(\n                        shrink_target.spans, result.spans, strict=False\n                    ):\n                        assert span1.start == span2.start\n                        assert span1.start <= start\n                        assert span1.label == span2.label\n                        if span1.start == start and span1.end == end:\n                            result_end = span2.end\n                            break\n                    else:\n                        raise NotImplementedError(\"Expected matching prefixes\")\n\n                    attempt = (\n                        choices[:start]\n                        + result.choices[start:result_end]\n                        + choices[end:]\n                    )\n                    chunks[(start, end)].append(result.choices[start:result_end])\n                    result = self.engine.cached_test_function(attempt)\n\n                    if result.status is Status.OVERRUN:\n                        continue  # pragma: no cover  # flakily covered\n                    result = cast(ConjectureResult, result)\n                else:\n                    chunks[(start, end)].append(result.choices[start:end])\n\n                if shrink_target is not self.shrink_target:  # pragma: no cover\n                    # If we've shrunk further without meaning to, bail out.\n                    self.shrink_target.slice_comments.clear()\n                    return\n                if result.status is Status.VALID:\n                    # The test passed, indicating that this param can't vary freely.\n                    # However, it's really hard to write a simple and reliable covering\n                    # test, because of our `seen_passing_buffers` check above.\n                    break  # pragma: no cover\n                if self.__predicate(result):  # pragma: no branch\n                    n_same_failures += 1\n                    if n_same_failures >= 100:\n                        self.shrink_target.slice_comments[(start, end)] = note\n                        break\n\n        # Finally, if we've found multiple independently-variable parts, check whether\n        # they can all be varied together.\n        if len(self.shrink_target.slice_comments) <= 1:\n            return\n        n_same_failures_together = 0\n        # Only include slices that were actually added to slice_comments\n        chunks_by_start_index = sorted(\n            (k, v) for k, v in chunks.items() if k in self.shrink_target.slice_comments\n        )\n        for _ in range(500):  # pragma: no branch\n            # no-branch here because we don't coverage-test the abort-at-500 logic.\n            new_choices: list[ChoiceT] = []\n            prev_end = 0\n            for (start, end), ls in chunks_by_start_index:\n                assert prev_end <= start < end, \"these chunks must be nonoverlapping\"\n                new_choices.extend(choices[prev_end:start])\n                new_choices.extend(self.random.choice(ls))\n                prev_end = end\n\n            result = self.engine.cached_test_function(new_choices)\n\n            # This *can't* be a shrink because none of the components were.\n            assert shrink_target is self.shrink_target\n            if result.status == Status.VALID:\n                self.shrink_target.slice_comments[(0, 0)] = (\n                    \"The test sometimes passed when commented parts were varied together.\"\n                )\n                break  # Test passed, this param can't vary freely.\n            if self.__predicate(result):  # pragma: no branch\n                n_same_failures_together += 1\n                if n_same_failures_together >= 100:\n                    self.shrink_target.slice_comments[(0, 0)] = (\n                        \"The test always failed when commented parts were varied together.\"\n                    )\n                    break\n\n    def greedy_shrink(self) -> None:\n        \"\"\"Run a full set of greedy shrinks (that is, ones that will only ever\n        move to a better target) and update shrink_target appropriately.\n\n        This method iterates to a fixed point and so is idempontent - calling\n        it twice will have exactly the same effect as calling it once.\n        \"\"\"\n        self.fixate_shrink_passes(self.shrink_passes)\n\n    def initial_coarse_reduction(self):\n        \"\"\"Performs some preliminary reductions that should not be\n        repeated as part of the main shrink passes.\n\n        The main reason why these can't be included as part of shrink\n        passes is that they have much more ability to make the test\n        case \"worse\". e.g. they might rerandomise part of it, significantly\n        increasing the value of individual nodes, which works in direct\n        opposition to the lexical shrinking and will frequently undo\n        its work.\n        \"\"\"\n        self.reduce_each_alternative()\n\n    @derived_value  # type: ignore\n    def spans_starting_at(self):\n        result = [[] for _ in self.shrink_target.nodes]\n        for i, ex in enumerate(self.spans):\n            # We can have zero-length spans that start at the end\n            if ex.start < len(result):\n                result[ex.start].append(i)\n        return tuple(map(tuple, result))\n\n    def reduce_each_alternative(self):\n        \"\"\"This is a pass that is designed to rerandomise use of the\n        one_of strategy or things that look like it, in order to try\n        to move from later strategies to earlier ones in the branch\n        order.\n\n        It does this by trying to systematically lower each value it\n        finds that looks like it might be the branch decision for\n        one_of, and then attempts to repair any changes in shape that\n        this causes.\n        \"\"\"\n        i = 0\n        while i < len(self.shrink_target.nodes):\n            nodes = self.shrink_target.nodes\n            node = nodes[i]\n            if (\n                node.type == \"integer\"\n                and not node.was_forced\n                and node.value <= 10\n                and node.constraints[\"min_value\"] == 0\n            ):\n                assert isinstance(node.value, int)\n\n                # We've found a plausible candidate for a ``one_of`` choice.\n                # We now want to see if the shape of the test case actually depends\n                # on it. If it doesn't, then we don't need to do this (comparatively\n                # costly) pass, and can let much simpler lexicographic reduction\n                # handle it later.\n                #\n                # We test this by trying to set the value to zero and seeing if the\n                # shape changes, as measured by either changing the number of subsequent\n                # nodes, or changing the nodes in such a way as to cause one of the\n                # previous values to no longer be valid in its position.\n                zero_attempt = self.cached_test_function(\n                    nodes[:i] + (nodes[i].copy(with_value=0),) + nodes[i + 1 :]\n                )[1]\n                if (\n                    zero_attempt is not self.shrink_target\n                    and zero_attempt is not None\n                    and zero_attempt.status >= Status.VALID\n                ):\n                    changed_shape = len(zero_attempt.nodes) != len(nodes)\n\n                    if not changed_shape:\n                        for j in range(i + 1, len(nodes)):\n                            zero_node = zero_attempt.nodes[j]\n                            orig_node = nodes[j]\n                            if (\n                                zero_node.type != orig_node.type\n                                or not choice_permitted(\n                                    orig_node.value, zero_node.constraints\n                                )\n                            ):\n                                changed_shape = True\n                                break\n                    if changed_shape:\n                        for v in range(node.value):\n                            if self.try_lower_node_as_alternative(i, v):\n                                break\n            i += 1\n\n    def try_lower_node_as_alternative(self, i, v):\n        \"\"\"Attempt to lower `self.shrink_target.nodes[i]` to `v`,\n        while rerandomising and attempting to repair any subsequent\n        changes to the shape of the test case that this causes.\"\"\"\n        nodes = self.shrink_target.nodes\n        if self.consider_new_nodes(\n            nodes[:i] + (nodes[i].copy(with_value=v),) + nodes[i + 1 :]\n        ):\n            return True\n\n        prefix = nodes[:i] + (nodes[i].copy(with_value=v),)\n        initial = self.shrink_target\n        spans = self.spans_starting_at[i]\n        for _ in range(3):\n            random_attempt = self.engine.cached_test_function(\n                [n.value for n in prefix], extend=len(nodes)\n            )\n            if random_attempt.status < Status.VALID:\n                continue\n            self.incorporate_test_data(random_attempt)\n            for j in spans:\n                initial_span = initial.spans[j]\n                attempt_span = random_attempt.spans[j]\n                contents = random_attempt.nodes[attempt_span.start : attempt_span.end]\n                self.consider_new_nodes(\n                    nodes[:i] + contents + nodes[initial_span.end :]\n                )\n                if initial is not self.shrink_target:\n                    return True\n        return False\n\n    @derived_value  # type: ignore\n    def shrink_pass_choice_trees(self) -> dict[Any, ChoiceTree]:\n        return defaultdict(ChoiceTree)\n\n    def step(self, shrink_pass: ShrinkPass, *, random_order: bool = False) -> bool:\n        tree = self.shrink_pass_choice_trees[shrink_pass]\n        if tree.exhausted:\n            return False\n\n        initial_shrinks = self.shrinks\n        initial_calls = self.calls\n        initial_misaligned = self.misaligned\n        size = len(self.shrink_target.choices)\n        assert shrink_pass.name is not None\n        self.engine.explain_next_call_as(shrink_pass.name)\n\n        if random_order:\n            selection_order = random_selection_order(self.random)\n        else:\n            selection_order = prefix_selection_order(shrink_pass.last_prefix)\n\n        try:\n            shrink_pass.last_prefix = tree.step(\n                selection_order,\n                lambda chooser: shrink_pass.function(chooser),\n            )\n        finally:\n            shrink_pass.calls += self.calls - initial_calls\n            shrink_pass.misaligned += self.misaligned - initial_misaligned\n            shrink_pass.shrinks += self.shrinks - initial_shrinks\n            shrink_pass.deletions += size - len(self.shrink_target.choices)\n            self.engine.clear_call_explanation()\n        return True\n\n    def fixate_shrink_passes(self, passes: list[ShrinkPass]) -> None:\n        \"\"\"Run steps from each pass in ``passes`` until the current shrink target\n        is a fixed point of all of them.\"\"\"\n        any_ran = True\n        while any_ran:\n            any_ran = False\n\n            reordering = {}\n\n            # We run remove_discarded after every pass to do cleanup\n            # keeping track of whether that actually works. Either there is\n            # no discarded data and it is basically free, or it reliably works\n            # and deletes data, or it doesn't work. In that latter case we turn\n            # it off for the rest of this loop through the passes, but will\n            # try again once all of the passes have been run.\n            can_discard = self.remove_discarded()\n\n            calls_at_loop_start = self.calls\n\n            # We keep track of how many calls can be made by a single step\n            # without making progress and use this to test how much to pad\n            # out self.max_stall by as we go along.\n            max_calls_per_failing_step = 1\n\n            for sp in passes:\n                if can_discard:\n                    can_discard = self.remove_discarded()\n\n                before_sp = self.shrink_target\n\n                # Run the shrink pass until it fails to make any progress\n                # max_failures times in a row. This implicitly boosts shrink\n                # passes that are more likely to work.\n                failures = 0\n                max_failures = 20\n                while failures < max_failures:\n                    # We don't allow more than max_stall consecutive failures\n                    # to shrink, but this means that if we're unlucky and the\n                    # shrink passes are in a bad order where only the ones at\n                    # the end are useful, if we're not careful this heuristic\n                    # might stop us before we've tried everything. In order to\n                    # avoid that happening, we make sure that there's always\n                    # plenty of breathing room to make it through a single\n                    # iteration of the fixate_shrink_passes loop.\n                    self.max_stall = max(\n                        self.max_stall,\n                        2 * max_calls_per_failing_step\n                        + (self.calls - calls_at_loop_start),\n                    )\n\n                    prev = self.shrink_target\n                    initial_calls = self.calls\n                    # It's better for us to run shrink passes in a deterministic\n                    # order, to avoid repeat work, but this can cause us to create\n                    # long stalls when there are a lot of steps which fail to do\n                    # anything useful. In order to avoid this, once we've noticed\n                    # we're in a stall (i.e. half of max_failures calls have failed\n                    # to do anything) we switch to randomly jumping around. If we\n                    # find a success then we'll resume deterministic order from\n                    # there which, with any luck, is in a new good region.\n                    if not self.step(sp, random_order=failures >= max_failures // 2):\n                        # step returns False when there is nothing to do because\n                        # the entire choice tree is exhausted. If this happens\n                        # we break because we literally can't run this pass any\n                        # more than we already have until something else makes\n                        # progress.\n                        break\n                    any_ran = True\n\n                    # Don't count steps that didn't actually try to do\n                    # anything as failures. Otherwise, this call is a failure\n                    # if it failed to make any changes to the shrink target.\n                    if initial_calls != self.calls:\n                        if prev is not self.shrink_target:\n                            failures = 0\n                        else:\n                            max_calls_per_failing_step = max(\n                                max_calls_per_failing_step, self.calls - initial_calls\n                            )\n                            failures += 1\n\n                # We reorder the shrink passes so that on our next run through\n                # we try good ones first. The rule is that shrink passes that\n                # did nothing useful are the worst, shrink passes that reduced\n                # the length are the best.\n                if self.shrink_target is before_sp:\n                    reordering[sp] = 1\n                elif len(self.choices) < len(before_sp.choices):\n                    reordering[sp] = -1\n                else:\n                    reordering[sp] = 0\n\n            passes.sort(key=reordering.__getitem__)\n\n    @property\n    def nodes(self) -> tuple[ChoiceNode, ...]:\n        return self.shrink_target.nodes\n\n    @property\n    def choices(self) -> tuple[ChoiceT, ...]:\n        return self.shrink_target.choices\n\n    @property\n    def spans(self) -> Spans:\n        return self.shrink_target.spans\n\n    @derived_value  # type: ignore\n    def spans_by_label(self):\n        \"\"\"\n        A mapping of labels to a list of spans with that label. Spans in the list\n        are ordered by their normal index order.\n        \"\"\"\n\n        spans_by_label = defaultdict(list)\n        for ex in self.spans:\n            spans_by_label[ex.label].append(ex)\n        return dict(spans_by_label)\n\n    @derived_value  # type: ignore\n    def distinct_labels(self):\n        return sorted(self.spans_by_label, key=str)\n\n    def pass_to_descendant(self, chooser):\n        \"\"\"Attempt to replace each span with a descendant span.\n\n        This is designed to deal with strategies that call themselves\n        recursively. For example, suppose we had:\n\n        binary_tree = st.deferred(\n            lambda: st.one_of(\n                st.integers(), st.tuples(binary_tree, binary_tree)))\n\n        This pass guarantees that we can replace any binary tree with one of\n        its subtrees - each of those will create an interval that the parent\n        could validly be replaced with, and this pass will try doing that.\n\n        This is pretty expensive - it takes O(len(intervals)^2) - so we run it\n        late in the process when we've got the number of intervals as far down\n        as possible.\n        \"\"\"\n\n        label = chooser.choose(\n            self.distinct_labels, lambda l: len(self.spans_by_label[l]) >= 2\n        )\n\n        spans = self.spans_by_label[label]\n        i = chooser.choose(range(len(spans) - 1))\n        ancestor = spans[i]\n\n        if i + 1 == len(spans) or spans[i + 1].start >= ancestor.end:\n            return\n\n        @self.cached(label, i)\n        def descendants():\n            lo = i + 1\n            hi = len(spans)\n            while lo + 1 < hi:\n                mid = (lo + hi) // 2\n                if spans[mid].start >= ancestor.end:\n                    hi = mid\n                else:\n                    lo = mid\n            return [\n                span\n                for span in spans[i + 1 : hi]\n                if span.choice_count < ancestor.choice_count\n            ]\n\n        descendant = chooser.choose(descendants, lambda ex: ex.choice_count > 0)\n\n        assert ancestor.start <= descendant.start\n        assert ancestor.end >= descendant.end\n        assert descendant.choice_count < ancestor.choice_count\n\n        self.consider_new_nodes(\n            self.nodes[: ancestor.start]\n            + self.nodes[descendant.start : descendant.end]\n            + self.nodes[ancestor.end :]\n        )\n\n    def lower_common_node_offset(self):\n        \"\"\"Sometimes we find ourselves in a situation where changes to one part\n        of the choice sequence unlock changes to other parts. Sometimes this is\n        good, but sometimes this can cause us to exhibit exponential slow\n        downs!\n\n        e.g. suppose we had the following:\n\n        m = draw(integers(min_value=0))\n        n = draw(integers(min_value=0))\n        assert abs(m - n) > 1\n\n        If this fails then we'll end up with a loop where on each iteration we\n        reduce each of m and n by 2 - m can't go lower because of n, then n\n        can't go lower because of m.\n\n        This will take us O(m) iterations to complete, which is exponential in\n        the data size, as we gradually zig zag our way towards zero.\n\n        This can only happen if we're failing to reduce the size of the choice\n        sequence: The number of iterations that reduce the length of the choice\n        sequence is bounded by that length.\n\n        So what we do is this: We keep track of which nodes are changing, and\n        then if there's some non-zero common offset to them we try and minimize\n        them all at once by lowering that offset.\n\n        This may not work, and it definitely won't get us out of all possible\n        exponential slow downs (an example of where it doesn't is where the\n        shape of the nodes changes as a result of this bouncing behaviour),\n        but it fails fast when it doesn't work and gets us out of a really\n        nastily slow case when it does.\n        \"\"\"\n        if len(self.__changed_nodes) <= 1:\n            return\n\n        changed = []\n        for i in sorted(self.__changed_nodes):\n            node = self.nodes[i]\n            if node.trivial or node.type != \"integer\":\n                continue\n            changed.append(node)\n\n        if not changed:\n            return\n\n        ints = [\n            abs(node.value - node.constraints[\"shrink_towards\"]) for node in changed\n        ]\n        offset = min(ints)\n        assert offset > 0\n\n        for i in range(len(ints)):\n            ints[i] -= offset\n\n        st = self.shrink_target\n\n        def offset_node(node, n):\n            return (\n                node.index,\n                node.index + 1,\n                [node.copy(with_value=node.constraints[\"shrink_towards\"] + n)],\n            )\n\n        def consider(n, sign):\n            return self.consider_new_nodes(\n                replace_all(\n                    st.nodes,\n                    [\n                        offset_node(node, sign * (n + v))\n                        for node, v in zip(changed, ints, strict=False)\n                    ],\n                )\n            )\n\n        # shrink from both sides\n        Integer.shrink(offset, lambda n: consider(n, 1))\n        Integer.shrink(offset, lambda n: consider(n, -1))\n        self.clear_change_tracking()\n\n    def clear_change_tracking(self):\n        self.__last_checked_changed_at = self.shrink_target\n        self.__all_changed_nodes = set()\n\n    def mark_changed(self, i):\n        self.__changed_nodes.add(i)\n\n    @property\n    def __changed_nodes(self) -> set[int]:\n        if self.__last_checked_changed_at is self.shrink_target:\n            return self.__all_changed_nodes\n\n        prev_target = self.__last_checked_changed_at\n        new_target = self.shrink_target\n        assert prev_target is not new_target\n        prev_nodes = prev_target.nodes\n        new_nodes = new_target.nodes\n        assert sort_key(new_target.nodes) < sort_key(prev_target.nodes)\n\n        if len(prev_nodes) != len(new_nodes) or any(\n            n1.type != n2.type for n1, n2 in zip(prev_nodes, new_nodes, strict=True)\n        ):\n            # should we check constraints are equal as well?\n            self.__all_changed_nodes = set()\n        else:\n            assert len(prev_nodes) == len(new_nodes)\n            for i, (n1, n2) in enumerate(zip(prev_nodes, new_nodes, strict=True)):\n                assert n1.type == n2.type\n                if not choice_equal(n1.value, n2.value):\n                    self.__all_changed_nodes.add(i)\n\n        return self.__all_changed_nodes\n\n    def update_shrink_target(self, new_target):\n        assert isinstance(new_target, ConjectureResult)\n        self.shrinks += 1\n        # If we are just taking a long time to shrink we don't want to\n        # trigger this heuristic, so whenever we shrink successfully\n        # we give ourselves a bit of breathing room to make sure we\n        # would find a shrink that took that long to find the next time.\n        # The case where we're taking a long time but making steady\n        # progress is handled by `finish_shrinking_deadline` in engine.py\n        self.max_stall = max(\n            self.max_stall, (self.calls - self.calls_at_last_shrink) * 2\n        )\n        self.calls_at_last_shrink = self.calls\n        self.shrink_target = new_target\n        self.__derived_values = {}\n\n    def try_shrinking_nodes(self, nodes, n):\n        \"\"\"Attempts to replace each node in the nodes list with n. Returns\n        True if it succeeded (which may include some additional modifications\n        to shrink_target).\n\n        In current usage it is expected that each of the nodes currently have\n        the same value and choice_type, although this is not essential. Note that\n        n must be < the node at min(nodes) or this is not a valid shrink.\n\n        This method will attempt to do some small amount of work to delete data\n        that occurs after the end of the nodes. This is useful for cases where\n        there is some size dependency on the value of a node.\n        \"\"\"\n        # If the length of the shrink target has changed from under us such that\n        # the indices are out of bounds, give up on the replacement.\n        # TODO_BETTER_SHRINK: we probably want to narrow down the root cause here at some point.\n        if any(node.index >= len(self.nodes) for node in nodes):\n            return  # pragma: no cover\n\n        initial_attempt = replace_all(\n            self.nodes,\n            [(node.index, node.index + 1, [node.copy(with_value=n)]) for node in nodes],\n        )\n\n        attempt = self.cached_test_function(initial_attempt)[1]\n\n        if attempt is None:\n            return False\n\n        if attempt is self.shrink_target:\n            # if the initial shrink was a success, try lowering offsets.\n            self.lower_common_node_offset()\n            return True\n\n        # If this produced something completely invalid we ditch it\n        # here rather than trying to persevere.\n        if attempt.status is Status.OVERRUN:\n            return False\n\n        if attempt.status is Status.INVALID:\n            return False\n\n        if attempt.misaligned_at is not None:\n            # we're invalid due to a misalignment in the tree. We'll try to fix\n            # a very specific type of misalignment here: where we have a node of\n            # {\"size\": n} and tried to draw the same node, but with {\"size\": m < n}.\n            # This can occur with eg\n            #\n            #   n = data.draw_integer()\n            #   s = data.draw_string(min_size=n)\n            #\n            # where we try lowering n, resulting in the test_function drawing a lower\n            # min_size than our attempt had for the draw_string node.\n            #\n            # We'll now try realigning this tree by:\n            # * replacing the constraints in our attempt with what test_function tried\n            #   to draw in practice\n            # * truncating the value of that node to match min_size\n            #\n            # This helps in the specific case of drawing a value and then drawing\n            # a collection of that size...and not much else. In practice this\n            # helps because this antipattern is fairly common.\n\n            # TODO we'll probably want to apply the same trick as in the valid\n            # case of this function of preserving from the right instead of\n            # preserving from the left. see test_can_shrink_variable_string_draws.\n\n            index, attempt_choice_type, attempt_constraints, _attempt_forced = (\n                attempt.misaligned_at\n            )\n            node = self.nodes[index]\n            if node.type != attempt_choice_type:\n                return False  # pragma: no cover\n            if node.was_forced:\n                return False  # pragma: no cover\n\n            if node.type in {\"string\", \"bytes\"}:\n                # if the size *increased*, we would have to guess what to pad with\n                # in order to try fixing up this attempt. Just give up.\n                if node.constraints[\"min_size\"] <= attempt_constraints[\"min_size\"]:\n                    # attempts which increase min_size tend to overrun rather than\n                    # be misaligned, making a covering case difficult.\n                    return False  # pragma: no cover\n                # the size decreased in our attempt. Try again, but truncate the value\n                # to that size by removing any elements past min_size.\n                return self.consider_new_nodes(\n                    initial_attempt[: node.index]\n                    + [\n                        initial_attempt[node.index].copy(\n                            with_constraints=attempt_constraints,\n                            with_value=initial_attempt[node.index].value[\n                                : attempt_constraints[\"min_size\"]\n                            ],\n                        )\n                    ]\n                    + initial_attempt[node.index :]\n                )\n\n        lost_nodes = len(self.nodes) - len(attempt.nodes)\n        if lost_nodes <= 0:\n            return False\n\n        start = nodes[0].index\n        end = nodes[-1].index + 1\n        # We now look for contiguous regions to delete that might help fix up\n        # this failed shrink. We only look for contiguous regions of the right\n        # lengths because doing anything more than that starts to get very\n        # expensive. See minimize_individual_choices for where we\n        # try to be more aggressive.\n        regions_to_delete = {(end, end + lost_nodes)}\n\n        for ex in self.spans:\n            if ex.start > start:\n                continue\n            if ex.end <= end:\n                continue\n\n            if ex.index >= len(attempt.spans):\n                continue  # pragma: no cover\n\n            replacement = attempt.spans[ex.index]\n            in_original = [c for c in ex.children if c.start >= end]\n            in_replaced = [c for c in replacement.children if c.start >= end]\n\n            if len(in_replaced) >= len(in_original) or not in_replaced:\n                continue\n\n            # We've found a span where some of the children went missing\n            # as a result of this change, and just replacing it with the data\n            # it would have had and removing the spillover didn't work. This\n            # means that some of its children towards the right must be\n            # important, so we try to arrange it so that it retains its\n            # rightmost children instead of its leftmost.\n            regions_to_delete.add(\n                (in_original[0].start, in_original[-len(in_replaced)].start)\n            )\n\n        for u, v in sorted(regions_to_delete, key=lambda x: x[1] - x[0], reverse=True):\n            try_with_deleted = initial_attempt[:u] + initial_attempt[v:]\n            if self.consider_new_nodes(try_with_deleted):\n                return True\n\n        return False\n\n    def remove_discarded(self):\n        \"\"\"Try removing all bytes marked as discarded.\n\n        This is primarily to deal with data that has been ignored while\n        doing rejection sampling - e.g. as a result of an integer range, or a\n        filtered strategy.\n\n        Such data will also be handled by the adaptive_example_deletion pass,\n        but that pass is necessarily more conservative and will try deleting\n        each interval individually. The common case is that all data drawn and\n        rejected can just be thrown away immediately in one block, so this pass\n        will be much faster than trying each one individually when it works.\n\n        returns False if there is discarded data and removing it does not work,\n        otherwise returns True.\n        \"\"\"\n        while self.shrink_target.has_discards:\n            discarded = []\n\n            for ex in self.shrink_target.spans:\n                if (\n                    ex.choice_count > 0\n                    and ex.discarded\n                    and (not discarded or ex.start >= discarded[-1][-1])\n                ):\n                    discarded.append((ex.start, ex.end))\n\n            # This can happen if we have discards but they are all of\n            # zero length. This shouldn't happen very often so it's\n            # faster to check for it here than at the point of example\n            # generation.\n            if not discarded:\n                break\n\n            attempt = list(self.nodes)\n            for u, v in reversed(discarded):\n                del attempt[u:v]\n\n            if not self.consider_new_nodes(tuple(attempt)):\n                return False\n        return True\n\n    @derived_value  # type: ignore\n    def duplicated_nodes(self):\n        \"\"\"Returns a list of nodes grouped (choice_type, value).\"\"\"\n        duplicates = defaultdict(list)\n        for node in self.nodes:\n            duplicates[(node.type, choice_key(node.value))].append(node)\n        return list(duplicates.values())\n\n    def node_program(self, program: str) -> ShrinkPass:\n        return ShrinkPass(\n            lambda chooser: self._node_program(chooser, program),\n            name=f\"node_program_{program}\",\n        )\n\n    def _node_program(self, chooser, program):\n        n = len(program)\n        # Adaptively attempt to run the node program at the current\n        # index. If this successfully applies the node program ``k`` times\n        # then this runs in ``O(log(k))`` test function calls.\n        i = chooser.choose(range(len(self.nodes) - n + 1))\n\n        # First, run the node program at the chosen index. If this fails,\n        # don't do any extra work, so that failure is as cheap as possible.\n        if not self.run_node_program(i, program, original=self.shrink_target):\n            return\n\n        # Because we run in a random order we will often find ourselves in the middle\n        # of a region where we could run the node program. We thus start by moving\n        # left to the beginning of that region if possible in order to start from\n        # the beginning of that region.\n        def offset_left(k):\n            return i - k * n\n\n        i = offset_left(\n            find_integer(\n                lambda k: self.run_node_program(\n                    offset_left(k), program, original=self.shrink_target\n                )\n            )\n        )\n\n        original = self.shrink_target\n        # Now try to run the node program multiple times here.\n        find_integer(\n            lambda k: self.run_node_program(i, program, original=original, repeats=k)\n        )\n\n    def minimize_duplicated_choices(self, chooser):\n        \"\"\"Find choices that have been duplicated in multiple places and attempt\n        to minimize all of the duplicates simultaneously.\n\n        This lets us handle cases where two values can't be shrunk\n        independently of each other but can easily be shrunk together.\n        For example if we had something like:\n\n        ls = data.draw(lists(integers()))\n        y = data.draw(integers())\n        assert y not in ls\n\n        Suppose we drew y = 3 and after shrinking we have ls = [3]. If we were\n        to replace both 3s with 0, this would be a valid shrink, but if we were\n        to replace either 3 with 0 on its own the test would start passing.\n\n        It is also useful for when that duplication is accidental and the value\n        of the choices don't matter very much because it allows us to replace\n        more values at once.\n        \"\"\"\n        nodes = chooser.choose(self.duplicated_nodes)\n        # we can't lower any nodes which are trivial. try proceeding with the\n        # remaining nodes.\n        nodes = [node for node in nodes if not node.trivial]\n        if len(nodes) <= 1:\n            return\n\n        self.minimize_nodes(nodes)\n\n    def redistribute_numeric_pairs(self, chooser):\n        \"\"\"If there is a sum of generated numbers that we need their sum\n        to exceed some bound, lowering one of them requires raising the\n        other. This pass enables that.\"\"\"\n\n        # look for a pair of nodes (node1, node2) which are both numeric\n        # and aren't separated by too many other nodes. We'll decrease node1 and\n        # increase node2 (note that the other way around doesn't make sense as\n        # it's strictly worse in the ordering).\n        def can_choose_node(node):\n            # don't choose nan, inf, or floats above the threshold where f + 1 > f\n            # (which is not necessarily true for floats above MAX_PRECISE_INTEGER).\n            # The motivation for the last condition is to avoid trying weird\n            # non-shrinks where we raise one node and think we lowered another\n            # (but didn't).\n            return node.type in {\"integer\", \"float\"} and not (\n                node.type == \"float\"\n                and (math.isnan(node.value) or abs(node.value) >= MAX_PRECISE_INTEGER)\n            )\n\n        node1 = chooser.choose(\n            self.nodes,\n            lambda node: can_choose_node(node) and not node.trivial,\n        )\n        node2 = chooser.choose(\n            self.nodes,\n            lambda node: can_choose_node(node)\n            # Note that it's fine for node2 to be trivial, because we're going to\n            # explicitly make it *not* trivial by adding to its value.\n            and not node.was_forced\n            # to avoid quadratic behavior, scan ahead only a small amount for\n            # the related node.\n            and node1.index < node.index <= node1.index + 4,\n        )\n\n        m: int | float = node1.value\n        n: int | float = node2.value\n\n        def boost(k: int) -> bool:\n            # floats always shrink towards 0\n            shrink_towards = (\n                node1.constraints[\"shrink_towards\"] if node1.type == \"integer\" else 0\n            )\n            if k > abs(m - shrink_towards):\n                return False\n\n            # We are trying to move node1 (m) closer to shrink_towards, and node2\n            # (n) farther away from shrink_towards. If m is below shrink_towards,\n            # we want to add to m and subtract from n, and vice versa if above\n            # shrink_towards.\n            if m < shrink_towards:\n                k = -k\n\n            try:\n                v1 = m - k\n                v2 = n + k\n            except OverflowError:  # pragma: no cover\n                # if n or m is a float and k is over sys.float_info.max, coercing\n                # k to a float will overflow.\n                return False\n\n            # if we've increased node2 to the point that we're past max precision,\n            # give up - things have become too unstable.\n            if node1.type == \"float\" and abs(v2) >= MAX_PRECISE_INTEGER:\n                return False\n\n            return self.consider_new_nodes(\n                self.nodes[: node1.index]\n                + (node1.copy(with_value=v1),)\n                + self.nodes[node1.index + 1 : node2.index]\n                + (node2.copy(with_value=v2),)\n                + self.nodes[node2.index + 1 :]\n            )\n\n        find_integer(boost)\n\n    def lower_integers_together(self, chooser):\n        node1 = chooser.choose(\n            self.nodes, lambda n: n.type == \"integer\" and not n.trivial\n        )\n        # Search up to 3 nodes ahead, to avoid quadratic time.\n        node2 = self.nodes[\n            chooser.choose(\n                range(node1.index + 1, min(len(self.nodes), node1.index + 3 + 1)),\n                lambda i: self.nodes[i].type == \"integer\"\n                and not self.nodes[i].was_forced,\n            )\n        ]\n\n        # one might expect us to require node2 to be nontrivial, and to minimize\n        # the node which is closer to its shrink_towards, rather than node1\n        # unconditionally. In reality, it's acceptable for us to transition node2\n        # from trivial to nontrivial, because the shrink ordering is dominated by\n        # the complexity of the earlier node1. What matters is minimizing node1.\n        shrink_towards = node1.constraints[\"shrink_towards\"]\n\n        def consider(n):\n            return self.consider_new_nodes(\n                self.nodes[: node1.index]\n                + (node1.copy(with_value=node1.value - n),)\n                + self.nodes[node1.index + 1 : node2.index]\n                + (node2.copy(with_value=node2.value - n),)\n                + self.nodes[node2.index + 1 :]\n            )\n\n        find_integer(lambda n: consider(shrink_towards - n))\n        find_integer(lambda n: consider(n - shrink_towards))\n\n    def lower_duplicated_characters(self, chooser):\n        \"\"\"\n        Select two string choices no more than 4 choices apart and simultaneously\n        lower characters which appear in both strings. This helps cases where the\n        same character must appear in two strings, but the actual value of the\n        character is not relevant.\n\n        This shrinking pass currently only tries lowering *all* instances of the\n        duplicated character in both strings. So for instance, given two choices:\n\n            \"bbac\"\n            \"abbb\"\n\n        we would try lowering all five of the b characters simultaneously. This\n        may fail to shrink some cases where only certain character indices are\n        correlated, for instance if only the b at index 1 could be lowered\n        simultaneously and the rest did in fact actually have to be a `b`.\n\n        It would be nice to try shrinking that case as well, but we would need good\n        safeguards because it could get very expensive to try all combinations.\n        I expect lowering all duplicates to handle most cases in the meantime.\n        \"\"\"\n        node1 = chooser.choose(\n            self.nodes, lambda n: n.type == \"string\" and not n.trivial\n        )\n\n        # limit search to up to 4 choices ahead, to avoid quadratic behavior\n        node2 = self.nodes[\n            chooser.choose(\n                range(node1.index + 1, min(len(self.nodes), node1.index + 1 + 4)),\n                lambda i: self.nodes[i].type == \"string\" and not self.nodes[i].trivial\n                # select nodes which have at least one of the same character present\n                and set(node1.value) & set(self.nodes[i].value),\n            )\n        ]\n\n        duplicated_characters = set(node1.value) & set(node2.value)\n        # deterministic ordering\n        char = chooser.choose(sorted(duplicated_characters))\n        intervals = node1.constraints[\"intervals\"]\n\n        def copy_node(node, n):\n            # replace all duplicate characters in each string. This might miss\n            # some shrinks compared to only replacing some, but trying all possible\n            # combinations of indices could get expensive if done without some\n            # thought.\n            return node.copy(\n                with_value=node.value.replace(char, intervals.char_in_shrink_order(n))\n            )\n\n        Integer.shrink(\n            intervals.index_from_char_in_shrink_order(char),\n            lambda n: self.consider_new_nodes(\n                self.nodes[: node1.index]\n                + (copy_node(node1, n),)\n                + self.nodes[node1.index + 1 : node2.index]\n                + (copy_node(node2, n),)\n                + self.nodes[node2.index + 1 :]\n            ),\n        )\n\n    def minimize_nodes(self, nodes):\n        choice_type = nodes[0].type\n        value = nodes[0].value\n        # unlike choice_type and value, constraints are *not* guaranteed to be equal among all\n        # passed nodes. We arbitrarily use the constraints of the first node. I think\n        # this is unsound (= leads to us trying shrinks that could not have been\n        # generated), but those get discarded at test-time, and this enables useful\n        # slips where constraints are not equal but are close enough that doing the\n        # same operation on both basically just works.\n        constraints = nodes[0].constraints\n        assert all(\n            node.type == choice_type and choice_equal(node.value, value)\n            for node in nodes\n        )\n\n        if choice_type == \"integer\":\n            shrink_towards = constraints[\"shrink_towards\"]\n            # try shrinking from both sides towards shrink_towards.\n            # we're starting from n = abs(shrink_towards - value). Because the\n            # shrinker will not check its starting value, we need to try\n            # shrinking to n first.\n            self.try_shrinking_nodes(nodes, abs(shrink_towards - value))\n            Integer.shrink(\n                abs(shrink_towards - value),\n                lambda n: self.try_shrinking_nodes(nodes, shrink_towards + n),\n            )\n            Integer.shrink(\n                abs(shrink_towards - value),\n                lambda n: self.try_shrinking_nodes(nodes, shrink_towards - n),\n            )\n        elif choice_type == \"float\":\n            self.try_shrinking_nodes(nodes, abs(value))\n            Float.shrink(\n                abs(value),\n                lambda val: self.try_shrinking_nodes(nodes, val),\n            )\n            Float.shrink(\n                abs(value),\n                lambda val: self.try_shrinking_nodes(nodes, -val),\n            )\n        elif choice_type == \"boolean\":\n            # must be True, otherwise would be trivial and not selected.\n            assert value is True\n            # only one thing to try: false!\n            self.try_shrinking_nodes(nodes, False)\n        elif choice_type == \"bytes\":\n            Bytes.shrink(\n                value,\n                lambda val: self.try_shrinking_nodes(nodes, val),\n                min_size=constraints[\"min_size\"],\n            )\n        elif choice_type == \"string\":\n            String.shrink(\n                value,\n                lambda val: self.try_shrinking_nodes(nodes, val),\n                intervals=constraints[\"intervals\"],\n                min_size=constraints[\"min_size\"],\n            )\n        else:\n            raise NotImplementedError\n\n    def try_trivial_spans(self, chooser):\n        i = chooser.choose(range(len(self.spans)))\n\n        prev = self.shrink_target\n        nodes = self.shrink_target.nodes\n        span = self.spans[i]\n        prefix = nodes[: span.start]\n        replacement = tuple(\n            [\n                (\n                    node\n                    if node.was_forced\n                    else node.copy(\n                        with_value=choice_from_index(0, node.type, node.constraints)\n                    )\n                )\n                for node in nodes[span.start : span.end]\n            ]\n        )\n        suffix = nodes[span.end :]\n        attempt = self.cached_test_function(prefix + replacement + suffix)[1]\n\n        if self.shrink_target is not prev:\n            return\n\n        if isinstance(attempt, ConjectureResult):\n            new_span = attempt.spans[i]\n            new_replacement = attempt.nodes[new_span.start : new_span.end]\n            self.consider_new_nodes(prefix + new_replacement + suffix)\n\n    def minimize_individual_choices(self, chooser):\n        \"\"\"Attempt to minimize each choice in sequence.\n\n        This is the pass that ensures that e.g. each integer we draw is a\n        minimum value. So it's the part that guarantees that if we e.g. do\n\n        x = data.draw(integers())\n        assert x < 10\n\n        then in our shrunk example, x = 10 rather than say 97.\n\n        If we are unsuccessful at minimizing a choice of interest we then\n        check if that's because it's changing the size of the test case and,\n        if so, we also make an attempt to delete parts of the test case to\n        see if that fixes it.\n\n        We handle most of the common cases in try_shrinking_nodes which is\n        pretty good at clearing out large contiguous blocks of dead space,\n        but it fails when there is data that has to stay in particular places\n        in the list.\n        \"\"\"\n        node = chooser.choose(self.nodes, lambda node: not node.trivial)\n        initial_target = self.shrink_target\n\n        self.minimize_nodes([node])\n        if self.shrink_target is not initial_target:\n            # the shrink target changed, so our shrink worked. Defer doing\n            # anything more intelligent until this shrink fails.\n            return\n\n        # the shrink failed. One particularly common case where minimizing a\n        # node can fail is the antipattern of drawing a size and then drawing a\n        # collection of that size, or more generally when there is a size\n        # dependency on some single node. We'll explicitly try and fix up this\n        # common case here: if decreasing an integer node by one would reduce\n        # the size of the generated input, we'll try deleting things after that\n        # node and see if the resulting attempt works.\n\n        if node.type != \"integer\":\n            # Only try this fixup logic on integer draws. Almost all size\n            # dependencies are on integer draws, and if it's not, it's doing\n            # something convoluted enough that it is unlikely to shrink well anyway.\n            # TODO: extent to floats? we probably currently fail on the following,\n            # albeit convoluted example:\n            # n = int(data.draw(st.floats()))\n            # s = data.draw(st.lists(st.integers(), min_size=n, max_size=n))\n            return\n\n        lowered = (\n            self.nodes[: node.index]\n            + (node.copy(with_value=node.value - 1),)\n            + self.nodes[node.index + 1 :]\n        )\n        attempt = self.cached_test_function(lowered)[1]\n        if (\n            attempt is None\n            or attempt.status < Status.VALID\n            or len(attempt.nodes) == len(self.nodes)\n            or len(attempt.nodes) == node.index + 1\n        ):\n            # no point in trying our size-dependency-logic if our attempt at\n            # lowering the node resulted in:\n            # * an invalid conjecture data\n            # * the same number of nodes as before\n            # * no nodes beyond the lowered node (nothing to try to delete afterwards)\n            return\n\n        # If it were then the original shrink should have worked and we could\n        # never have got here.\n        assert attempt is not self.shrink_target\n\n        @self.cached(node.index)\n        def first_span_after_node():\n            lo = 0\n            hi = len(self.spans)\n            while lo + 1 < hi:\n                mid = (lo + hi) // 2\n                span = self.spans[mid]\n                if span.start >= node.index:\n                    hi = mid\n                else:\n                    lo = mid\n            return hi\n\n        # we try deleting both entire spans, and single nodes.\n        # If we wanted to get more aggressive, we could try deleting n\n        # consecutive nodes (that don't cross a span boundary) for say\n        # n <= 2 or n <= 3.\n        if chooser.choose([True, False]):\n            span = self.spans[\n                chooser.choose(\n                    range(first_span_after_node, len(self.spans)),\n                    lambda i: self.spans[i].choice_count > 0,\n                )\n            ]\n            self.consider_new_nodes(lowered[: span.start] + lowered[span.end :])\n        else:\n            node = self.nodes[chooser.choose(range(node.index + 1, len(self.nodes)))]\n            self.consider_new_nodes(lowered[: node.index] + lowered[node.index + 1 :])\n\n    def reorder_spans(self, chooser):\n        \"\"\"This pass allows us to reorder the children of each span.\n\n        For example, consider the following:\n\n        .. code-block:: python\n\n            import hypothesis.strategies as st\n            from hypothesis import given\n\n\n            @given(st.text(), st.text())\n            def test_not_equal(x, y):\n                assert x != y\n\n        Without the ability to reorder x and y this could fail either with\n        ``x=\"\"``, ``y=\"0\"``, or the other way around. With reordering it will\n        reliably fail with ``x=\"\"``, ``y=\"0\"``.\n        \"\"\"\n        span = chooser.choose(self.spans)\n\n        label = chooser.choose(span.children).label\n        spans = [c for c in span.children if c.label == label]\n        if len(spans) <= 1:\n            return\n\n        endpoints = [(span.start, span.end) for span in spans]\n        st = self.shrink_target\n\n        Ordering.shrink(\n            range(len(spans)),\n            lambda indices: self.consider_new_nodes(\n                replace_all(\n                    st.nodes,\n                    [\n                        (\n                            u,\n                            v,\n                            st.nodes[spans[i].start : spans[i].end],\n                        )\n                        for (u, v), i in zip(endpoints, indices, strict=True)\n                    ],\n                )\n            ),\n            key=lambda i: sort_key(st.nodes[spans[i].start : spans[i].end]),\n        )\n\n    def run_node_program(self, i, program, original, repeats=1):\n        \"\"\"Node programs are a mini-DSL for node rewriting, defined as a sequence\n        of commands that can be run at some index into the nodes\n\n        Commands are:\n\n            * \"X\", delete this node\n\n        This method runs the node program in ``program`` at node index\n        ``i`` on the ConjectureData ``original``. If ``repeats > 1`` then it\n        will attempt to approximate the results of running it that many times.\n\n        Returns True if this successfully changes the underlying shrink target,\n        else False.\n        \"\"\"\n        if i + len(program) > len(original.nodes) or i < 0:\n            return False\n        attempt = list(original.nodes)\n        for _ in range(repeats):\n            for k, command in reversed(list(enumerate(program))):\n                j = i + k\n                if j >= len(attempt):\n                    return False\n\n                if command == \"X\":\n                    del attempt[j]\n                else:\n                    raise NotImplementedError(f\"Unrecognised command {command!r}\")\n\n        return self.consider_new_nodes(attempt)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/shrinking/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.internal.conjecture.shrinking.bytes import Bytes\nfrom hypothesis.internal.conjecture.shrinking.collection import Collection\nfrom hypothesis.internal.conjecture.shrinking.floats import Float\nfrom hypothesis.internal.conjecture.shrinking.integer import Integer\nfrom hypothesis.internal.conjecture.shrinking.ordering import Ordering\nfrom hypothesis.internal.conjecture.shrinking.string import String\n\n__all__ = [\"Bytes\", \"Collection\", \"Float\", \"Integer\", \"Ordering\", \"String\"]\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/shrinking/bytes.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.internal.conjecture.shrinking.collection import Collection\nfrom hypothesis.internal.conjecture.shrinking.integer import Integer\n\n\nclass Bytes(Collection):\n    def __init__(self, initial, predicate, **kwargs):\n        super().__init__(\n            # implicit conversion from bytes to list of integers here\n            list(initial),\n            lambda val: predicate(bytes(val)),\n            ElementShrinker=Integer,\n            **kwargs,\n        )\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/shrinking/choicetree.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections import defaultdict\nfrom collections.abc import Callable, Iterable, Sequence\nfrom random import Random\n\nfrom hypothesis.internal.conjecture.junkdrawer import LazySequenceCopy\n\n\ndef prefix_selection_order(\n    prefix: Sequence[int],\n) -> Callable[[int, int], Iterable[int]]:\n    \"\"\"Select choices starting from ``prefix```,\n    preferring to move left then wrapping around\n    to the right.\"\"\"\n\n    def selection_order(depth: int, n: int) -> Iterable[int]:\n        if depth < len(prefix):\n            i = prefix[depth]\n            if i >= n:\n                i = n - 1\n            yield from range(i, -1, -1)\n            yield from range(n - 1, i, -1)\n        else:\n            yield from range(n - 1, -1, -1)\n\n    return selection_order\n\n\ndef random_selection_order(random: Random) -> Callable[[int, int], Iterable[int]]:\n    \"\"\"Select choices uniformly at random.\"\"\"\n\n    def selection_order(depth: int, n: int) -> Iterable[int]:\n        pending = LazySequenceCopy(range(n))\n        while pending:\n            i = random.randrange(0, len(pending))\n            yield pending.pop(i)\n\n    return selection_order\n\n\nclass Chooser:\n    \"\"\"A source of nondeterminism for use in shrink passes.\"\"\"\n\n    def __init__(\n        self,\n        tree: \"ChoiceTree\",\n        selection_order: Callable[[int, int], Iterable[int]],\n    ):\n        self.__selection_order = selection_order\n        self.__node_trail = [tree.root]\n        self.__choices: list[int] = []\n        self.__finished = False\n\n    def choose(\n        self,\n        values: Sequence[int],\n        condition: Callable[[int], bool] = lambda x: True,\n    ) -> int:\n        \"\"\"Return some element of values satisfying the condition\n        that will not lead to an exhausted branch, or raise DeadBranch\n        if no such element exist\".\n        \"\"\"\n        assert not self.__finished\n        node = self.__node_trail[-1]\n        if node.live_child_count is None:\n            node.live_child_count = len(values)\n            node.n = len(values)\n\n        assert node.live_child_count > 0 or len(values) == 0\n\n        for i in self.__selection_order(len(self.__choices), len(values)):\n            if node.live_child_count == 0:\n                break\n            if not node.children[i].exhausted:\n                v = values[i]\n                if condition(v):\n                    self.__choices.append(i)\n                    self.__node_trail.append(node.children[i])\n                    return v\n                else:\n                    node.children[i] = DeadNode\n                    node.live_child_count -= 1\n        assert node.live_child_count == 0\n        raise DeadBranch\n\n    def finish(self) -> Sequence[int]:\n        \"\"\"Record the decisions made in the underlying tree and return\n        a prefix that can be used for the next Chooser to be used.\"\"\"\n        self.__finished = True\n        assert len(self.__node_trail) == len(self.__choices) + 1\n\n        result = tuple(self.__choices)\n\n        self.__node_trail[-1].live_child_count = 0\n        while len(self.__node_trail) > 1 and self.__node_trail[-1].exhausted:\n            self.__node_trail.pop()\n            assert len(self.__node_trail) == len(self.__choices)\n            i = self.__choices.pop()\n            target = self.__node_trail[-1]\n            target.children[i] = DeadNode\n            assert target.live_child_count is not None\n            target.live_child_count -= 1\n\n        return result\n\n\nclass ChoiceTree:\n    \"\"\"Records sequences of choices made during shrinking so that we\n    can track what parts of a pass has run. Used to create Chooser\n    objects that are the main interface that a pass uses to make\n    decisions about what to do.\n    \"\"\"\n\n    def __init__(self) -> None:\n        self.root = TreeNode()\n\n    @property\n    def exhausted(self) -> bool:\n        return self.root.exhausted\n\n    def step(\n        self,\n        selection_order: Callable[[int, int], Iterable[int]],\n        f: Callable[[Chooser], None],\n    ) -> Sequence[int]:\n        assert not self.exhausted\n\n        chooser = Chooser(self, selection_order)\n        try:\n            f(chooser)\n        except DeadBranch:\n            pass\n        return chooser.finish()\n\n\nclass TreeNode:\n    def __init__(self) -> None:\n        self.children: dict[int, TreeNode] = defaultdict(TreeNode)\n        self.live_child_count: int | None = None\n        self.n: int | None = None\n\n    @property\n    def exhausted(self) -> bool:\n        return self.live_child_count == 0\n\n\nDeadNode = TreeNode()\nDeadNode.live_child_count = 0\n\n\nclass DeadBranch(Exception):\n    pass\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/shrinking/collection.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections import Counter\n\nfrom hypothesis.internal.conjecture.shrinking.common import Shrinker\nfrom hypothesis.internal.conjecture.shrinking.ordering import Ordering\nfrom hypothesis.internal.conjecture.utils import identity\n\n\nclass Collection(Shrinker):\n    def setup(\n        self, *, ElementShrinker, min_size, to_order=identity, from_order=identity\n    ):\n        self.ElementShrinker = ElementShrinker\n        self.to_order = to_order\n        self.from_order = from_order\n        self.min_size = min_size\n\n    def make_immutable(self, value):\n        return tuple(value)\n\n    def short_circuit(self):\n        zero = self.from_order(0)\n        return self.consider([zero] * self.min_size)\n\n    def left_is_better(self, left, right):\n        if len(left) < len(right):\n            return True\n\n        # examine elements one by one from the left until an element differs.\n        for v1, v2 in zip(left, right, strict=False):\n            if self.to_order(v1) == self.to_order(v2):\n                continue\n            return self.to_order(v1) < self.to_order(v2)\n\n        # equal length and all values were equal by our ordering, so must be equal\n        # by our ordering.\n        assert list(map(self.to_order, left)) == list(map(self.to_order, right))\n        return False\n\n    def run_step(self):\n        # try all-zero first; we already considered all-zero-and-smallest in\n        # short_circuit.\n        zero = self.from_order(0)\n        self.consider([zero] * len(self.current))\n\n        # try deleting each element in turn, starting from the back\n        # TODO_BETTER_SHRINK: adaptively delete here by deleting larger chunks at once\n        # if early deletes succeed. use find_integer. turns O(n) into O(log(n))\n        for i in reversed(range(len(self.current))):\n            self.consider(self.current[:i] + self.current[i + 1 :])\n\n        # then try reordering\n        Ordering.shrink(self.current, self.consider, key=self.to_order)\n\n        # then try minimizing all duplicated elements together simultaneously. This\n        # helps in cases like https://github.com/HypothesisWorks/hypothesis/issues/4286\n        duplicated = {val for val, count in Counter(self.current).items() if count > 1}\n        for val in duplicated:\n            self.ElementShrinker.shrink(\n                self.to_order(val),\n                lambda v: self.consider(\n                    tuple(self.from_order(v) if x == val else x for x in self.current)\n                ),\n            )\n\n        # then try minimizing each element in turn\n        for i, val in enumerate(self.current):\n            self.ElementShrinker.shrink(\n                self.to_order(val),\n                lambda v: self.consider(\n                    self.current[:i] + (self.from_order(v),) + self.current[i + 1 :]\n                ),\n            )\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/shrinking/common.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"This module implements various useful common functions for shrinking tasks.\"\"\"\n\n\nclass Shrinker:\n    \"\"\"A Shrinker object manages a single value and a predicate it should\n    satisfy, and attempts to improve it in some direction, making it smaller\n    and simpler.\"\"\"\n\n    def __init__(\n        self,\n        initial,\n        predicate,\n        *,\n        full=False,\n        debug=False,\n        name=None,\n        **kwargs,\n    ):\n        self.setup(**kwargs)\n        self.current = self.make_immutable(initial)\n        self.initial = self.current\n        self.full = full\n        self.changes = 0\n        self.name = name\n\n        self.__predicate = predicate\n        self.__seen = {self.make_canonical(self.current)}\n        self.debugging_enabled = debug\n\n    @property\n    def calls(self) -> int:\n        return len(self.__seen)\n\n    def __repr__(self) -> str:\n        return \"{}({}initial={!r}, current={!r})\".format(\n            type(self).__name__,\n            \"\" if self.name is None else f\"{self.name!r}, \",\n            self.initial,\n            self.current,\n        )\n\n    def setup(self, **kwargs):\n        \"\"\"Runs initial setup code.\n\n        Convenience function for children that doesn't require messing\n        with the signature of init.\n        \"\"\"\n\n    def delegate(self, other_class, convert_to, convert_from, **kwargs):\n        \"\"\"Delegates shrinking to another shrinker class, by converting the\n        current value to and from it with provided functions.\"\"\"\n        self.call_shrinker(\n            other_class,\n            convert_to(self.current),\n            lambda v: self.consider(convert_from(v)),\n            **kwargs,\n        )\n\n    def call_shrinker(self, other_class, initial, predicate, **kwargs):\n        \"\"\"Calls another shrinker class, passing through the relevant context\n        variables.\n\n        Note we explicitly do not pass through full.\n        \"\"\"\n\n        return other_class.shrink(initial, predicate, **kwargs)\n\n    def debug(self, *args: object) -> None:\n        if self.debugging_enabled:\n            print(\"DEBUG\", self, *args)\n\n    @classmethod\n    def shrink(cls, initial, predicate, **kwargs):\n        \"\"\"Shrink the value ``initial`` subject to the constraint that it\n        satisfies ``predicate``.\n\n        Returns the shrunk value.\n        \"\"\"\n        shrinker = cls(initial, predicate, **kwargs)\n        shrinker.run()\n        return shrinker.current\n\n    def run(self):\n        \"\"\"Run for an appropriate number of steps to improve the current value.\n\n        If self.full is True, will run until no further improvements can\n        be found.\n        \"\"\"\n        if self.short_circuit():\n            return\n        if self.full:\n            prev = -1\n            while self.changes != prev:\n                prev = self.changes\n                self.run_step()\n        else:\n            self.run_step()\n        self.debug(\"COMPLETE\")\n\n    def consider(self, value):\n        \"\"\"Try using ``value`` as a possible candidate improvement.\n\n        Return True if self.current is canonically equal to value after the call, either because\n        the value was incorporated as an improvement or because it had that value already.\n        \"\"\"\n        value = self.make_immutable(value)\n        self.debug(f\"considering {value!r}\")\n        canonical = self.make_canonical(value)\n        if canonical == self.make_canonical(self.current):\n            return True\n        if canonical in self.__seen:\n            return False\n        self.__seen.add(canonical)\n        self.check_invariants(value)\n        if not self.left_is_better(value, self.current):\n            self.debug(f\"Rejected {value!r} as no better than {self.current=}\")\n            return False\n        if self.__predicate(value):\n            self.debug(f\"shrinking to {value!r}\")\n            self.changes += 1\n            self.current = value\n            return True\n        else:\n            self.debug(f\"Rejected {value!r} not satisfying predicate\")\n            return False\n\n    def make_canonical(self, value):\n        \"\"\"Convert immutable value into a canonical and hashable, but not necessarily equal,\n        representation of itself.\n\n        This representation is used only for tracking already-seen values, not passed to the\n        shrinker.\n\n        Defaults to just returning the (immutable) input value.\n        \"\"\"\n        return value\n\n    def make_immutable(self, value):\n        \"\"\"Convert value into an immutable representation of itself.\n\n        It is these immutable versions that the shrinker will work on.\n\n        Defaults to just returning the value.\n        \"\"\"\n        return value\n\n    def check_invariants(self, value):\n        \"\"\"Make appropriate assertions about the value to ensure that it is\n        valid for this shrinker.\n\n        Does nothing by default.\n        \"\"\"\n\n    def short_circuit(self):\n        \"\"\"Possibly attempt to do some shrinking.\n\n        If this returns True, the ``run`` method will terminate early\n        without doing any more work.\n        \"\"\"\n        return False\n\n    def left_is_better(self, left, right):\n        \"\"\"Returns True if the left is strictly simpler than the right\n        according to the standards of this shrinker.\"\"\"\n        raise NotImplementedError\n\n    def run_step(self):\n        \"\"\"Run a single step of the main shrink loop, attempting to improve the\n        current value.\"\"\"\n        raise NotImplementedError\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/shrinking/floats.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nimport sys\n\nfrom hypothesis.internal.conjecture.floats import float_to_lex\nfrom hypothesis.internal.conjecture.shrinking.common import Shrinker\nfrom hypothesis.internal.conjecture.shrinking.integer import Integer\nfrom hypothesis.internal.floats import MAX_PRECISE_INTEGER, float_to_int\n\n\nclass Float(Shrinker):\n    def setup(self):\n        self.debugging_enabled = True\n\n    def make_canonical(self, f):\n        if math.isnan(f):\n            # Distinguish different NaN bit patterns, while making each equal to itself.\n            # Wrap in tuple to avoid potential collision with (huge) finite floats.\n            return (\"nan\", float_to_int(f))\n        return f\n\n    def check_invariants(self, value):\n        # We only handle positive floats (including NaN) because we encode the sign\n        # separately anyway.\n        assert not (value < 0)\n\n    def left_is_better(self, left, right):\n        lex1 = float_to_lex(left)\n        lex2 = float_to_lex(right)\n        return lex1 < lex2\n\n    def short_circuit(self):\n        # We check for a bunch of standard \"large\" floats. If we're currently\n        # worse than them and the shrink downwards doesn't help, abort early\n        # because there's not much useful we can do here.\n\n        for g in [sys.float_info.max, math.inf, math.nan]:\n            self.consider(g)\n\n        # If we're stuck at a nasty float don't try to shrink it further.\n        if not math.isfinite(self.current):\n            return True\n\n    def run_step(self):\n        # above MAX_PRECISE_INTEGER, all floats are integers. Shrink like one.\n        # TODO_BETTER_SHRINK: at 2 * MAX_PRECISE_INTEGER, n - 1 == n - 2, and\n        # Integer.shrink will likely perform badly. We should have a specialized\n        # big-float shrinker, which mostly follows Integer.shrink but replaces\n        # n - 1 with next_down(n).\n        if self.current > MAX_PRECISE_INTEGER:\n            self.delegate(Integer, convert_to=int, convert_from=float)\n            return\n\n        # Finally we get to the important bit: Each of these is a small change\n        # to the floating point number that corresponds to a large change in\n        # the lexical representation. Trying these ensures that our floating\n        # point shrink can always move past these obstacles. In particular it\n        # ensures we can always move to integer boundaries and shrink past a\n        # change that would require shifting the exponent while not changing\n        # the float value much.\n\n        # First, try dropping precision bits by rounding the scaled value. We\n        # try values ordered from least-precise (integer) to more precise, ie.\n        # approximate lexicographical order. Once we find an acceptable shrink,\n        # self.consider discards the remaining attempts early and skips test\n        # invocation. The loop count sets max fractional bits to keep, and is a\n        # compromise between completeness and performance.\n\n        for p in range(10):\n            scaled = self.current * 2**p  # note: self.current may change in loop\n            for truncate in [math.floor, math.ceil]:\n                self.consider(truncate(scaled) / 2**p)\n\n        if self.consider(int(self.current)):\n            self.debug(\"Just an integer now\")\n            self.delegate(Integer, convert_to=int, convert_from=float)\n            return\n\n        # Now try to minimize the top part of the fraction as an integer. This\n        # basically splits the float as k + x with 0 <= x < 1 and minimizes\n        # k as an integer, but without the precision issues that would have.\n        m, n = self.current.as_integer_ratio()\n        i, r = divmod(m, n)\n        self.call_shrinker(Integer, i, lambda k: self.consider((k * n + r) / n))\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/shrinking/integer.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.internal.conjecture.junkdrawer import find_integer\nfrom hypothesis.internal.conjecture.shrinking.common import Shrinker\n\n\"\"\"\nThis module implements a shrinker for non-negative integers.\n\"\"\"\n\n\nclass Integer(Shrinker):\n    \"\"\"Attempts to find a smaller integer. Guaranteed things to try ``0``,\n\n    ``1``, ``initial - 1``, ``initial - 2``. Plenty of optimisations beyond\n    that but those are the guaranteed ones.\n    \"\"\"\n\n    def short_circuit(self):\n        for i in range(2):\n            if self.consider(i):\n                return True\n        self.mask_high_bits()\n        if self.size > 8:\n            # see if we can squeeze the integer into a single byte.\n            self.consider(self.current >> (self.size - 8))\n            self.consider(self.current & 0xFF)\n        return self.current == 2\n\n    def check_invariants(self, value):\n        assert value >= 0\n\n    def left_is_better(self, left, right):\n        return left < right\n\n    def run_step(self):\n        self.shift_right()\n        self.shrink_by_multiples(2)\n        self.shrink_by_multiples(1)\n\n    def shift_right(self):\n        base = self.current\n        find_integer(lambda k: k <= self.size and self.consider(base >> k))\n\n    def mask_high_bits(self):\n        base = self.current\n        n = base.bit_length()\n\n        @find_integer\n        def try_mask(k):\n            if k >= n:\n                return False\n            mask = (1 << (n - k)) - 1\n            return self.consider(mask & base)\n\n    @property\n    def size(self) -> int:\n        return self.current.bit_length()\n\n    def shrink_by_multiples(self, k):\n        base = self.current\n\n        @find_integer\n        def shrunk(n):\n            attempt = base - n * k\n            return attempt >= 0 and self.consider(attempt)\n\n        return shrunk > 0\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/shrinking/ordering.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.internal.conjecture.junkdrawer import find_integer\nfrom hypothesis.internal.conjecture.shrinking.common import Shrinker\nfrom hypothesis.internal.conjecture.utils import identity\n\n\nclass Ordering(Shrinker):\n    \"\"\"A shrinker that tries to make a sequence more sorted.\n\n    Will not change the length or the contents, only tries to reorder\n    the elements of the sequence.\n    \"\"\"\n\n    def setup(self, key=identity):\n        self.key = key\n\n    def make_immutable(self, value):\n        return tuple(value)\n\n    def short_circuit(self):\n        # If we can flat out sort the target then there's nothing more to do.\n        return self.consider(sorted(self.current, key=self.key))\n\n    def left_is_better(self, left, right):\n        return tuple(map(self.key, left)) < tuple(map(self.key, right))\n\n    def check_invariants(self, value):\n        assert len(value) == len(self.current)\n        assert sorted(value) == sorted(self.current)\n\n    def run_step(self):\n        self.sort_regions()\n        self.sort_regions_with_gaps()\n\n    def sort_regions(self):\n        \"\"\"Guarantees that for each i we have tried to swap index i with\n        index i + 1.\n\n        This uses an adaptive algorithm that works by sorting contiguous\n        regions starting from each element.\n        \"\"\"\n        i = 0\n        while i + 1 < len(self.current):\n            prefix = list(self.current[:i])\n            k = find_integer(\n                lambda k: i + k <= len(self.current)\n                and self.consider(\n                    prefix\n                    + sorted(self.current[i : i + k], key=self.key)\n                    + list(self.current[i + k :])\n                )\n            )\n            i += k\n\n    def sort_regions_with_gaps(self):\n        \"\"\"Guarantees that for each i we have tried to swap index i with\n        index i + 2.\n\n        This uses an adaptive algorithm that works by sorting contiguous\n        regions centered on each element, where that element is treated as\n        fixed and the elements around it are sorted..\n        \"\"\"\n        for i in range(1, len(self.current) - 1):\n            if self.current[i - 1] <= self.current[i] <= self.current[i + 1]:\n                # The `continue` line is optimised out of the bytecode on\n                # CPython >= 3.7 (https://bugs.python.org/issue2506) and on\n                # PyPy, and so coverage cannot tell that it has been taken.\n                continue  # pragma: no cover\n\n            def can_sort(a, b):\n                if a < 0 or b > len(self.current):\n                    return False\n                assert a <= i < b\n                split = i - a\n                values = sorted(self.current[a:i] + self.current[i + 1 : b])\n                return self.consider(\n                    list(self.current[:a])\n                    + values[:split]\n                    + [self.current[i]]\n                    + values[split:]\n                    + list(self.current[b:])\n                )\n\n            left = i\n            right = i + 1\n            right += find_integer(lambda k: can_sort(left, right + k))\n            find_integer(lambda k: can_sort(left - k, right))\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/shrinking/string.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.internal.conjecture.shrinking.collection import Collection\nfrom hypothesis.internal.conjecture.shrinking.integer import Integer\n\n\nclass String(Collection):\n    def __init__(self, initial, predicate, *, intervals, **kwargs):\n        super().__init__(\n            list(initial),\n            lambda val: predicate(\"\".join(val)),\n            to_order=intervals.index_from_char_in_shrink_order,\n            from_order=intervals.char_in_shrink_order,\n            ElementShrinker=Integer,\n            **kwargs,\n        )\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/conjecture/utils.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport enum\nimport hashlib\nimport heapq\nimport math\nimport sys\nfrom collections import OrderedDict, abc\nfrom collections.abc import Callable, Sequence\nfrom functools import lru_cache\nfrom types import FunctionType\nfrom typing import TYPE_CHECKING, TypeVar\n\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.compat import int_from_bytes\nfrom hypothesis.internal.floats import next_up\nfrom hypothesis.internal.lambda_sources import _function_key\n\nif TYPE_CHECKING:\n    from hypothesis.internal.conjecture.data import ConjectureData\n\n\nLABEL_MASK = 2**64 - 1\n\n\ndef calc_label_from_name(name: str) -> int:\n    hashed = hashlib.sha384(name.encode()).digest()\n    return int_from_bytes(hashed[:8])\n\n\ndef calc_label_from_callable(f: Callable) -> int:\n    if isinstance(f, FunctionType):\n        return calc_label_from_hash(_function_key(f, ignore_name=True))\n    elif isinstance(f, type):\n        return calc_label_from_cls(f)\n    else:\n        # probably an instance defining __call__\n        try:\n            return calc_label_from_hash(f)\n        except Exception:\n            # not hashable\n            return calc_label_from_cls(type(f))\n\n\ndef calc_label_from_cls(cls: type) -> int:\n    return calc_label_from_name(cls.__qualname__)\n\n\ndef calc_label_from_hash(obj: object) -> int:\n    return calc_label_from_name(str(hash(obj)))\n\n\ndef combine_labels(*labels: int) -> int:\n    label = 0\n    for l in labels:\n        label = (label << 1) & LABEL_MASK\n        label ^= l\n    return label\n\n\nSAMPLE_IN_SAMPLER_LABEL = calc_label_from_name(\"a sample() in Sampler\")\nONE_FROM_MANY_LABEL = calc_label_from_name(\"one more from many()\")\n\n\nT = TypeVar(\"T\")\n\n\ndef identity(v: T) -> T:\n    return v\n\n\ndef check_sample(\n    values: type[enum.Enum] | Sequence[T], strategy_name: str\n) -> Sequence[T]:\n    if \"numpy\" in sys.modules and isinstance(values, sys.modules[\"numpy\"].ndarray):\n        if values.ndim != 1:\n            raise InvalidArgument(\n                \"Only one-dimensional arrays are supported for sampling, \"\n                f\"and the given value has {values.ndim} dimensions (shape \"\n                f\"{values.shape}).  This array would give samples of array slices \"\n                \"instead of elements!  Use np.ravel(values) to convert \"\n                \"to a one-dimensional array, or tuple(values) if you \"\n                \"want to sample slices.\"\n            )\n    elif not isinstance(values, (OrderedDict, abc.Sequence, enum.EnumMeta)):\n        raise InvalidArgument(\n            f\"Cannot sample from {values!r} because it is not an ordered collection. \"\n            f\"Hypothesis goes to some length to ensure that the {strategy_name} \"\n            \"strategy has stable results between runs. To replay a saved \"\n            \"example, the sampled values must have the same iteration order \"\n            \"on every run - ruling out sets, dicts, etc due to hash \"\n            \"randomization. Most cases can simply use `sorted(values)`, but \"\n            \"mixed types or special values such as math.nan require careful \"\n            \"handling - and note that when simplifying an example, \"\n            \"Hypothesis treats earlier values as simpler.\"\n        )\n    if isinstance(values, range):\n        # Pyright is unhappy with every way I've tried to type-annotate this\n        # function, so fine, we'll just ignore the analysis error.\n        return values  # type: ignore\n    return tuple(values)\n\n\n@lru_cache(64)\ndef compute_sampler_table(weights: tuple[float, ...]) -> list[tuple[int, int, float]]:\n    n = len(weights)\n    table: list[list[int | float | None]] = [[i, None, None] for i in range(n)]\n    total = sum(weights)\n    num_type = type(total)\n\n    zero = num_type(0)  # type: ignore\n    one = num_type(1)  # type: ignore\n\n    small: list[int] = []\n    large: list[int] = []\n\n    probabilities = [w / total for w in weights]\n    scaled_probabilities: list[float] = []\n\n    for i, alternate_chance in enumerate(probabilities):\n        scaled = alternate_chance * n\n        scaled_probabilities.append(scaled)\n        if scaled == 1:\n            table[i][2] = zero\n        elif scaled < 1:\n            small.append(i)\n        else:\n            large.append(i)\n    heapq.heapify(small)\n    heapq.heapify(large)\n\n    while small and large:\n        lo = heapq.heappop(small)\n        hi = heapq.heappop(large)\n\n        assert lo != hi\n        assert scaled_probabilities[hi] > one\n        assert table[lo][1] is None\n        table[lo][1] = hi\n        table[lo][2] = one - scaled_probabilities[lo]\n        scaled_probabilities[hi] = (\n            scaled_probabilities[hi] + scaled_probabilities[lo]\n        ) - one\n\n        if scaled_probabilities[hi] < 1:\n            heapq.heappush(small, hi)\n        elif scaled_probabilities[hi] == 1:\n            table[hi][2] = zero\n        else:\n            heapq.heappush(large, hi)\n    while large:\n        table[large.pop()][2] = zero\n    while small:\n        table[small.pop()][2] = zero\n\n    new_table: list[tuple[int, int, float]] = []\n    for base, alternate, alternate_chance in table:\n        assert isinstance(base, int)\n        assert isinstance(alternate, int) or alternate is None\n        assert alternate_chance is not None\n        if alternate is None:\n            new_table.append((base, base, alternate_chance))\n        elif alternate < base:\n            new_table.append((alternate, base, one - alternate_chance))\n        else:\n            new_table.append((base, alternate, alternate_chance))\n    new_table.sort()\n    return new_table\n\n\nclass Sampler:\n    \"\"\"Sampler based on Vose's algorithm for the alias method. See\n    http://www.keithschwarz.com/darts-dice-coins/ for a good explanation.\n\n    The general idea is that we store a table of triples (base, alternate, p).\n    base. We then pick a triple uniformly at random, and choose its alternate\n    value with probability p and else choose its base value. The triples are\n    chosen so that the resulting mixture has the right distribution.\n\n    We maintain the following invariants to try to produce good shrinks:\n\n    1. The table is in lexicographic (base, alternate) order, so that choosing\n       an earlier value in the list always lowers (or at least leaves\n       unchanged) the value.\n    2. base[i] < alternate[i], so that shrinking the draw always results in\n       shrinking the chosen element.\n    \"\"\"\n\n    table: list[tuple[int, int, float]]  # (base_idx, alt_idx, alt_chance)\n\n    def __init__(self, weights: Sequence[float], *, observe: bool = True):\n        self.observe = observe\n        self.table = compute_sampler_table(tuple(weights))\n\n    def sample(\n        self,\n        data: \"ConjectureData\",\n        *,\n        forced: int | None = None,\n    ) -> int:\n        if self.observe:\n            data.start_span(SAMPLE_IN_SAMPLER_LABEL)\n        forced_choice = (  # pragma: no branch # https://github.com/nedbat/coveragepy/issues/1617\n            None\n            if forced is None\n            else next(\n                (base, alternate, alternate_chance)\n                for (base, alternate, alternate_chance) in self.table\n                if forced == base or (forced == alternate and alternate_chance > 0)\n            )\n        )\n        base, alternate, alternate_chance = data.choice(\n            self.table,\n            forced=forced_choice,\n            observe=self.observe,\n        )\n        forced_use_alternate = None\n        if forced is not None:\n            # we maintain this invariant when picking forced_choice above.\n            # This song and dance about alternate_chance > 0 is to avoid forcing\n            # e.g. draw_boolean(p=0, forced=True), which is an error.\n            forced_use_alternate = forced == alternate and alternate_chance > 0\n            assert forced == base or forced_use_alternate\n\n        use_alternate = data.draw_boolean(\n            alternate_chance,\n            forced=forced_use_alternate,\n            observe=self.observe,\n        )\n        if self.observe:\n            data.stop_span()\n        if use_alternate:\n            assert forced is None or alternate == forced, (forced, alternate)\n            return alternate\n        else:\n            assert forced is None or base == forced, (forced, base)\n            return base\n\n\nINT_SIZES = (8, 16, 32, 64, 128)\nINT_SIZES_SAMPLER = Sampler((4.0, 8.0, 1.0, 1.0, 0.5), observe=False)\n\n\nclass many:\n    \"\"\"Utility class for collections. Bundles up the logic we use for \"should I\n    keep drawing more values?\" and handles starting and stopping examples in\n    the right place.\n\n    Intended usage is something like:\n\n    elements = many(data, ...)\n    while elements.more():\n        add_stuff_to_result()\n    \"\"\"\n\n    def __init__(\n        self,\n        data: \"ConjectureData\",\n        min_size: int,\n        max_size: int | float,\n        average_size: int | float,\n        *,\n        forced: int | None = None,\n        observe: bool = True,\n    ) -> None:\n        assert 0 <= min_size <= average_size <= max_size\n        assert forced is None or min_size <= forced <= max_size\n        self.min_size = min_size\n        self.max_size = max_size\n        self.data = data\n        self.forced_size = forced\n        self.p_continue = _calc_p_continue(average_size - min_size, max_size - min_size)\n        self.count = 0\n        self.rejections = 0\n        self.drawn = False\n        self.force_stop = False\n        self.rejected = False\n        self.observe = observe\n\n    def stop_span(self):\n        if self.observe:\n            self.data.stop_span()\n\n    def start_span(self, label):\n        if self.observe:\n            self.data.start_span(label)\n\n    def more(self) -> bool:\n        \"\"\"Should I draw another element to add to the collection?\"\"\"\n        if self.drawn:\n            self.stop_span()\n\n        self.drawn = True\n        self.rejected = False\n\n        self.start_span(ONE_FROM_MANY_LABEL)\n        if self.min_size == self.max_size:\n            # if we have to hit an exact size, draw unconditionally until that\n            # point, and no further.\n            should_continue = self.count < self.min_size\n        else:\n            forced_result = None\n            if self.force_stop:\n                # if our size is forced, we can't reject in a way that would\n                # cause us to differ from the forced size.\n                assert self.forced_size is None or self.count == self.forced_size\n                forced_result = False\n            elif self.count < self.min_size:\n                forced_result = True\n            elif self.count >= self.max_size:\n                forced_result = False\n            elif self.forced_size is not None:\n                forced_result = self.count < self.forced_size\n            should_continue = self.data.draw_boolean(\n                self.p_continue,\n                forced=forced_result,\n                observe=self.observe,\n            )\n\n        if should_continue:\n            self.count += 1\n            return True\n        else:\n            self.stop_span()\n            return False\n\n    def reject(self, why: str | None = None) -> None:\n        \"\"\"Reject the last example (i.e. don't count it towards our budget of\n        elements because it's not going to go in the final collection).\"\"\"\n        assert self.count > 0\n        self.count -= 1\n        self.rejections += 1\n        self.rejected = True\n        # We set a minimum number of rejections before we give up to avoid\n        # failing too fast when we reject the first draw.\n        if self.rejections > max(3, 2 * self.count):\n            if self.count < self.min_size:\n                self.data.mark_invalid(why)\n            else:\n                self.force_stop = True\n\n\nSMALLEST_POSITIVE_FLOAT: float = next_up(0.0) or sys.float_info.min\n\n\n@lru_cache\ndef _calc_p_continue(desired_avg: float, max_size: int | float) -> float:\n    \"\"\"Return the p_continue which will generate the desired average size.\"\"\"\n    assert desired_avg <= max_size, (desired_avg, max_size)\n    if desired_avg == max_size:\n        return 1.0\n    p_continue = 1 - 1.0 / (1 + desired_avg)\n    if p_continue == 0 or max_size == math.inf:\n        assert 0 <= p_continue < 1, p_continue\n        return p_continue\n    assert 0 < p_continue < 1, p_continue\n    # For small max_size, the infinite-series p_continue is a poor approximation,\n    # and while we can't solve the polynomial a few rounds of iteration quickly\n    # gets us a good approximate solution in almost all cases (sometimes exact!).\n    while _p_continue_to_avg(p_continue, max_size) > desired_avg:\n        # This is impossible over the reals, but *can* happen with floats.\n        p_continue -= 0.0001\n        # If we've reached zero or gone negative, we want to break out of this loop,\n        # and do so even if we're on a system with the unsafe denormals-are-zero flag.\n        # We make that an explicit error in st.floats(), but here we'd prefer to\n        # just get somewhat worse precision on collection lengths.\n        if p_continue < SMALLEST_POSITIVE_FLOAT:\n            p_continue = SMALLEST_POSITIVE_FLOAT\n            break\n    # Let's binary-search our way to a better estimate!  We tried fancier options\n    # like gradient descent, but this is numerically stable and works better.\n    hi = 1.0\n    while desired_avg - _p_continue_to_avg(p_continue, max_size) > 0.01:\n        assert 0 < p_continue < hi, (p_continue, hi)\n        mid = (p_continue + hi) / 2\n        if _p_continue_to_avg(mid, max_size) <= desired_avg:\n            p_continue = mid\n        else:\n            hi = mid\n    assert 0 < p_continue < 1, p_continue\n    assert _p_continue_to_avg(p_continue, max_size) <= desired_avg\n    return p_continue\n\n\ndef _p_continue_to_avg(p_continue: float, max_size: int | float) -> float:\n    \"\"\"Return the average_size generated by this p_continue and max_size.\"\"\"\n    if p_continue >= 1:\n        return max_size\n    return (1.0 / (1 - p_continue) - 1) * (1 - p_continue**max_size)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/constants_ast.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport ast\nimport hashlib\nimport inspect\nimport math\nimport sys\nfrom ast import Constant, Expr, NodeVisitor, UnaryOp, USub\nfrom collections.abc import Iterator, MutableSet\nfrom functools import lru_cache\nfrom itertools import chain\nfrom pathlib import Path\nfrom types import ModuleType\nfrom typing import TypeAlias\n\nimport hypothesis\nfrom hypothesis.configuration import storage_directory\nfrom hypothesis.internal.conjecture.choice import ChoiceTypeT\nfrom hypothesis.internal.escalation import is_hypothesis_file\n\nConstantT: TypeAlias = int | float | bytes | str\n\n# unfortunate collision with builtin. I don't want to name the init arg bytes_.\nbytesT = bytes\n\n\nclass Constants:\n    def __init__(\n        self,\n        *,\n        integers: MutableSet[int] | None = None,\n        floats: MutableSet[float] | None = None,\n        bytes: MutableSet[bytes] | None = None,\n        strings: MutableSet[str] | None = None,\n    ):\n        self.integers: MutableSet[int] = set() if integers is None else integers\n        self.floats: MutableSet[float] = set() if floats is None else floats\n        self.bytes: MutableSet[bytesT] = set() if bytes is None else bytes\n        self.strings: MutableSet[str] = set() if strings is None else strings\n\n    def set_for_type(\n        self, constant_type: type[ConstantT] | ChoiceTypeT\n    ) -> MutableSet[int] | MutableSet[float] | MutableSet[bytes] | MutableSet[str]:\n        if constant_type is int or constant_type == \"integer\":\n            return self.integers\n        elif constant_type is float or constant_type == \"float\":\n            return self.floats\n        elif constant_type is bytes or constant_type == \"bytes\":\n            return self.bytes\n        elif constant_type is str or constant_type == \"string\":\n            return self.strings\n        raise ValueError(f\"unknown constant_type {constant_type}\")\n\n    def add(self, constant: ConstantT) -> None:\n        self.set_for_type(type(constant)).add(constant)  # type: ignore\n\n    def __contains__(self, constant: ConstantT) -> bool:\n        return constant in self.set_for_type(type(constant))\n\n    def __or__(self, other: \"Constants\") -> \"Constants\":\n        return Constants(\n            integers=self.integers | other.integers,  # type: ignore\n            floats=self.floats | other.floats,  # type: ignore\n            bytes=self.bytes | other.bytes,  # type: ignore\n            strings=self.strings | other.strings,  # type: ignore\n        )\n\n    def __iter__(self) -> Iterator[ConstantT]:\n        return iter(chain(self.integers, self.floats, self.bytes, self.strings))\n\n    def __len__(self) -> int:\n        return (\n            len(self.integers) + len(self.floats) + len(self.bytes) + len(self.strings)\n        )\n\n    def __repr__(self) -> str:\n        return f\"Constants({self.integers=}, {self.floats=}, {self.bytes=}, {self.strings=})\"\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, Constants):\n            return False\n        return (\n            self.integers == other.integers\n            and self.floats == other.floats\n            and self.bytes == other.bytes\n            and self.strings == other.strings\n        )\n\n\nclass TooManyConstants(Exception):\n    # a control flow exception which we raise in ConstantsVisitor when the\n    # number of constants in a module gets too large.\n    pass\n\n\nclass ConstantVisitor(NodeVisitor):\n    CONSTANTS_LIMIT: int = 1024\n\n    def __init__(self, *, limit: bool):\n        super().__init__()\n        self.constants = Constants()\n        self.limit = limit\n\n    def _add_constant(self, value: object) -> None:\n        if self.limit and len(self.constants) >= self.CONSTANTS_LIMIT:\n            raise TooManyConstants\n\n        if isinstance(value, str) and (\n            value.isspace()\n            or value == \"\"\n            # long strings are unlikely to be useful.\n            or len(value) > 20\n        ):\n            return\n        if isinstance(value, bytes) and (\n            value == b\"\"\n            # long bytes seem plausibly more likely to be useful than long strings\n            # (e.g. AES-256 has a 32 byte key), but we still want to cap at some\n            # point to avoid performance issues.\n            or len(value) > 50\n        ):\n            return\n        if isinstance(value, bool):\n            return\n        if isinstance(value, float) and math.isinf(value):\n            # we already upweight inf.\n            return\n        if isinstance(value, int) and -100 < value < 100:\n            # we already upweight small integers.\n            return\n\n        if isinstance(value, (int, float, bytes, str)):\n            self.constants.add(value)\n            return\n\n        # I don't kow what case could go here, but am also not confident there\n        # isn't one.\n        return  # pragma: no cover\n\n    def visit_UnaryOp(self, node: UnaryOp) -> None:\n        # `a = -1` is actually a combination of a USub and the constant 1.\n        if (\n            isinstance(node.op, USub)\n            and isinstance(node.operand, Constant)\n            and isinstance(node.operand.value, (int, float))\n            and not isinstance(node.operand.value, bool)\n        ):\n            self._add_constant(-node.operand.value)\n            # don't recurse on this node to avoid adding the positive variant\n            return\n\n        self.generic_visit(node)\n\n    def visit_Expr(self, node: Expr) -> None:\n        if isinstance(node.value, Constant) and isinstance(node.value.value, str):\n            return\n\n        self.generic_visit(node)\n\n    def visit_JoinedStr(self, node):\n        # dont recurse on JoinedStr, i.e. f strings. Constants that appear *only*\n        # in f strings are unlikely to be helpful.\n        return\n\n    def visit_Constant(self, node):\n        self._add_constant(node.value)\n        self.generic_visit(node)\n\n\ndef _constants_from_source(source: str | bytes, *, limit: bool) -> Constants:\n    tree = ast.parse(source)\n    visitor = ConstantVisitor(limit=limit)\n\n    try:\n        visitor.visit(tree)\n    except TooManyConstants:\n        # in the case of an incomplete collection, return nothing, to avoid\n        # muddying caches etc.\n        return Constants()\n\n    return visitor.constants\n\n\ndef _constants_file_str(constants: Constants) -> str:\n    return str(sorted(constants, key=lambda v: (str(type(v)), v)))\n\n\n@lru_cache(4096)\ndef constants_from_module(module: ModuleType, *, limit: bool = True) -> Constants:\n    try:\n        module_file = inspect.getsourcefile(module)\n        # use type: ignore because we know this might error\n        source_bytes = Path(module_file).read_bytes()  # type: ignore\n    except Exception:\n        return Constants()\n\n    if limit and len(source_bytes) > 512 * 1024:\n        # Skip files over 512kb. For reference, the largest source file\n        # in Hypothesis is strategies/_internal/core.py at 107kb at time\n        # of writing.\n        return Constants()\n\n    source_hash = hashlib.sha1(source_bytes).hexdigest()[:16]\n    # separate cache files for each limit param. see discussion in pull/4398\n    cache_p = storage_directory(\"constants\") / (\n        source_hash + (\"\" if limit else \"_nolimit\")\n    )\n    try:\n        return _constants_from_source(cache_p.read_bytes(), limit=limit)\n    except Exception:\n        # if the cached location doesn't exist, or it does exist but there was\n        # a problem reading it, fall back to standard computation of the constants\n        pass\n\n    try:\n        constants = _constants_from_source(source_bytes, limit=limit)\n    except Exception:\n        # A bunch of things can go wrong here.\n        # * ast.parse may fail on the source code\n        # * NodeVisitor may hit a RecursionError (see many related issues on\n        #   e.g. libcst https://github.com/Instagram/LibCST/issues?q=recursion),\n        #   or a MemoryError (`\"[1, \" * 200 + \"]\" * 200`)\n        return Constants()\n\n    try:\n        cache_p.parent.mkdir(parents=True, exist_ok=True)\n        cache_p.write_text(\n            f\"# file: {module_file}\\n# hypothesis_version: {hypothesis.__version__}\\n\\n\"\n            # somewhat arbitrary sort order. The cache file doesn't *have* to be\n            # stable... but it is aesthetically pleasing, and means we could rely\n            # on it in the future!\n            + _constants_file_str(constants),\n            encoding=\"utf-8\",\n        )\n    except Exception:  # pragma: no cover\n        pass\n\n    return constants\n\n\n@lru_cache(4096)\ndef is_local_module_file(path: str) -> bool:\n    from hypothesis.internal.scrutineer import ModuleLocation\n\n    return (\n        # Skip expensive path lookup for stdlib modules.\n        # This will cause false negatives if a user names their module the\n        # same as a stdlib module.\n        path not in sys.stdlib_module_names\n        # A path containing site-packages is extremely likely to be\n        # ModuleLocation.SITE_PACKAGES. Skip the expensive path lookup here.\n        and \"/site-packages/\" not in path\n        and ModuleLocation.from_path(path) is ModuleLocation.LOCAL\n        # normally, hypothesis is a third-party library and is not returned\n        # by local_modules. However, if it is installed as an editable package\n        # with pip install -e, then we will pick up on it. Just hardcode an\n        # ignore here.\n        and not is_hypothesis_file(path)\n        # avoid collecting constants from test files\n        and not (\n            \"test\" in (p := Path(path)).parts\n            or \"tests\" in p.parts\n            or p.stem.startswith(\"test_\")\n            or p.stem.endswith(\"_test\")\n        )\n    )\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/coverage.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport json\nimport os\nimport sys\nfrom collections.abc import Callable\nfrom contextlib import contextmanager\nfrom typing import TypeVar\n\nfrom hypothesis.internal.reflection import proxies\n\n\"\"\"\nThis module implements a custom coverage system that records conditions and\nthen validates that every condition has been seen to be both True and False\nduring the execution of our tests.\n\nThe only thing we use it for at present is our argument validation functions,\nwhere we assert that every validation function has been seen to both pass and\nfail in the course of testing.\n\nWhen not running with a magic environment variable set, this module disables\nitself and has essentially no overhead.\n\"\"\"\n\nFunc = TypeVar(\"Func\", bound=Callable)\npretty_file_name_cache: dict[str, str] = {}\n\n\ndef pretty_file_name(f):\n    try:\n        return pretty_file_name_cache[f]\n    except KeyError:\n        pass\n\n    parts = f.split(os.path.sep)\n    if \"hypothesis\" in parts:  # pragma: no branch\n        parts = parts[-parts[::-1].index(\"hypothesis\") :]\n    result = os.path.sep.join(parts)\n    pretty_file_name_cache[f] = result\n    return result\n\n\nIN_COVERAGE_TESTS = os.getenv(\"HYPOTHESIS_INTERNAL_COVERAGE\") == \"true\"\ndescription_stack = []\n\n\nif IN_COVERAGE_TESTS:\n    # By this point, \"branch-check\" should have already been deleted by the\n    # tox config. We can't delete it here because of #1718.\n\n    written: set[tuple[str, bool]] = set()\n\n    def record_branch(name, value):\n        key = (name, value)\n        if key in written:\n            return\n        written.add(key)\n        with open(f\"branch-check-{os.getpid()}\", mode=\"a\", encoding=\"utf-8\") as log:\n            log.write(json.dumps({\"name\": name, \"value\": value}) + \"\\n\")\n\n    @contextmanager\n    def check_block(name, depth):\n        # We add an extra two callers to the stack: One for the contextmanager\n        # function, one for our actual caller, so we want to go two extra\n        # stack frames up.\n        caller = sys._getframe(depth + 2)\n        fname = pretty_file_name(caller.f_code.co_filename)\n        local_description = f\"{name} at {fname}:{caller.f_lineno}\"\n        try:\n            description_stack.append(local_description)\n            description = \" in \".join(reversed(description_stack)) + \" passed\"\n            yield\n            record_branch(description, True)\n        except BaseException:\n            record_branch(description, False)\n            raise\n        finally:\n            description_stack.pop()\n\n    @contextmanager\n    def check(name):\n        with check_block(name, 2):\n            yield\n\n    def check_function(f: Func) -> Func:\n        @proxies(f)\n        def accept(*args, **kwargs):\n            # depth of 2 because of the proxy function calling us.\n            with check_block(f.__name__, 2):\n                return f(*args, **kwargs)\n\n        return accept\n\nelse:  # pragma: no cover\n\n    def check_function(f: Func) -> Func:\n        return f\n\n    @contextmanager\n    def check(name):\n        yield\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/detection.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom types import MethodType\n\n\ndef is_hypothesis_test(f: object) -> bool:\n    \"\"\"\n    Returns ``True`` if ``f`` represents a test function that has been defined\n    with Hypothesis. This is true for:\n\n    * Functions decorated with |@given|\n    * The ``runTest`` method of stateful tests\n\n    For example:\n\n    .. code-block:: python\n\n        @given(st.integers())\n        def f(n): ...\n\n        class MyStateMachine(RuleBasedStateMachine): ...\n\n        assert is_hypothesis_test(f)\n        assert is_hypothesis_test(MyStateMachine.TestCase().runTest)\n\n    .. seealso::\n\n        See also the :doc:`Detect Hypothesis tests\n        </how-to/detect-hypothesis-tests>` how-to.\n    \"\"\"\n    if isinstance(f, MethodType):\n        return is_hypothesis_test(f.__func__)\n    return getattr(f, \"is_hypothesis_test\", False)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/entropy.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport contextlib\nimport gc\nimport random\nimport sys\nimport warnings\nfrom collections.abc import Callable, Generator, Hashable\nfrom itertools import count\nfrom random import Random\nfrom typing import TYPE_CHECKING, Any\nfrom weakref import WeakValueDictionary\n\nimport hypothesis.core\nfrom hypothesis.errors import HypothesisWarning, InvalidArgument\nfrom hypothesis.internal.compat import FREE_THREADED_CPYTHON, GRAALPY, PYPY\n\nif TYPE_CHECKING:\n    from typing import Protocol\n\n    # we can't use this at runtime until from_type supports\n    # protocols -- breaks ghostwriter tests\n    class RandomLike(Protocol):\n        def seed(self, *args: Any, **kwargs: Any) -> Any: ...\n        def getstate(self, *args: Any, **kwargs: Any) -> Any: ...\n        def setstate(self, *args: Any, **kwargs: Any) -> Any: ...\n\nelse:  # pragma: no cover\n    RandomLike = random.Random\n\n_RKEY = count()\n_global_random_rkey = next(_RKEY)\n# This is effectively a WeakSet, which allows us to associate the saved states\n# with their respective Random instances even as new ones are registered and old\n# ones go out of scope and get garbage collected.  Keys are ascending integers.\nRANDOMS_TO_MANAGE: WeakValueDictionary[int, RandomLike] = WeakValueDictionary(\n    {_global_random_rkey: random}\n)\n\n\nclass NumpyRandomWrapper:\n    def __init__(self) -> None:\n        assert \"numpy\" in sys.modules\n        # This class provides a shim that matches the numpy to stdlib random,\n        # and lets us avoid importing Numpy until it's already in use.\n        import numpy.random\n\n        self.seed = numpy.random.seed\n        self.getstate = numpy.random.get_state\n        self.setstate = numpy.random.set_state\n\n\nNP_RANDOM: RandomLike | None = None\n\n\nif not (PYPY or GRAALPY):\n\n    def _get_platform_base_refcount(r: Any) -> int:\n        return sys.getrefcount(r)\n\n    # Determine the number of refcounts created by function scope for\n    # the given platform / version of Python.\n    _PLATFORM_REF_COUNT = _get_platform_base_refcount(object())\nelse:  # pragma: no cover\n    # PYPY and GRAALPY don't have `sys.getrefcount`\n    _PLATFORM_REF_COUNT = -1\n\n\ndef register_random(r: RandomLike) -> None:\n    \"\"\"Register (a weakref to) the given Random-like instance for management by\n    Hypothesis.\n\n    You can pass instances of structural subtypes of ``random.Random``\n    (i.e., objects with seed, getstate, and setstate methods) to\n    ``register_random(r)`` to have their states seeded and restored in the same\n    way as the global PRNGs from the ``random`` and ``numpy.random`` modules.\n\n    All global PRNGs, from e.g. simulation or scheduling frameworks, should\n    be registered to prevent flaky tests. Hypothesis will ensure that the\n    PRNG state is consistent for all test runs, always seeding them to zero and\n    restoring the previous state after the test, or, reproducibly varied if you\n    choose to use the :func:`~hypothesis.strategies.random_module` strategy.\n\n    ``register_random`` only makes `weakrefs\n    <https://docs.python.org/3/library/weakref.html#module-weakref>`_ to ``r``,\n    thus ``r`` will only be managed by Hypothesis as long as it has active\n    references elsewhere at runtime. The pattern ``register_random(MyRandom())``\n    will raise a ``ReferenceError`` to help protect users from this issue.\n    This check does not occur for the PyPy interpreter. See the following example for\n    an illustration of this issue\n\n    .. code-block:: python\n\n\n       def my_BROKEN_hook():\n           r = MyRandomLike()\n\n           # `r` will be garbage collected after the hook resolved\n           # and Hypothesis will 'forget' that it was registered\n           register_random(r)  # Hypothesis will emit a warning\n\n\n       rng = MyRandomLike()\n\n\n       def my_WORKING_hook():\n           register_random(rng)\n    \"\"\"\n    if not (hasattr(r, \"seed\") and hasattr(r, \"getstate\") and hasattr(r, \"setstate\")):\n        raise InvalidArgument(f\"{r=} does not have all the required methods\")\n\n    if r in [\n        random\n        for ref in RANDOMS_TO_MANAGE.data.copy().values()  # type: ignore\n        if (random := ref()) is not None\n    ]:\n        return\n\n    if not (PYPY or GRAALPY):  # pragma: no branch\n        # PYPY and GRAALPY do not have `sys.getrefcount`.\n        gc.collect()\n        if not gc.get_referrers(r):\n            if sys.getrefcount(r) <= _PLATFORM_REF_COUNT:\n                raise ReferenceError(\n                    f\"`register_random` was passed `r={r}` which will be \"\n                    \"garbage collected immediately after `register_random` creates a \"\n                    \"weakref to it. This will prevent Hypothesis from managing this \"\n                    \"PRNG. See the docs for `register_random` for more \"\n                    \"details.\"\n                )\n            elif not FREE_THREADED_CPYTHON:  # pragma: no branch\n                # On CPython, check for the free-threaded build because\n                # gc.get_referrers() ignores objects with immortal refcounts\n                # and objects are immortalized in the Python 3.13\n                # free-threading implementation at runtime.\n\n                warnings.warn(\n                    \"It looks like `register_random` was passed an object that could \"\n                    \"be garbage collected immediately after `register_random` creates \"\n                    \"a weakref to it. This will prevent Hypothesis from managing this \"\n                    \"PRNG. See the docs for `register_random` for more details.\",\n                    HypothesisWarning,\n                    stacklevel=2,\n                )\n\n    RANDOMS_TO_MANAGE[next(_RKEY)] = r\n\n\n# Used to make the warning issued by `deprecate_random_in_strategy` thread-safe,\n# as well as to avoid warning on uses of st.randoms().\n# Store just the hash to reduce memory consumption. This is an underapproximation\n# of membership (distinct items might have the same hash), which is fine for the\n# warning, as it results in missed alarms, not false alarms.\n_known_random_state_hashes: set[Any] = set()\n\n\ndef get_seeder_and_restorer(\n    seed: Hashable = 0,\n) -> tuple[Callable[[], None], Callable[[], None]]:\n    \"\"\"Return a pair of functions which respectively seed all and restore\n    the state of all registered PRNGs.\n\n    This is used by the core engine via `deterministic_PRNG`, and by users\n    via `register_random`.  We support registration of additional random.Random\n    instances (or other objects with seed, getstate, and setstate methods)\n    to force determinism on simulation or scheduling frameworks which avoid\n    using the global random state.  See e.g. #1709.\n    \"\"\"\n    assert isinstance(seed, int)\n    assert 0 <= seed < 2**32\n    states: dict[int, object] = {}\n\n    if \"numpy\" in sys.modules:\n        global NP_RANDOM\n        if NP_RANDOM is None:\n            # Protect this from garbage-collection by adding it to global scope\n            NP_RANDOM = RANDOMS_TO_MANAGE[next(_RKEY)] = NumpyRandomWrapper()\n\n    def seed_all() -> None:\n        assert not states\n        # access .data.copy().items() instead of .items() to avoid a \"dictionary\n        # changed size during iteration\" error under multithreading.\n        #\n        # I initially expected this to be fixed by\n        # https://github.com/python/cpython/commit/96d37dbcd23e65a7a57819aeced9034296ef747e,\n        # but I believe that is addressing the size change from weakrefs expiring\n        # during gc, not from the user adding new elements to the dict.\n        #\n        # Since we're accessing .data, we have to manually handle checking for\n        # expired ref instances during iteration. Normally WeakValueDictionary\n        # handles this for us.\n        #\n        # This command reproduces at time of writing:\n        #   pytest hypothesis-python/tests/ -k test_intervals_are_equivalent_to_their_lists\n        #   --parallel-threads 2\n        for k, ref in RANDOMS_TO_MANAGE.data.copy().items():  # type: ignore\n            r = ref()\n            if r is None:\n                # ie the random instance has been gc'd\n                continue  # pragma: no cover\n            states[k] = r.getstate()\n            if k == _global_random_rkey:\n                # r.seed sets the random's state. We want to add that state to\n                # _known_random_states before calling r.seed, in case a thread\n                # switch occurs between the two. To figure out the seed -> state\n                # mapping, set the seed on a dummy random and add that state to\n                # _known_random_state.\n                #\n                # we could use a global dummy random here, but then we'd have to\n                # put a lock around it, and it's not clear to me if that's more\n                # efficient than constructing a new instance each time.\n                dummy_random = Random()\n                dummy_random.seed(seed)\n                _known_random_state_hashes.add(hash(dummy_random.getstate()))\n                # we expect `assert r.getstate() == dummy_random.getstate()` to\n                # hold here, but thread switches means it might not.\n\n            r.seed(seed)\n\n    def restore_all() -> None:\n        for k, state in states.items():\n            r = RANDOMS_TO_MANAGE.get(k)\n            if r is None:  # i.e., has been garbage-collected\n                continue\n\n            if k == _global_random_rkey:\n                _known_random_state_hashes.add(hash(state))\n            r.setstate(state)\n\n        states.clear()\n\n    return seed_all, restore_all\n\n\n@contextlib.contextmanager\ndef deterministic_PRNG(seed: int = 0) -> Generator[None, None, None]:\n    \"\"\"Context manager that handles random.seed without polluting global state.\n\n    See issue #1266 and PR #1295 for details and motivation - in short,\n    leaving the global pseudo-random number generator (PRNG) seeded is a very\n    bad idea in principle, and breaks all kinds of independence assumptions\n    in practice.\n    \"\"\"\n    if (\n        hypothesis.core.threadlocal._hypothesis_global_random is None\n    ):  # pragma: no cover\n        hypothesis.core.threadlocal._hypothesis_global_random = Random()\n        register_random(hypothesis.core.threadlocal._hypothesis_global_random)\n\n    seed_all, restore_all = get_seeder_and_restorer(seed)\n    seed_all()\n    try:\n        yield\n    finally:\n        restore_all()\n        # TODO it would be nice to clean up _known_random_state_hashes when no\n        # active deterministic_PRNG contexts remain, to free memory (see similar\n        # logic in StackframeLimiter). But it's a bit annoying to get right, and\n        # likely not a big deal.\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/escalation.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport contextlib\nimport os\nimport sys\nimport textwrap\nimport traceback\nfrom collections.abc import Callable\nfrom dataclasses import dataclass\nfrom functools import partial\nfrom inspect import getfile, getsourcefile\nfrom pathlib import Path\nfrom types import ModuleType, TracebackType\n\nimport hypothesis\nfrom hypothesis.errors import _Trimmable\nfrom hypothesis.internal.compat import BaseExceptionGroup\nfrom hypothesis.utils.dynamicvariables import DynamicVariable\n\nFILE_CACHE: dict[ModuleType, dict[str, bool]] = {}\n\n\ndef belongs_to(package: ModuleType) -> Callable[[str], bool]:\n    if getattr(package, \"__file__\", None) is None:  # pragma: no cover\n        return lambda filepath: False\n\n    assert package.__file__ is not None\n    FILE_CACHE.setdefault(package, {})\n    cache = FILE_CACHE[package]\n    root = Path(package.__file__).resolve().parent\n\n    def accept(filepath: str) -> bool:\n        try:\n            return cache[filepath]\n        except KeyError:\n            pass\n        try:\n            Path(filepath).resolve().relative_to(root)\n            result = True\n        except Exception:\n            result = False\n        cache[filepath] = result\n        return result\n\n    accept.__name__ = f\"is_{package.__name__}_file\"\n    return accept\n\n\nis_hypothesis_file = belongs_to(hypothesis)\n\n\ndef get_trimmed_traceback(\n    exception: BaseException | None = None,\n) -> TracebackType | None:\n    \"\"\"Return the current traceback, minus any frames added by Hypothesis.\"\"\"\n    if exception is None:\n        _, exception, tb = sys.exc_info()\n    else:\n        tb = exception.__traceback__\n    # Avoid trimming the traceback if we're in verbose mode, or the error\n    # was raised inside Hypothesis. Additionally, the environment variable\n    # HYPOTHESIS_NO_TRACEBACK_TRIM is respected if nonempty, because verbose\n    # mode is prohibitively slow when debugging strategy recursion errors.\n    assert hypothesis.settings.default is not None\n    if (\n        tb is None\n        or os.environ.get(\"HYPOTHESIS_NO_TRACEBACK_TRIM\")\n        or hypothesis.settings.default.verbosity >= hypothesis.Verbosity.debug\n        or (\n            is_hypothesis_file(traceback.extract_tb(tb)[-1][0])\n            and not isinstance(exception, _Trimmable)\n        )\n    ):\n        return tb\n    while tb.tb_next is not None and (\n        # If the frame is from one of our files, it's been added by Hypothesis.\n        is_hypothesis_file(getsourcefile(tb.tb_frame) or getfile(tb.tb_frame))\n        # But our `@proxies` decorator overrides the source location,\n        # so we check for an attribute it injects into the frame too.\n        or tb.tb_frame.f_globals.get(\"__hypothesistracebackhide__\") is True\n    ):\n        tb = tb.tb_next\n    return tb\n\n\n@dataclass(slots=True, frozen=True)\nclass InterestingOrigin:\n    # The `interesting_origin` is how Hypothesis distinguishes between multiple\n    # failures, for reporting and also to replay from the example database (even\n    # if report_multiple_bugs=False).  We traditionally use the exception type and\n    # location, but have extracted this logic in order to see through `except ...:`\n    # blocks and understand the __cause__ (`raise x from y`) or __context__ that\n    # first raised an exception as well as PEP-654 exception groups.\n    exc_type: type[BaseException]\n    filename: str | None\n    lineno: int | None\n    context: \"InterestingOrigin | tuple[()]\"\n    group_elems: \"tuple[InterestingOrigin, ...]\"\n\n    def __str__(self) -> str:\n        ctx = \"\"\n        if self.context:\n            ctx = textwrap.indent(f\"\\ncontext: {self.context}\", prefix=\"    \")\n        group = \"\"\n        if self.group_elems:\n            chunks = \"\\n  \".join(str(x) for x in self.group_elems)\n            group = textwrap.indent(f\"\\nchild exceptions:\\n  {chunks}\", prefix=\"    \")\n        return f\"{self.exc_type.__name__} at {self.filename}:{self.lineno}{ctx}{group}\"\n\n    @classmethod\n    def from_exception(\n        cls, exception: BaseException, /, seen: tuple[BaseException, ...] = ()\n    ) -> \"InterestingOrigin\":\n        filename, lineno = None, None\n        if tb := get_trimmed_traceback(exception):\n            filename, lineno, *_ = traceback.extract_tb(tb)[-1]\n        seen = (*seen, exception)\n        make = partial(cls.from_exception, seen=seen)\n        context: InterestingOrigin | tuple[()] = ()\n        if exception.__context__ is not None and exception.__context__ not in seen:\n            context = make(exception.__context__)\n        return cls(\n            type(exception),\n            filename,\n            lineno,\n            # Note that if __cause__ is set it is always equal to __context__, explicitly\n            # to support introspection when debugging, so we can use that unconditionally.\n            context,\n            # We distinguish exception groups by the inner exceptions, as for __context__\n            (\n                tuple(make(exc) for exc in exception.exceptions if exc not in seen)\n                if isinstance(exception, BaseExceptionGroup)\n                else ()\n            ),\n        )\n\n\ncurrent_pytest_item = DynamicVariable(None)\n\n\ndef _get_exceptioninfo():\n    # ExceptionInfo was moved to the top-level namespace in Pytest 7.0\n    if \"pytest\" in sys.modules:\n        with contextlib.suppress(Exception):\n            # From Pytest 7, __init__ warns on direct calls.\n            return sys.modules[\"pytest\"].ExceptionInfo.from_exc_info\n    if \"_pytest._code\" in sys.modules:  # old versions only\n        with contextlib.suppress(Exception):\n            return sys.modules[\"_pytest._code\"].ExceptionInfo\n    return None  # pragma: no cover  # coverage tests always use pytest\n\n\ndef format_exception(err, tb):\n    # Try using Pytest to match the currently configured traceback style\n    ExceptionInfo = _get_exceptioninfo()\n    if current_pytest_item.value is not None and ExceptionInfo is not None:\n        item = current_pytest_item.value\n        return str(item.repr_failure(ExceptionInfo((type(err), err, tb)))) + \"\\n\"\n\n    # Or use better_exceptions, if that's installed and enabled\n    if \"better_exceptions\" in sys.modules:\n        better_exceptions = sys.modules[\"better_exceptions\"]\n        if sys.excepthook is better_exceptions.excepthook:\n            return \"\".join(better_exceptions.format_exception(type(err), err, tb))\n\n    # If all else fails, use the standard-library formatting tools\n    return \"\".join(traceback.format_exception(type(err), err, tb))\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/filtering.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"Tools for understanding predicates, to satisfy them by construction.\n\nFor example::\n\n    integers().filter(lambda x: x >= 0) -> integers(min_value=0)\n\nThis is intractable in general, but reasonably easy for simple cases involving\nnumeric bounds, strings with length or regex constraints, and collection lengths -\nand those are precisely the most common cases.  When they arise in e.g. Pandas\ndataframes, it's also pretty painful to do the constructive version by hand in\na library; so we prefer to share all the implementation effort here.\nSee https://github.com/HypothesisWorks/hypothesis/issues/2701 for details.\n\"\"\"\n\nimport ast\nimport inspect\nimport math\nimport operator\nimport sys\nfrom collections.abc import Callable, Collection\nfrom decimal import Decimal\nfrom fractions import Fraction\nfrom functools import partial\nfrom typing import Any, NamedTuple, TypeVar\n\nfrom hypothesis.internal.compat import ceil, floor\nfrom hypothesis.internal.floats import next_down, next_up\nfrom hypothesis.internal.lambda_sources import lambda_description\nfrom hypothesis.internal.reflection import get_pretty_function_description\n\nif sys.version_info[:2] >= (3, 14):\n    from functools import Placeholder\nelse:  # pragma: no cover\n    Placeholder = object()\n\nEx = TypeVar(\"Ex\")\nPredicate = Callable[[Ex], bool]\n\n\nclass ConstructivePredicate(NamedTuple):\n    \"\"\"Return constraints to the appropriate strategy, and the predicate if needed.\n\n    For example::\n\n        integers().filter(lambda x: x >= 0)\n        -> {\"min_value\": 0\"}, None\n\n        integers().filter(lambda x: x >= 0 and x % 7)\n        -> {\"min_value\": 0}, lambda x: x % 7\n\n    At least in principle - for now we usually return the predicate unchanged\n    if needed.\n\n    We have a separate get-predicate frontend for each \"group\" of strategies; e.g.\n    for each numeric type, for strings, for bytes, for collection sizes, etc.\n    \"\"\"\n\n    constraints: dict[str, Any]\n    predicate: Predicate | None\n\n    @classmethod\n    def unchanged(cls, predicate: Predicate) -> \"ConstructivePredicate\":\n        return cls({}, predicate)\n\n    def __repr__(self) -> str:\n        fn = get_pretty_function_description(self.predicate)\n        return f\"{self.__class__.__name__}(constraints={self.constraints!r}, predicate={fn})\"\n\n\nARG = object()\n\n\ndef convert(node: ast.AST, argname: str) -> object:\n    if isinstance(node, ast.Name):\n        if node.id != argname:\n            raise ValueError(\"Non-local variable\")\n        return ARG\n    if isinstance(node, ast.Call):\n        if (\n            isinstance(node.func, ast.Name)\n            and node.func.id == \"len\"\n            and len(node.args) == 1\n        ):\n            # error unless comparison is to the len *of the lambda arg*\n            return convert(node.args[0], argname)\n    return ast.literal_eval(node)\n\n\ndef comp_to_constraints(x: ast.AST, op: ast.AST, y: ast.AST, *, argname: str) -> dict:\n    a = convert(x, argname)\n    b = convert(y, argname)\n    num = (int, float)\n    if not (a is ARG and isinstance(b, num)) and not (isinstance(a, num) and b is ARG):\n        # It would be possible to work out if comparisons between two literals\n        # are always true or false, but it's too rare to be worth the complexity.\n        # (and we can't even do `arg == arg`, because what if it's NaN?)\n        raise ValueError(\"Can't analyse this comparison\")\n\n    of_len = {\"len\": True} if isinstance(x, ast.Call) or isinstance(y, ast.Call) else {}\n\n    if isinstance(op, ast.Lt):\n        if a is ARG:\n            return {\"max_value\": b, \"exclude_max\": True, **of_len}\n        return {\"min_value\": a, \"exclude_min\": True, **of_len}\n    elif isinstance(op, ast.LtE):\n        if a is ARG:\n            return {\"max_value\": b, **of_len}\n        return {\"min_value\": a, **of_len}\n    elif isinstance(op, ast.Eq):\n        if a is ARG:\n            return {\"min_value\": b, \"max_value\": b, **of_len}\n        return {\"min_value\": a, \"max_value\": a, **of_len}\n    elif isinstance(op, ast.GtE):\n        if a is ARG:\n            return {\"min_value\": b, **of_len}\n        return {\"max_value\": a, **of_len}\n    elif isinstance(op, ast.Gt):\n        if a is ARG:\n            return {\"min_value\": b, \"exclude_min\": True, **of_len}\n        return {\"max_value\": a, \"exclude_max\": True, **of_len}\n    raise ValueError(\"Unhandled comparison operator\")  # e.g. ast.Ne\n\n\ndef merge_preds(*con_predicates: ConstructivePredicate) -> ConstructivePredicate:\n    # This function is just kinda messy.  Unfortunately the neatest way\n    # to do this is just to roll out each case and handle them in turn.\n    base = {\n        \"min_value\": -math.inf,\n        \"max_value\": math.inf,\n        \"exclude_min\": False,\n        \"exclude_max\": False,\n    }\n    predicate = None\n    for kw, p in con_predicates:\n        assert (\n            not p or not predicate or p is predicate\n        ), \"Can't merge two partially-constructive preds\"\n        predicate = p or predicate\n        if \"min_value\" in kw:\n            if kw[\"min_value\"] > base[\"min_value\"]:\n                base[\"exclude_min\"] = kw.get(\"exclude_min\", False)\n                base[\"min_value\"] = kw[\"min_value\"]\n            elif kw[\"min_value\"] == base[\"min_value\"]:\n                base[\"exclude_min\"] |= kw.get(\"exclude_min\", False)\n        if \"max_value\" in kw:\n            if kw[\"max_value\"] < base[\"max_value\"]:\n                base[\"exclude_max\"] = kw.get(\"exclude_max\", False)\n                base[\"max_value\"] = kw[\"max_value\"]\n            elif kw[\"max_value\"] == base[\"max_value\"]:\n                base[\"exclude_max\"] |= kw.get(\"exclude_max\", False)\n\n    has_len = {\"len\" in kw for kw, _ in con_predicates if kw}\n    assert len(has_len) <= 1, \"can't mix numeric with length constraints\"\n    if has_len == {True}:\n        base[\"len\"] = True\n\n    if not base[\"exclude_min\"]:\n        del base[\"exclude_min\"]\n        if base[\"min_value\"] == -math.inf:\n            del base[\"min_value\"]\n    if not base[\"exclude_max\"]:\n        del base[\"exclude_max\"]\n        if base[\"max_value\"] == math.inf:\n            del base[\"max_value\"]\n    return ConstructivePredicate(base, predicate)\n\n\ndef numeric_bounds_from_ast(\n    tree: ast.AST, argname: str, fallback: ConstructivePredicate\n) -> ConstructivePredicate:\n    \"\"\"Take an AST; return a ConstructivePredicate.\n\n    >>> lambda x: x >= 0\n    {\"min_value\": 0}, None\n    >>> lambda x: x < 10\n    {\"max_value\": 10, \"exclude_max\": True}, None\n    >>> lambda x: len(x) >= 5\n    {\"min_value\": 5, \"len\": True}, None\n    >>> lambda x: x >= y\n    {}, lambda x: x >= y\n\n    See also https://greentreesnakes.readthedocs.io/en/latest/\n    \"\"\"\n    if isinstance(tree, ast.Compare):\n        ops = tree.ops\n        vals = tree.comparators\n        comparisons = [(tree.left, ops[0], vals[0])]\n        for i, (op, val) in enumerate(zip(ops[1:], vals[1:], strict=True), start=1):\n            comparisons.append((vals[i - 1], op, val))\n        bounds = []\n        for comp in comparisons:\n            try:\n                constraints = comp_to_constraints(*comp, argname=argname)\n                # Because `len` could be redefined in the enclosing scope, we *always*\n                # have to apply the condition as a filter, in addition to rewriting.\n                pred = fallback.predicate if \"len\" in constraints else None\n                bounds.append(ConstructivePredicate(constraints, pred))\n            except ValueError:\n                bounds.append(fallback)\n        return merge_preds(*bounds)\n\n    if isinstance(tree, ast.BoolOp) and isinstance(tree.op, ast.And):\n        return merge_preds(\n            *(numeric_bounds_from_ast(node, argname, fallback) for node in tree.values)\n        )\n\n    return fallback\n\n\ndef get_numeric_predicate_bounds(predicate: Predicate) -> ConstructivePredicate:\n    \"\"\"Shared logic for understanding numeric bounds.\n\n    We then specialise this in the other functions below, to ensure that e.g.\n    all the values are representable in the types that we're planning to generate\n    so that the strategy validation doesn't complain.\n    \"\"\"\n    unchanged = ConstructivePredicate.unchanged(predicate)\n    if (\n        isinstance(predicate, partial)\n        and not predicate.keywords\n        and (\n            len(predicate.args) == 1\n            or (predicate.args[0] is Placeholder and len(predicate.args) == 2)\n        )\n    ):\n        if len(predicate.args) == 1:\n            arg = predicate.args[0]\n            func = predicate.func\n        else:  # pragma: no cover  # Python 3.14+ only\n            assert predicate.args[0] is Placeholder\n            arg = predicate.args[1]\n            func = {  # reverses the table below; eq is unchanged\n                operator.lt: operator.gt,\n                operator.le: operator.ge,\n                operator.ge: operator.le,\n                operator.gt: operator.lt,\n            }.get(predicate.func, predicate.func)\n            assert func not in (min_len, max_len)  # sanity-check; these are private\n\n        if (\n            (isinstance(arg, Decimal) and Decimal.is_snan(arg))\n            or not isinstance(arg, (int, float, Fraction, Decimal))\n            or math.isnan(arg)\n        ):\n            return unchanged\n        options = {\n            # We're talking about op(arg, x) - the reverse of our usual intuition!\n            operator.lt: {\"min_value\": arg, \"exclude_min\": True},  # lambda x: arg < x\n            operator.le: {\"min_value\": arg},  #                      lambda x: arg <= x\n            operator.eq: {\"min_value\": arg, \"max_value\": arg},  #    lambda x: arg == x\n            operator.ge: {\"max_value\": arg},  #                      lambda x: arg >= x\n            operator.gt: {\"max_value\": arg, \"exclude_max\": True},  # lambda x: arg > x\n            # Special-case our default predicates for length bounds\n            min_len: {\"min_value\": arg, \"len\": True},\n            max_len: {\"max_value\": arg, \"len\": True},\n        }\n        if func in options:\n            return ConstructivePredicate(options[func], None)\n\n    # This section is a little complicated, but stepping through with comments should\n    # help to clarify it.  We start by finding the source code for our predicate and\n    # parsing it to an abstract syntax tree; if this fails for any reason we bail out\n    # and fall back to standard rejection sampling (a running theme).\n    try:\n        if predicate.__name__ == \"<lambda>\":\n            source = lambda_description(predicate)\n        else:\n            source = inspect.getsource(predicate)\n        tree: ast.AST = ast.parse(source)\n    except Exception:\n        return unchanged\n\n    # Dig down to the relevant subtree - our tree is probably a Module containing\n    # either a FunctionDef, or an Expr which in turn contains a lambda definition.\n    while isinstance(tree, ast.Module) and len(tree.body) == 1:\n        tree = tree.body[0]\n    while isinstance(tree, ast.Expr):\n        tree = tree.value\n\n    if isinstance(tree, ast.Lambda) and len(tree.args.args) == 1:\n        return numeric_bounds_from_ast(tree.body, tree.args.args[0].arg, unchanged)\n    elif isinstance(tree, ast.FunctionDef) and len(tree.args.args) == 1:\n        if len(tree.body) != 1 or not isinstance(tree.body[0], ast.Return):\n            # If the body of the function is anything but `return <expr>`,\n            # i.e. as simple as a lambda, we can't process it (yet).\n            return unchanged\n        argname = tree.args.args[0].arg\n        body = tree.body[0].value\n        assert isinstance(body, ast.AST)\n        return numeric_bounds_from_ast(body, argname, unchanged)\n    return unchanged\n\n\ndef get_integer_predicate_bounds(predicate: Predicate) -> ConstructivePredicate:\n    constraints, predicate = get_numeric_predicate_bounds(predicate)\n\n    if \"min_value\" in constraints:\n        if constraints[\"min_value\"] == -math.inf:\n            del constraints[\"min_value\"]\n        elif math.isinf(constraints[\"min_value\"]):\n            return ConstructivePredicate({\"min_value\": 1, \"max_value\": -1}, None)\n        elif constraints[\"min_value\"] != int(constraints[\"min_value\"]):\n            constraints[\"min_value\"] = ceil(constraints[\"min_value\"])\n        elif constraints.get(\"exclude_min\", False):\n            constraints[\"min_value\"] = int(constraints[\"min_value\"]) + 1\n\n    if \"max_value\" in constraints:\n        if constraints[\"max_value\"] == math.inf:\n            del constraints[\"max_value\"]\n        elif math.isinf(constraints[\"max_value\"]):\n            return ConstructivePredicate({\"min_value\": 1, \"max_value\": -1}, None)\n        elif constraints[\"max_value\"] != int(constraints[\"max_value\"]):\n            constraints[\"max_value\"] = floor(constraints[\"max_value\"])\n        elif constraints.get(\"exclude_max\", False):\n            constraints[\"max_value\"] = int(constraints[\"max_value\"]) - 1\n\n    kw_categories = {\"min_value\", \"max_value\", \"len\"}\n    constraints = {k: v for k, v in constraints.items() if k in kw_categories}\n    return ConstructivePredicate(constraints, predicate)\n\n\ndef get_float_predicate_bounds(predicate: Predicate) -> ConstructivePredicate:\n    constraints, predicate = get_numeric_predicate_bounds(predicate)\n\n    if \"min_value\" in constraints:\n        min_value = constraints[\"min_value\"]\n        constraints[\"min_value\"] = float(constraints[\"min_value\"])\n        if min_value < constraints[\"min_value\"] or (\n            min_value == constraints[\"min_value\"]\n            and constraints.get(\"exclude_min\", False)\n        ):\n            constraints[\"min_value\"] = next_up(constraints[\"min_value\"])\n\n    if \"max_value\" in constraints:\n        max_value = constraints[\"max_value\"]\n        constraints[\"max_value\"] = float(constraints[\"max_value\"])\n        if max_value > constraints[\"max_value\"] or (\n            max_value == constraints[\"max_value\"]\n            and constraints.get(\"exclude_max\", False)\n        ):\n            constraints[\"max_value\"] = next_down(constraints[\"max_value\"])\n\n    constraints = {\n        k: v for k, v in constraints.items() if k in {\"min_value\", \"max_value\"}\n    }\n    return ConstructivePredicate(constraints, predicate)\n\n\ndef max_len(size: int, element: Collection[object]) -> bool:\n    return len(element) <= size\n\n\ndef min_len(size: int, element: Collection[object]) -> bool:\n    return size <= len(element)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/floats.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nimport struct\nfrom collections.abc import Callable\nfrom sys import float_info\nfrom typing import Literal, SupportsFloat, TypeAlias\n\nSignedIntFormat: TypeAlias = Literal[\"!h\", \"!i\", \"!q\"]\nUnsignedIntFormat: TypeAlias = Literal[\"!H\", \"!I\", \"!Q\"]\nIntFormat: TypeAlias = SignedIntFormat | UnsignedIntFormat\nFloatFormat: TypeAlias = Literal[\"!e\", \"!f\", \"!d\"]\nWidth: TypeAlias = Literal[16, 32, 64]\n\n# Format codes for (int, float) sized types, used for byte-wise casts.\n# See https://docs.python.org/3/library/struct.html#format-characters\nSTRUCT_FORMATS: dict[int, tuple[UnsignedIntFormat, FloatFormat]] = {\n    16: (\"!H\", \"!e\"),\n    32: (\"!I\", \"!f\"),\n    64: (\"!Q\", \"!d\"),\n}\n\nTO_SIGNED_FORMAT: dict[UnsignedIntFormat, SignedIntFormat] = {\n    \"!H\": \"!h\",\n    \"!I\": \"!i\",\n    \"!Q\": \"!q\",\n}\n\n\ndef reinterpret_bits(x: float | int, from_: str, to: str) -> float | int:\n    x = struct.unpack(to, struct.pack(from_, x))[0]\n    assert isinstance(x, (float, int))\n    return x\n\n\ndef float_of(x: SupportsFloat, width: Width) -> float:\n    assert width in (16, 32, 64)\n    if width == 64:\n        return float(x)\n    elif width == 32:\n        return reinterpret_bits(float(x), \"!f\", \"!f\")\n    else:\n        return reinterpret_bits(float(x), \"!e\", \"!e\")\n\n\ndef is_negative(x: SupportsFloat) -> bool:\n    try:\n        return math.copysign(1.0, x) < 0\n    except TypeError:\n        raise TypeError(\n            f\"Expected float but got {x!r} of type {type(x).__name__}\"\n        ) from None\n\n\ndef count_between_floats(x: float, y: float, width: int = 64) -> int:\n    assert x <= y\n    if is_negative(x):\n        if is_negative(y):\n            return float_to_int(x, width) - float_to_int(y, width) + 1\n        else:\n            return count_between_floats(x, -0.0, width) + count_between_floats(\n                0.0, y, width\n            )\n    else:\n        assert not is_negative(y)\n        return float_to_int(y, width) - float_to_int(x, width) + 1\n\n\ndef float_to_int(value: float, width: int = 64) -> int:\n    fmt_int, fmt_flt = STRUCT_FORMATS[width]\n    x = reinterpret_bits(value, fmt_flt, fmt_int)\n    assert isinstance(x, int)\n    return x\n\n\ndef int_to_float(value: int, width: int = 64) -> float:\n    fmt_int, fmt_flt = STRUCT_FORMATS[width]\n    return reinterpret_bits(value, fmt_int, fmt_flt)\n\n\ndef next_up(value: float, width: int = 64) -> float:\n    \"\"\"Return the first float larger than finite `val` - IEEE 754's `nextUp`.\n\n    From https://stackoverflow.com/a/10426033, with thanks to Mark Dickinson.\n    \"\"\"\n    assert isinstance(value, float), f\"{value!r} of type {type(value)}\"\n    if math.isnan(value) or (math.isinf(value) and value > 0):\n        return value\n    if value == 0.0 and is_negative(value):\n        return 0.0\n    fmt_int, fmt_flt = STRUCT_FORMATS[width]\n    # Note: n is signed; float_to_int returns unsigned\n    fmt_int_signed = TO_SIGNED_FORMAT[fmt_int]\n    n = reinterpret_bits(value, fmt_flt, fmt_int_signed)\n    if n >= 0:\n        n += 1\n    else:\n        n -= 1\n    return reinterpret_bits(n, fmt_int_signed, fmt_flt)\n\n\ndef next_down(value: float, width: int = 64) -> float:\n    return -next_up(-value, width)\n\n\ndef next_down_normal(value: float, width: int, *, allow_subnormal: bool) -> float:\n    value = next_down(value, width)\n    if (not allow_subnormal) and 0 < abs(value) < width_smallest_normals[width]:\n        return 0.0 if value > 0 else -width_smallest_normals[width]\n    return value\n\n\ndef next_up_normal(value: float, width: int, *, allow_subnormal: bool) -> float:\n    return -next_down_normal(-value, width, allow_subnormal=allow_subnormal)\n\n\n# Smallest positive non-zero numbers that is fully representable by an\n# IEEE-754 float, calculated with the width's associated minimum exponent.\n# Values from https://en.wikipedia.org/wiki/IEEE_754#Basic_and_interchange_formats\nwidth_smallest_normals: dict[int, float] = {\n    16: 2 ** -(2 ** (5 - 1) - 2),\n    32: 2 ** -(2 ** (8 - 1) - 2),\n    64: 2 ** -(2 ** (11 - 1) - 2),\n}\nassert width_smallest_normals[64] == float_info.min\n\nmantissa_mask = (1 << 52) - 1\n\n\ndef make_float_clamper(\n    min_value: float,\n    max_value: float,\n    *,\n    allow_nan: bool,\n    smallest_nonzero_magnitude: float,\n) -> Callable[[float], float]:\n    \"\"\"\n    Return a function that clamps positive floats into the given bounds.\n    \"\"\"\n    from hypothesis.internal.conjecture.choice import choice_permitted\n\n    assert sign_aware_lte(min_value, max_value)\n    range_size = min(max_value - min_value, float_info.max)\n\n    def float_clamper(f: float) -> float:\n        if choice_permitted(\n            f,\n            {\n                \"min_value\": min_value,\n                \"max_value\": max_value,\n                \"allow_nan\": allow_nan,\n                \"smallest_nonzero_magnitude\": smallest_nonzero_magnitude,\n            },\n        ):\n            return f\n        # Outside bounds; pick a new value, sampled from the allowed range,\n        # using the mantissa bits.\n        mant = float_to_int(abs(f)) & mantissa_mask\n        f = min_value + range_size * (mant / mantissa_mask)\n\n        # if we resampled into the space disallowed by smallest_nonzero_magnitude,\n        # default to smallest_nonzero_magnitude.\n        if 0 < abs(f) < smallest_nonzero_magnitude:\n            f = smallest_nonzero_magnitude\n            # we must have either -smallest_nonzero_magnitude <= min_value or\n            # smallest_nonzero_magnitude >= max_value, or no values would be\n            # possible. If smallest_nonzero_magnitude is not valid (because it's\n            # larger than max_value), then -smallest_nonzero_magnitude must be valid.\n            if smallest_nonzero_magnitude > max_value:\n                f *= -1\n\n        # Re-enforce the bounds (just in case of floating point arithmetic error)\n        return clamp(min_value, f, max_value)\n\n    return float_clamper\n\n\ndef sign_aware_lte(x: float | int, y: float | int) -> bool:\n    \"\"\"Less-than-or-equals, but strictly orders -0.0 and 0.0\"\"\"\n    if x == 0.0 == y:\n        return math.copysign(1.0, x) <= math.copysign(1.0, y)\n    else:\n        return x <= y\n\n\ndef clamp(lower: float | int, value: float | int, upper: float | int) -> float | int:\n    \"\"\"Given a value and lower/upper bounds, 'clamp' the value so that\n    it satisfies lower <= value <= upper.  NaN is mapped to lower.\"\"\"\n    # this seems pointless (and is for integers), but handles the -0.0/0.0 case.\n    if not sign_aware_lte(lower, value):\n        return lower\n    if not sign_aware_lte(value, upper):\n        return upper\n    return value\n\n\nSMALLEST_SUBNORMAL = next_up(0.0)\nSIGNALING_NAN = int_to_float(0x7FF8_0000_0000_0001)  # nonzero mantissa\nMAX_PRECISE_INTEGER = 2**53\nassert math.isnan(SIGNALING_NAN)\nassert math.copysign(1, SIGNALING_NAN) == 1\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/healthcheck.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.errors import FailedHealthCheck\n\n\ndef fail_health_check(settings, message, label):\n    # Tell pytest to omit the body of this function from tracebacks\n    # https://docs.pytest.org/en/latest/example/simple.html#writing-well-integrated-assertion-helpers\n    __tracebackhide__ = True\n\n    if label in settings.suppress_health_check:\n        return\n    raise FailedHealthCheck(message)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/intervalsets.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections.abc import Iterable, Sequence\nfrom typing import TYPE_CHECKING, TypeAlias, cast, final\n\nif TYPE_CHECKING:\n    from typing_extensions import Self\n\nIntervalsT: TypeAlias = tuple[tuple[int, int], ...]\n\n\n# @final makes mypy happy with the Self return annotations. We otherwise run\n# afoul of:\n# > You should not use Self as the return annotation if the method is not\n# > guaranteed to return an instance of a subclass when the class is subclassed\n# > https://docs.python.org/3/library/typing.html#typing.Self\n\n\n@final\nclass IntervalSet:\n    \"\"\"\n    A compact and efficient representation of a set of ``(a, b)`` intervals. Can\n    be treated like a set of integers, in that ``n in intervals`` will return\n    ``True`` if ``n`` is contained in any of the ``(a, b)`` intervals, and\n    ``False`` otherwise.\n    \"\"\"\n\n    @classmethod\n    def from_string(cls, s: str) -> \"Self\":\n        \"\"\"Return a tuple of intervals, covering the codepoints of characters in `s`.\n\n        >>> IntervalSet.from_string('abcdef0123456789')\n        ((48, 57), (97, 102))\n        \"\"\"\n        x = cls([(ord(c), ord(c)) for c in sorted(s)])\n        return x.union(x)\n\n    def __init__(self, intervals: Iterable[Sequence[int]] = ()) -> None:\n        self.intervals: IntervalsT = cast(\n            IntervalsT, tuple(tuple(v) for v in intervals)\n        )\n        # cast above is validated by this length assertion. check here instead of\n        # before to not exhaust generators before we create intervals from it\n        assert all(len(v) == 2 for v in self.intervals)\n\n        self.offsets: list[int] = [0]\n        for u, v in self.intervals:\n            self.offsets.append(self.offsets[-1] + v - u + 1)\n        self.size = self.offsets.pop()\n        self._idx_of_zero = self.index_above(ord(\"0\"))\n        self._idx_of_Z = min(self.index_above(ord(\"Z\")), len(self) - 1)\n\n    def __len__(self) -> int:\n        return self.size\n\n    def __iter__(self) -> Iterable[int]:\n        for u, v in self.intervals:\n            yield from range(u, v + 1)\n\n    def __getitem__(self, i: int) -> int:\n        if i < 0:\n            i = self.size + i\n        if i < 0 or i >= self.size:\n            raise IndexError(f\"Invalid index {i} for [0, {self.size})\")\n        # Want j = maximal such that offsets[j] <= i\n\n        j = len(self.intervals) - 1\n        if self.offsets[j] > i:\n            hi = j\n            lo = 0\n            # Invariant: offsets[lo] <= i < offsets[hi]\n            while lo + 1 < hi:\n                mid = (lo + hi) // 2\n                if self.offsets[mid] <= i:\n                    lo = mid\n                else:\n                    hi = mid\n            j = lo\n        t = i - self.offsets[j]\n        u, v = self.intervals[j]\n        r = u + t\n        assert r <= v\n        return r\n\n    def __contains__(self, elem: str | int) -> bool:\n        if isinstance(elem, str):\n            elem = ord(elem)\n        assert 0 <= elem <= 0x10FFFF\n        return any(start <= elem <= end for start, end in self.intervals)\n\n    def __repr__(self) -> str:\n        return f\"IntervalSet({self.intervals!r})\"\n\n    def index(self, value: int) -> int:\n        for offset, (u, v) in zip(self.offsets, self.intervals, strict=True):\n            if u == value:\n                return offset\n            elif u > value:\n                raise ValueError(f\"{value} is not in list\")\n            if value <= v:\n                return offset + (value - u)\n        raise ValueError(f\"{value} is not in list\")\n\n    def index_above(self, value: int) -> int:\n        for offset, (u, v) in zip(self.offsets, self.intervals, strict=True):\n            if u >= value:\n                return offset\n            if value <= v:\n                return offset + (value - u)\n        return self.size\n\n    def __or__(self, other: \"Self\") -> \"Self\":\n        return self.union(other)\n\n    def __sub__(self, other: \"Self\") -> \"Self\":\n        return self.difference(other)\n\n    def __and__(self, other: \"Self\") -> \"Self\":\n        return self.intersection(other)\n\n    def __eq__(self, other: object) -> bool:\n        return isinstance(other, IntervalSet) and (other.intervals == self.intervals)\n\n    def __hash__(self) -> int:\n        return hash(self.intervals)\n\n    def union(self, other: \"Self\") -> \"Self\":\n        \"\"\"Merge two sequences of intervals into a single tuple of intervals.\n\n        Any integer bounded by `x` or `y` is also bounded by the result.\n\n        >>> union([(3, 10)], [(1, 2), (5, 17)])\n        ((1, 17),)\n        \"\"\"\n        assert isinstance(other, type(self))\n        x = self.intervals\n        y = other.intervals\n        if not x:\n            return IntervalSet(y)\n        if not y:\n            return IntervalSet(x)\n        intervals = sorted(x + y, reverse=True)\n        result = [intervals.pop()]\n        while intervals:\n            # 1. intervals is in descending order\n            # 2. pop() takes from the RHS.\n            # 3. (a, b) was popped 1st, then (u, v) was popped 2nd\n            # 4. Therefore: a <= u\n            # 5. We assume that u <= v and a <= b\n            # 6. So we need to handle 2 cases of overlap, and one disjoint case\n            #    |   u--v     |   u----v   |       u--v  |\n            #    |   a----b   |   a--b     |  a--b       |\n            u, v = intervals.pop()\n            a, b = result[-1]\n            if u <= b + 1:\n                # Overlap cases\n                result[-1] = (a, max(v, b))\n            else:\n                # Disjoint case\n                result.append((u, v))\n        return IntervalSet(result)\n\n    def difference(self, other: \"Self\") -> \"Self\":\n        \"\"\"Set difference for lists of intervals. That is, returns a list of\n        intervals that bounds all values bounded by x that are not also bounded by\n        y. x and y are expected to be in sorted order.\n\n        For example difference([(1, 10)], [(2, 3), (9, 15)]) would\n        return [(1, 1), (4, 8)], removing the values 2, 3, 9 and 10 from the\n        interval.\n        \"\"\"\n        assert isinstance(other, type(self))\n        x = self.intervals\n        y = other.intervals\n        if not y:\n            return IntervalSet(x)\n        x = list(map(list, x))\n        i = 0\n        j = 0\n        result: list[Iterable[int]] = []\n        while i < len(x) and j < len(y):\n            # Iterate in parallel over x and y. j stays pointing at the smallest\n            # interval in the left hand side that could still overlap with some\n            # element of x at index >= i.\n            # Similarly, i is not incremented until we know that it does not\n            # overlap with any element of y at index >= j.\n\n            xl, xr = x[i]\n            assert xl <= xr\n            yl, yr = y[j]\n            assert yl <= yr\n\n            if yr < xl:\n                # The interval at y[j] is strictly to the left of the interval at\n                # x[i], so will not overlap with it or any later interval of x.\n                j += 1\n            elif yl > xr:\n                # The interval at y[j] is strictly to the right of the interval at\n                # x[i], so all of x[i] goes into the result as no further intervals\n                # in y will intersect it.\n                result.append(x[i])\n                i += 1\n            elif yl <= xl:\n                if yr >= xr:\n                    # x[i] is contained entirely in y[j], so we just skip over it\n                    # without adding it to the result.\n                    i += 1\n                else:\n                    # The beginning of x[i] is contained in y[j], so we update the\n                    # left endpoint of x[i] to remove this, and increment j as we\n                    # now have moved past it. Note that this is not added to the\n                    # result as is, as more intervals from y may intersect it so it\n                    # may need updating further.\n                    x[i][0] = yr + 1\n                    j += 1\n            else:\n                # yl > xl, so the left hand part of x[i] is not contained in y[j],\n                # so there are some values we should add to the result.\n                result.append((xl, yl - 1))\n\n                if yr + 1 <= xr:\n                    # If y[j] finishes before x[i] does, there may be some values\n                    # in x[i] left that should go in the result (or they may be\n                    # removed by a later interval in y), so we update x[i] to\n                    # reflect that and increment j because it no longer overlaps\n                    # with any remaining element of x.\n                    x[i][0] = yr + 1\n                    j += 1\n                else:\n                    # Every element of x[i] other than the initial part we have\n                    # already added is contained in y[j], so we move to the next\n                    # interval.\n                    i += 1\n        # Any remaining intervals in x do not overlap with any of y, as if they did\n        # we would not have incremented j to the end, so can be added to the result\n        # as they are.\n        result.extend(x[i:])\n        return IntervalSet(map(tuple, result))\n\n    def intersection(self, other: \"Self\") -> \"Self\":\n        \"\"\"Set intersection for lists of intervals.\"\"\"\n        assert isinstance(other, type(self)), other\n        intervals = []\n        i = j = 0\n        while i < len(self.intervals) and j < len(other.intervals):\n            u, v = self.intervals[i]\n            U, V = other.intervals[j]\n            if u > V:\n                j += 1\n            elif U > v:\n                i += 1\n            else:\n                intervals.append((max(u, U), min(v, V)))\n                if v < V:\n                    i += 1\n                else:\n                    j += 1\n        return IntervalSet(intervals)\n\n    def char_in_shrink_order(self, i: int) -> str:\n        # We would like it so that, where possible, shrinking replaces\n        # characters with simple ascii characters, so we rejig this\n        # bit so that the smallest values are 0, 1, 2, ..., Z.\n        #\n        # Imagine that numbers are laid out as abc0yyyZ...\n        # this rearranges them so that they are laid out as\n        # 0yyyZcba..., which gives a better shrinking order.\n        if i <= self._idx_of_Z:\n            # We want to rewrite the integers [0, n] inclusive\n            # to [zero_point, Z_point].\n            n = self._idx_of_Z - self._idx_of_zero\n            if i <= n:\n                i += self._idx_of_zero\n            else:\n                # We want to rewrite the integers [n + 1, Z_point] to\n                # [zero_point, 0] (reversing the order so that codepoints below\n                # zero_point shrink upwards).\n                i = self._idx_of_zero - (i - n)\n                assert i < self._idx_of_zero\n            assert 0 <= i <= self._idx_of_Z\n\n        return chr(self[i])\n\n    def index_from_char_in_shrink_order(self, c: str) -> int:\n        \"\"\"\n        Inverse of char_in_shrink_order.\n        \"\"\"\n        assert len(c) == 1\n        i = self.index(ord(c))\n\n        if i <= self._idx_of_Z:\n            n = self._idx_of_Z - self._idx_of_zero\n            # Rewrite [zero_point, Z_point] to [0, n].\n            if self._idx_of_zero <= i <= self._idx_of_Z:\n                i -= self._idx_of_zero\n                assert 0 <= i <= n\n            # Rewrite [zero_point, 0] to [n + 1, Z_point].\n            else:\n                i = self._idx_of_zero - i + n\n                assert n + 1 <= i <= self._idx_of_Z\n            assert 0 <= i <= self._idx_of_Z\n\n        return i\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/lambda_sources.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport ast\nimport hashlib\nimport inspect\nimport linecache\nimport sys\nimport textwrap\nfrom collections.abc import Callable, MutableMapping\nfrom inspect import Parameter\nfrom typing import Any\nfrom weakref import WeakKeyDictionary\n\nfrom hypothesis.internal import reflection\nfrom hypothesis.internal.cache import LRUCache\n\n# we have several levels of caching for lambda descriptions.\n# * LAMBDA_DESCRIPTION_CACHE maps a lambda f to its description _lambda_description(f).\n#   Note that _lambda_description(f) may not be identical to f as it appears in the\n#   source code file.\n# * LAMBDA_DIGEST_DESCRIPTION_CACHE maps _function_key(f) to _lambda_description(f).\n#   _function_key implements something close to \"ast equality\":\n#   two syntactically identical (minus whitespace etc) lambdas appearing in\n#   different files have the same key. Cache hits here provide a fast path which\n#   avoids ast-parsing syntactic lambdas we've seen before. Two lambdas with the\n#   same _function_key will not have different _lambda_descriptions - if\n#   they do, that's a bug here.\n# * AST_LAMBDAS_CACHE maps source code lines to a list of the lambdas found in\n#   that source code. A cache hit here avoids reparsing the ast.\nLAMBDA_DESCRIPTION_CACHE: MutableMapping[Callable, str] = WeakKeyDictionary()\nLAMBDA_DIGEST_DESCRIPTION_CACHE: LRUCache[tuple[Any], str] = LRUCache(max_size=1000)\nAST_LAMBDAS_CACHE: LRUCache[tuple[str], list[ast.Lambda]] = LRUCache(max_size=100)\n\n\ndef extract_all_lambdas(tree):\n    lambdas = []\n\n    class Visitor(ast.NodeVisitor):\n\n        def visit_Lambda(self, node):\n            lambdas.append(node)\n            self.visit(node.body)\n\n    Visitor().visit(tree)\n    return lambdas\n\n\ndef extract_all_attributes(tree):\n    attributes = []\n\n    class Visitor(ast.NodeVisitor):\n        def visit_Attribute(self, node):\n            attributes.append(node)\n            self.visit(node.value)\n\n    Visitor().visit(tree)\n    return attributes\n\n\ndef _function_key(f, *, bounded_size=False, ignore_name=False):\n    \"\"\"Returns a digest that differentiates functions that have different sources.\n\n    Either a function or a code object may be passed. If code object, default\n    arg/kwarg values are not recoverable - this is the best we can do, and is\n    sufficient for the use case of comparing nested lambdas.\n    \"\"\"\n    try:\n        code = f.__code__\n        defaults_repr = repr((f.__defaults__, f.__kwdefaults__))\n    except AttributeError:\n        code = f\n        defaults_repr = ()\n    consts_repr = repr(code.co_consts)\n    if bounded_size:\n        # Compress repr to avoid keeping arbitrarily large strings pinned as cache\n        # keys. We don't do this unconditionally because hashing takes time, and is\n        # not necessary if the key is used just for comparison (and is not stored).\n        if len(consts_repr) > 48:\n            consts_repr = hashlib.sha384(consts_repr.encode()).digest()\n        if len(defaults_repr) > 48:\n            defaults_repr = hashlib.sha384(defaults_repr.encode()).digest()\n    return (\n        consts_repr,\n        defaults_repr,\n        code.co_argcount,\n        code.co_kwonlyargcount,\n        code.co_code,\n        code.co_names,\n        code.co_varnames,\n        code.co_freevars,\n        ignore_name or code.co_name,\n    )\n\n\nclass _op:\n    # Opcodes, from dis.opmap. These may change between major versions.\n    NOP = 9\n    LOAD_FAST = 85\n    LOAD_FAST_LOAD_FAST = 88\n    LOAD_FAST_BORROW = 86\n    LOAD_FAST_BORROW_LOAD_FAST_BORROW = 87\n\n\ndef _normalize_code(f, l):\n    # A small selection of possible peephole code transformations, based on what\n    # is actually seen to differ between compilations in our test suite. Each\n    # entry contains two equivalent opcode sequences, plus a condition\n    # function called with their respective oparg sequences, which must return\n    # true for the transformation to be valid.\n    Checker = Callable[[list[int], list[int]], bool]\n    transforms: tuple[list[int], list[int], Checker | None] = [\n        ([_op.NOP], [], lambda a, b: True),\n        (\n            [_op.LOAD_FAST, _op.LOAD_FAST],\n            [_op.LOAD_FAST_LOAD_FAST],\n            lambda a, b: a == [b[0] >> 4, b[0] & 15],\n        ),\n        (\n            [_op.LOAD_FAST_BORROW, _op.LOAD_FAST_BORROW],\n            [_op.LOAD_FAST_BORROW_LOAD_FAST_BORROW],\n            lambda a, b: a == [b[0] >> 4, b[0] & 15],\n        ),\n    ]\n    # augment with converse\n    transforms += [\n        (\n            ops_b,\n            ops_a,\n            condition and (lambda a, b, condition=condition: condition(b, a)),\n        )\n        for ops_a, ops_b, condition in transforms\n    ]\n\n    # Normalize equivalent code. We assume that each bytecode op is 2 bytes,\n    # which is the case since Python 3.6. Since the opcodes values may change\n    # between version, there is a risk that a transform may not be equivalent\n    # -- even so, the risk of a bad transform producing a false positive is\n    # minuscule.\n    co_code = list(l.__code__.co_code)\n    f_code = list(f.__code__.co_code)\n\n    def alternating(code, i, n):\n        return code[i : i + 2 * n : 2]\n\n    i = 2\n    while i < max(len(co_code), len(f_code)):\n        # note that co_code is mutated in loop\n        if i < min(len(co_code), len(f_code)) and f_code[i] == co_code[i]:\n            i += 2\n        else:\n            for op1, op2, condition in transforms:\n                if (\n                    op1 == alternating(f_code, i, len(op1))\n                    and op2 == alternating(co_code, i, len(op2))\n                    and condition(\n                        alternating(f_code, i + 1, len(op1)),\n                        alternating(co_code, i + 1, len(op2)),\n                    )\n                ):\n                    break\n            else:\n                # no point in continuing since the bytecodes are different anyway\n                break\n            # Splice in the transform and continue\n            co_code = (\n                co_code[:i] + f_code[i : i + 2 * len(op1)] + co_code[i + 2 * len(op2) :]\n            )\n            i += 2 * len(op1)\n\n    # Normalize consts, in particular replace any lambda consts with the\n    # corresponding const from the template function, IFF they have the same\n    # source key.\n\n    f_consts = f.__code__.co_consts\n    l_consts = l.__code__.co_consts\n    if len(f_consts) == len(l_consts) and any(\n        inspect.iscode(l_const) for l_const in l_consts\n    ):\n        normalized_consts = []\n        for f_const, l_const in zip(f_consts, l_consts, strict=True):\n            if (\n                inspect.iscode(l_const)\n                and inspect.iscode(f_const)\n                and _function_key(f_const) == _function_key(l_const)\n            ):\n                # If the lambdas are compiled from the same source, make them be the\n                # same object so that the toplevel lambdas end up equal. Note that\n                # default arguments are not available on the code objects. But if the\n                # default arguments differ then the lambdas must also differ in other\n                # ways, since default arguments are set up from bytecode and constants.\n                # I.e., this appears to be safe wrt false positives.\n                normalized_consts.append(f_const)\n            else:\n                normalized_consts.append(l_const)\n    else:\n        normalized_consts = l_consts\n\n    return l.__code__.replace(\n        co_code=bytes(co_code),\n        co_consts=tuple(normalized_consts),\n    )\n\n\n_module_map: dict[int, str] = {}\n\n\ndef _mimic_lambda_from_node(f, node):\n    # Compile the source (represented by an ast.Lambda node) in a context that\n    # as far as possible mimics the context that f was compiled in. If - and\n    # only if - this was the source of f then the result is indistinguishable\n    # from f itself (to a casual observer such as _function_key).\n    f_globals = f.__globals__.copy()\n    f_code = f.__code__\n    source = ast.unparse(node)\n\n    # Install values for non-literal argument defaults. Thankfully, these are\n    # always captured by value - so there is no interaction with the closure.\n    if f.__defaults__:\n        for f_default, l_default in zip(\n            f.__defaults__, node.args.defaults, strict=True\n        ):\n            if isinstance(l_default, ast.Name):\n                f_globals[l_default.id] = f_default\n    if f.__kwdefaults__:  # pragma: no cover\n        for l_default, l_varname in zip(\n            node.args.kw_defaults, node.args.kwonlyargs, strict=True\n        ):\n            if isinstance(l_default, ast.Name):\n                f_globals[l_default.id] = f.__kwdefaults__[l_varname.arg]\n\n    # CPython's compiler treats known imports differently than normal globals,\n    # so check if we use attributes from globals that are modules (if so, we\n    # import them explicitly and redundantly in the exec below)\n    referenced_modules = [\n        (local_name, module)\n        for attr in extract_all_attributes(node)\n        if (\n            isinstance(attr.value, ast.Name)\n            and (local_name := attr.value.id)\n            and inspect.ismodule(module := f_globals.get(local_name))\n        )\n    ]\n\n    if not f_code.co_freevars and not referenced_modules:\n        compiled = eval(source, f_globals)\n    else:\n        if f_code.co_freevars:\n            # We have to reconstruct a local closure. The closure will have\n            # the same values as the original function, although this is not\n            # required for source/bytecode equality.\n            f_globals |= {\n                f\"__lc{i}\": c.cell_contents for i, c in enumerate(f.__closure__)\n            }\n            captures = [f\"{name}=__lc{i}\" for i, name in enumerate(f_code.co_freevars)]\n            capture_str = \";\".join(captures) + \";\"\n        else:\n            capture_str = \"\"\n        if referenced_modules:\n            # We add import statements for all referenced modules, since that\n            # influences the compiled code. The assumption is that these modules\n            # were explicitly imported, not assigned, in the source - if not,\n            # this may/will give a different compilation result.\n            global _module_map\n            if len(_module_map) != len(sys.modules):  # pragma: no branch\n                _module_map = {id(module): name for name, module in sys.modules.items()}\n            imports = [\n                (module_name, local_name)\n                for local_name, module in referenced_modules\n                if (module_name := _module_map.get(id(module))) is not None\n            ]\n            import_fragments = [f\"{name} as {asname}\" for name, asname in set(imports)]\n            import_str = f\"import {','.join(import_fragments)}\\n\"\n        else:\n            import_str = \"\"\n        exec_str = (\n            f\"{import_str}def __construct_lambda(): {capture_str} return ({source})\"\n        )\n        exec(exec_str, f_globals)\n        compiled = f_globals[\"__construct_lambda\"]()\n\n    return compiled\n\n\ndef _lambda_code_matches_node(f, node):\n    try:\n        compiled = _mimic_lambda_from_node(f, node)\n    except (NameError, SyntaxError):  # pragma: no cover # source is generated from ast\n        return False\n    if _function_key(f) == _function_key(compiled):\n        return True\n    # Try harder\n    compiled.__code__ = _normalize_code(f, compiled)\n    return _function_key(f) == _function_key(compiled)\n\n\ndef _check_unknown_perfectly_aligned_lambda(candidate):  # pragma: no cover\n    # This is a monkeypatch point for our self-tests, to make unknown\n    # lambdas raise.\n    pass\n\n\ndef _lambda_description(f, leeway=50, *, fail_if_confused_with_perfect_candidate=False):\n    if hasattr(f, \"__wrapped_target\"):\n        f = f.__wrapped_target\n\n    # You might be wondering how a lambda can have a return-type annotation?\n    # The answer is that we add this at runtime, in new_given_signature(),\n    # and we do support strange choices as applying @given() to a lambda.\n    sig = inspect.signature(f)\n    assert sig.return_annotation in (Parameter.empty, None), sig\n\n    # Using pytest-xdist on Python 3.13, there's an entry in the linecache for\n    # file \"<string>\", which then returns nonsense to getsource.  Discard it.\n    linecache.cache.pop(\"<string>\", None)\n\n    def format_lambda(body):\n        # The signature is more informative than the corresponding ast.unparse\n        # output in the case of default argument values, so add the signature\n        # to the unparsed body\n        return (\n            f\"lambda {str(sig)[1:-1]}: {body}\" if sig.parameters else f\"lambda: {body}\"\n        )\n\n    if_confused = format_lambda(\"<unknown>\")\n\n    try:\n        source_lines, lineno0 = inspect.findsource(f)\n        source_lines = tuple(source_lines)  # make it hashable\n    except OSError:\n        return if_confused\n\n    try:\n        all_lambdas = AST_LAMBDAS_CACHE[source_lines]\n    except KeyError:\n        # The source isn't already parsed, so we try to shortcut by parsing just\n        # the local block. If that fails to produce a code-identical lambda,\n        # fall through to the full parse.\n        local_lines = inspect.getblock(source_lines[lineno0:])\n        local_block = textwrap.dedent(\"\".join(local_lines))\n        # The fairly common \".map(lambda x: ...)\" case. This partial block\n        # isn't valid syntax, but it might be if we remove the leading \".\".\n        local_block = local_block.removeprefix(\".\")\n\n        try:\n            local_tree = ast.parse(local_block)\n        except SyntaxError:\n            pass\n        else:\n            local_lambdas = extract_all_lambdas(local_tree)\n            for candidate in local_lambdas:\n                if reflection.ast_arguments_matches_signature(\n                    candidate.args, sig\n                ) and _lambda_code_matches_node(f, candidate):\n                    return format_lambda(ast.unparse(candidate.body))\n\n        # Local parse failed or didn't produce a match, go ahead with the full parse\n        try:\n            tree = ast.parse(\"\".join(source_lines))\n        except SyntaxError:\n            all_lambdas = []\n        else:\n            all_lambdas = extract_all_lambdas(tree)\n        AST_LAMBDAS_CACHE[source_lines] = all_lambdas\n\n    aligned_lambdas = []\n    for candidate in all_lambdas:\n        if (\n            candidate.lineno - leeway <= lineno0 + 1 <= candidate.lineno + leeway\n            and reflection.ast_arguments_matches_signature(candidate.args, sig)\n        ):\n            aligned_lambdas.append(candidate)\n\n    aligned_lambdas.sort(key=lambda c: abs(lineno0 + 1 - c.lineno))\n    for candidate in aligned_lambdas:\n        if _lambda_code_matches_node(f, candidate):\n            return format_lambda(ast.unparse(candidate.body))\n\n    # None of the aligned lambdas match perfectly in generated code.\n    if aligned_lambdas and aligned_lambdas[0].lineno == lineno0 + 1:\n        _check_unknown_perfectly_aligned_lambda(aligned_lambdas[0])\n\n    return if_confused\n\n\ndef lambda_description(f):\n    \"\"\"\n    Returns a syntactically-valid expression describing `f`. This is often, but\n    not always, the exact lambda definition string which appears in the source code.\n    The difference comes from parsing the lambda ast into `tree` and then returning\n    the result of `ast.unparse(tree)`, which may differ in whitespace, double vs\n    single quotes, etc.\n\n    Returns a string indicating an unknown body if the parsing gets confused in any way.\n    \"\"\"\n    try:\n        return LAMBDA_DESCRIPTION_CACHE[f]\n    except KeyError:\n        pass\n\n    key = _function_key(f, bounded_size=True)\n    location = (f.__code__.co_filename, f.__code__.co_firstlineno)\n    try:\n        description, failed_locations = LAMBDA_DIGEST_DESCRIPTION_CACHE[key]\n    except KeyError:\n        failed_locations = set()\n    else:\n        # We got a hit in the digests cache, but only use it if either it has\n        # a good (known) description, or if it is unknown but we already tried\n        # to parse its exact source location before.\n        if \"<unknown>\" not in description or location in failed_locations:\n            # use the cached result\n            LAMBDA_DESCRIPTION_CACHE[f] = description\n            return description\n\n    description = _lambda_description(f)\n    LAMBDA_DESCRIPTION_CACHE[f] = description\n    if \"<unknown>\" in description:\n        failed_locations.add(location)\n    else:\n        failed_locations.clear()  # we have a good description now\n    LAMBDA_DIGEST_DESCRIPTION_CACHE[key] = description, failed_locations\n    return description\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/observability.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"Observability tools to spit out analysis-ready tables, one row per test case.\"\"\"\n\nimport base64\nimport dataclasses\nimport json\nimport math\nimport os\nimport sys\nimport threading\nimport time\nimport warnings\nfrom collections.abc import Callable, Generator\nfrom contextlib import contextmanager\nfrom dataclasses import dataclass\nfrom datetime import date, timedelta\nfrom functools import lru_cache\nfrom threading import Lock\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    Literal,\n    Optional,\n    TypeAlias,\n    Union,\n    cast,\n)\n\nfrom hypothesis.configuration import storage_directory\nfrom hypothesis.errors import HypothesisWarning\nfrom hypothesis.internal.conjecture.choice import (\n    BooleanConstraints,\n    BytesConstraints,\n    ChoiceConstraintsT,\n    ChoiceNode,\n    ChoiceT,\n    ChoiceTypeT,\n    FloatConstraints,\n    IntegerConstraints,\n    StringConstraints,\n)\nfrom hypothesis.internal.escalation import InterestingOrigin\nfrom hypothesis.internal.floats import float_to_int\nfrom hypothesis.internal.intervalsets import IntervalSet\nfrom hypothesis.utils.deprecation import note_deprecation\n\nif TYPE_CHECKING:\n    from hypothesis.internal.conjecture.data import ConjectureData, Spans, Status\n\n\nObservation: TypeAlias = Union[\"InfoObservation\", \"TestCaseObservation\"]\nCallbackThreadT: TypeAlias = Callable[[Observation], None]\n# for all_threads=True, we pass the thread id as well.\nCallbackAllThreadsT: TypeAlias = Callable[[Observation, int], None]\nCallbackT: TypeAlias = CallbackThreadT | CallbackAllThreadsT\n\n# thread_id: list[callback]\n_callbacks: dict[int | None, list[CallbackThreadT]] = {}\n# callbacks where all_threads=True was set\n_callbacks_all_threads: list[CallbackAllThreadsT] = []\n\n\n@dataclass(slots=True, frozen=False)\nclass PredicateCounts:\n    satisfied: int = 0\n    unsatisfied: int = 0\n\n    def update_count(self, *, condition: bool) -> None:\n        if condition:\n            self.satisfied += 1\n        else:\n            self.unsatisfied += 1\n\n\ndef _choice_to_json(choice: ChoiceT | None) -> Any:\n    if choice is None:\n        return None\n    # see the note on the same check in to_jsonable for why we cast large\n    # integers to floats.\n    if (\n        isinstance(choice, int)\n        and not isinstance(choice, bool)\n        and abs(choice) >= 2**63\n    ):\n        return [\"integer\", str(choice)]\n    elif isinstance(choice, bytes):\n        return [\"bytes\", base64.b64encode(choice).decode()]\n    elif isinstance(choice, float) and math.isnan(choice):\n        # handle nonstandard nan bit patterns. We don't need to do this for -0.0\n        # vs 0.0 since json doesn't normalize -0.0 to 0.0.\n        return [\"float\", float_to_int(choice)]\n    return choice\n\n\ndef choices_to_json(choices: tuple[ChoiceT, ...]) -> list[Any]:\n    return [_choice_to_json(choice) for choice in choices]\n\n\ndef _constraints_to_json(\n    choice_type: ChoiceTypeT, constraints: ChoiceConstraintsT\n) -> dict[str, Any]:\n    constraints = constraints.copy()\n    if choice_type == \"integer\":\n        constraints = cast(IntegerConstraints, constraints)\n        return {\n            \"min_value\": _choice_to_json(constraints[\"min_value\"]),\n            \"max_value\": _choice_to_json(constraints[\"max_value\"]),\n            \"weights\": (\n                None\n                if constraints[\"weights\"] is None\n                # wrap up in a list, instead of a dict, because json dicts\n                # require string keys\n                else [\n                    (_choice_to_json(k), v) for k, v in constraints[\"weights\"].items()\n                ]\n            ),\n            \"shrink_towards\": _choice_to_json(constraints[\"shrink_towards\"]),\n        }\n    elif choice_type == \"float\":\n        constraints = cast(FloatConstraints, constraints)\n        return {\n            \"min_value\": _choice_to_json(constraints[\"min_value\"]),\n            \"max_value\": _choice_to_json(constraints[\"max_value\"]),\n            \"allow_nan\": constraints[\"allow_nan\"],\n            \"smallest_nonzero_magnitude\": constraints[\"smallest_nonzero_magnitude\"],\n        }\n    elif choice_type == \"string\":\n        constraints = cast(StringConstraints, constraints)\n        assert isinstance(constraints[\"intervals\"], IntervalSet)\n        return {\n            \"intervals\": constraints[\"intervals\"].intervals,\n            \"min_size\": _choice_to_json(constraints[\"min_size\"]),\n            \"max_size\": _choice_to_json(constraints[\"max_size\"]),\n        }\n    elif choice_type == \"bytes\":\n        constraints = cast(BytesConstraints, constraints)\n        return {\n            \"min_size\": _choice_to_json(constraints[\"min_size\"]),\n            \"max_size\": _choice_to_json(constraints[\"max_size\"]),\n        }\n    elif choice_type == \"boolean\":\n        constraints = cast(BooleanConstraints, constraints)\n        return {\n            \"p\": constraints[\"p\"],\n        }\n    else:\n        raise NotImplementedError(f\"unknown choice type {choice_type}\")\n\n\ndef nodes_to_json(nodes: tuple[ChoiceNode, ...]) -> list[dict[str, Any]]:\n    return [\n        {\n            \"type\": node.type,\n            \"value\": _choice_to_json(node.value),\n            \"constraints\": _constraints_to_json(node.type, node.constraints),\n            \"was_forced\": node.was_forced,\n        }\n        for node in nodes\n    ]\n\n\n@dataclass(slots=True, frozen=True)\nclass ObservationMetadata:\n    traceback: str | None\n    reproduction_decorator: str | None\n    predicates: dict[str, PredicateCounts]\n    backend: dict[str, Any]\n    sys_argv: list[str]\n    os_getpid: int\n    imported_at: float\n    data_status: \"Status\"\n    phase: str\n    interesting_origin: InterestingOrigin | None\n    choice_nodes: tuple[ChoiceNode, ...] | None\n    choice_spans: Optional[\"Spans\"]\n\n    def to_json(self) -> dict[str, Any]:\n        data = {\n            \"traceback\": self.traceback,\n            \"reproduction_decorator\": self.reproduction_decorator,\n            \"predicates\": self.predicates,\n            \"backend\": self.backend,\n            \"sys.argv\": self.sys_argv,\n            \"os.getpid()\": self.os_getpid,\n            \"imported_at\": self.imported_at,\n            \"data_status\": self.data_status,\n            \"phase\": self.phase,\n            \"interesting_origin\": self.interesting_origin,\n            \"choice_nodes\": (\n                None if self.choice_nodes is None else nodes_to_json(self.choice_nodes)\n            ),\n            \"choice_spans\": (\n                None\n                if self.choice_spans is None\n                else [\n                    (\n                        # span.label is an int, but cast to string to avoid conversion\n                        # to float (and loss of precision) for large label values.\n                        #\n                        # The value of this label is opaque to consumers anyway, so its\n                        # type shouldn't matter as long as it's consistent.\n                        str(span.label),\n                        span.start,\n                        span.end,\n                        span.discarded,\n                    )\n                    for span in self.choice_spans\n                ]\n            ),\n        }\n        # check that we didn't forget one\n        assert len(data) == len(dataclasses.fields(self))\n        return data\n\n\n@dataclass(slots=True, frozen=True)\nclass BaseObservation:\n    type: Literal[\"test_case\", \"info\", \"alert\", \"error\"]\n    property: str\n    run_start: float\n\n\nInfoObservationType = Literal[\"info\", \"alert\", \"error\"]\nTestCaseStatus = Literal[\"gave_up\", \"passed\", \"failed\"]\n\n\n@dataclass(slots=True, frozen=True)\nclass InfoObservation(BaseObservation):\n    type: InfoObservationType\n    title: str\n    content: str | dict\n\n\n@dataclass(slots=True, frozen=True)\nclass TestCaseObservation(BaseObservation):\n    __test__ = False  # no! bad pytest!\n\n    type: Literal[\"test_case\"]\n    status: TestCaseStatus\n    status_reason: str\n    representation: str\n    arguments: dict\n    how_generated: str\n    features: dict\n    coverage: dict[str, list[int]] | None\n    timing: dict[str, float]\n    metadata: ObservationMetadata\n\n\ndef add_observability_callback(f: CallbackT, /, *, all_threads: bool = False) -> None:\n    \"\"\"\n    Adds ``f`` as a callback for :ref:`observability <observability>`. ``f``\n    should accept one argument, which is an observation. Whenever Hypothesis\n    produces a new observation, it calls each callback with that observation.\n\n    If Hypothesis tests are being run from multiple threads, callbacks are tracked\n    per-thread. In other words, ``add_observability_callback(f)`` only adds ``f``\n    as an observability callback for observations produced on that thread.\n\n    If ``all_threads=True`` is passed, ``f`` will instead be registered as a\n    callback for all threads. This means it will be called for observations\n    generated by all threads, not just the thread which registered ``f`` as a\n    callback. In this case, ``f`` will be passed two arguments: the first is the\n    observation, and the second is the integer thread id from\n    :func:`python:threading.get_ident` where that observation was generated.\n\n    We recommend against registering ``f`` as a callback for both ``all_threads=True``\n    and the default ``all_threads=False``, due to unclear semantics with\n    |remove_observability_callback|.\n    \"\"\"\n    if all_threads:\n        _callbacks_all_threads.append(cast(CallbackAllThreadsT, f))\n        return\n\n    thread_id = threading.get_ident()\n    if thread_id not in _callbacks:\n        _callbacks[thread_id] = []\n\n    _callbacks[thread_id].append(cast(CallbackThreadT, f))\n\n\ndef remove_observability_callback(f: CallbackT, /) -> None:\n    \"\"\"\n    Removes ``f`` from the :ref:`observability <observability>` callbacks.\n\n    If ``f`` is not in the list of observability callbacks, silently do nothing.\n\n    If running under multiple threads, ``f`` will only be removed from the\n    callbacks for this thread.\n    \"\"\"\n    if f in _callbacks_all_threads:\n        _callbacks_all_threads.remove(cast(CallbackAllThreadsT, f))\n\n    thread_id = threading.get_ident()\n    if thread_id not in _callbacks:\n        return\n\n    callbacks = _callbacks[thread_id]\n    if f in callbacks:\n        callbacks.remove(cast(CallbackThreadT, f))\n\n    if not callbacks:\n        del _callbacks[thread_id]\n\n\ndef observability_enabled() -> bool:\n    \"\"\"\n    Returns whether or not Hypothesis considers :ref:`observability <observability>`\n    to be enabled. Observability is enabled if there is at least one observability\n    callback present.\n\n    Callers might use this method to determine whether they should compute an\n    expensive representation that is only used under observability, for instance\n    by |alternative backends|.\n    \"\"\"\n    return bool(_callbacks) or bool(_callbacks_all_threads)\n\n\n@contextmanager\ndef with_observability_callback(\n    f: Callable[[Observation], None], /, *, all_threads: bool = False\n) -> Generator[None, None, None]:\n    \"\"\"\n    A simple context manager which calls |add_observability_callback| on ``f``\n    when it enters and |remove_observability_callback| on ``f`` when it exits.\n    \"\"\"\n    add_observability_callback(f, all_threads=all_threads)\n    try:\n        yield\n    finally:\n        remove_observability_callback(f)\n\n\ndef deliver_observation(observation: Observation) -> None:\n    thread_id = threading.get_ident()\n\n    for callback in _callbacks.get(thread_id, []):\n        callback(observation)\n\n    for callback in _callbacks_all_threads:\n        callback(observation, thread_id)\n\n\nclass _TestcaseCallbacks:\n    def __bool__(self):\n        self._note_deprecation()\n        return bool(_callbacks)\n\n    def _note_deprecation(self):\n        note_deprecation(\n            \"hypothesis.internal.observability.TESTCASE_CALLBACKS is deprecated. \"\n            \"Replace TESTCASE_CALLBACKS.append with add_observability_callback, \"\n            \"TESTCASE_CALLBACKS.remove with remove_observability_callback, and \"\n            \"bool(TESTCASE_CALLBACKS) with observability_enabled().\",\n            since=\"2025-08-01\",\n            has_codemod=False,\n        )\n\n    def append(self, f):\n        self._note_deprecation()\n        add_observability_callback(f)\n\n    def remove(self, f):\n        self._note_deprecation()\n        remove_observability_callback(f)\n\n\n#: .. warning::\n#:\n#:   Deprecated in favor of |add_observability_callback|,\n#:   |remove_observability_callback|, and |observability_enabled|.\n#:\n#:   |TESTCASE_CALLBACKS| remains a thin compatibility\n#:   shim which forwards ``.append``, ``.remove``, and ``bool()`` to those\n#:   three methods. It is not an attempt to be fully compatible with the previous\n#:   ``TESTCASE_CALLBACKS = []``, so iteration or other usages will not work\n#:   anymore. Please update to using the new methods instead.\n#:\n#:   |TESTCASE_CALLBACKS| will eventually be removed.\nTESTCASE_CALLBACKS = _TestcaseCallbacks()\n\n\ndef make_testcase(\n    *,\n    run_start: float,\n    property: str,\n    data: \"ConjectureData\",\n    how_generated: str,\n    representation: str = \"<unknown>\",\n    timing: dict[str, float],\n    arguments: dict | None = None,\n    coverage: dict[str, list[int]] | None = None,\n    phase: str | None = None,\n    backend_metadata: dict[str, Any] | None = None,\n    status: (\n        Union[TestCaseStatus, \"Status\"] | None\n    ) = None,  # overrides automatic calculation\n    status_reason: str | None = None,  # overrides automatic calculation\n    # added to calculated metadata. If keys overlap, the value from this `metadata`\n    # is used\n    metadata: dict[str, Any] | None = None,\n) -> TestCaseObservation:\n    from hypothesis.core import reproduction_decorator\n    from hypothesis.internal.conjecture.data import Status\n\n    # We should only be sending observability reports for datas that have finished\n    # being modified.\n    assert data.frozen\n\n    if status_reason is not None:\n        pass\n    elif data.interesting_origin:\n        status_reason = str(data.interesting_origin)\n    elif phase == \"shrink\" and data.status == Status.OVERRUN:\n        status_reason = \"exceeded size of current best example\"\n    else:\n        status_reason = str(data.events.pop(\"invalid because\", \"\"))\n\n    status_map: dict[Status, TestCaseStatus] = {\n        Status.OVERRUN: \"gave_up\",\n        Status.INVALID: \"gave_up\",\n        Status.VALID: \"passed\",\n        Status.INTERESTING: \"failed\",\n    }\n\n    if status is not None and isinstance(status, Status):\n        status = status_map[status]\n    if status is None:\n        status = status_map[data.status]\n\n    return TestCaseObservation(\n        type=\"test_case\",\n        status=status,\n        status_reason=status_reason,\n        representation=representation,\n        arguments={\n            k.removeprefix(\"generate:\"): v for k, v in (arguments or {}).items()\n        },\n        how_generated=how_generated,  # iid, mutation, etc.\n        features={\n            **{\n                f\"target:{k}\".strip(\":\"): v for k, v in data.target_observations.items()\n            },\n            **data.events,\n        },\n        coverage=coverage,\n        timing=timing,\n        metadata=ObservationMetadata(\n            **{\n                \"traceback\": data.expected_traceback,\n                \"reproduction_decorator\": (\n                    reproduction_decorator(data.choices) if status == \"failed\" else None\n                ),\n                \"predicates\": dict(data._observability_predicates),\n                \"backend\": backend_metadata or {},\n                \"data_status\": data.status,\n                \"phase\": phase,\n                \"interesting_origin\": data.interesting_origin,\n                \"choice_nodes\": data.nodes if OBSERVABILITY_CHOICES else None,\n                \"choice_spans\": data.spans if OBSERVABILITY_CHOICES else None,\n                **_system_metadata(),\n                # unpack last so it takes precedence for duplicate keys\n                **(metadata or {}),\n            }\n        ),\n        run_start=run_start,\n        property=property,\n    )\n\n\n_WROTE_TO = set()\n_deliver_to_file_lock = Lock()\n\n\ndef _deliver_to_file(\n    observation: Observation, thread_id: int\n) -> None:  # pragma: no cover\n    from hypothesis.strategies._internal.utils import to_jsonable\n\n    kind = \"testcases\" if observation.type == \"test_case\" else \"info\"\n    fname = storage_directory(\"observed\", f\"{date.today().isoformat()}_{kind}.jsonl\")\n    fname.parent.mkdir(exist_ok=True, parents=True)\n\n    observation_bytes = (\n        json.dumps(to_jsonable(observation, avoid_realization=False)) + \"\\n\"\n    )\n    # only allow one conccurent file write to avoid write races. This is likely to make\n    # HYPOTHESIS_EXPERIMENTAL_OBSERVABILITY quite slow under threading. A queue\n    # would be an improvement, but that requires a background thread, and I\n    # would prefer to avoid a thread in the single-threaded case. We could\n    # switch over to a queue if we detect multithreading, but it's tricky to get\n    # right.\n    with _deliver_to_file_lock:\n        _WROTE_TO.add(fname)\n        with fname.open(mode=\"a\") as f:\n            f.write(observation_bytes)\n\n\n_imported_at = time.time()\n\n\n@lru_cache\ndef _system_metadata() -> dict[str, Any]:\n    return {\n        \"sys_argv\": sys.argv,\n        \"os_getpid\": os.getpid(),\n        \"imported_at\": _imported_at,\n    }\n\n\n#: If ``False``, do not collect coverage information when observability is enabled.\n#:\n#: This is exposed both for performance (as coverage collection can be slow on\n#: Python 3.11 and earlier) and size (if you do not use coverage information,\n#: you may not want to store it in-memory).\nOBSERVABILITY_COLLECT_COVERAGE = (\n    \"HYPOTHESIS_EXPERIMENTAL_OBSERVABILITY_NOCOVER\" not in os.environ\n)\n#: If ``True``, include the ``metadata.choice_nodes`` and ``metadata.spans`` keys\n#: in test case observations.\n#:\n#: ``False`` by default. ``metadata.choice_nodes`` and ``metadata.spans`` can be\n#: a substantial amount of data, and so must be opted-in to, even when\n#: observability is enabled.\n#:\n#: .. warning::\n#:\n#:     EXPERIMENTAL AND UNSTABLE. We are actively working towards a better\n#:     interface for this as of June 2025, and this attribute may disappear or\n#:     be renamed without notice.\n#:\nOBSERVABILITY_CHOICES = \"HYPOTHESIS_EXPERIMENTAL_OBSERVABILITY_CHOICES\" in os.environ\n\nif OBSERVABILITY_COLLECT_COVERAGE is False and (\n    sys.version_info[:2] >= (3, 12)\n):  # pragma: no cover\n    warnings.warn(\n        \"Coverage data collection should be quite fast in Python 3.12 or later \"\n        \"so there should be no need to turn coverage reporting off.\",\n        HypothesisWarning,\n        stacklevel=2,\n    )\n\nif (\n    \"HYPOTHESIS_EXPERIMENTAL_OBSERVABILITY\" in os.environ\n    or OBSERVABILITY_COLLECT_COVERAGE is False\n):  # pragma: no cover\n    add_observability_callback(_deliver_to_file, all_threads=True)\n\n    # Remove files more than a week old, to cap the size on disk\n    max_age = (date.today() - timedelta(days=8)).isoformat()\n    for f in storage_directory(\"observed\", intent_to_write=False).glob(\"*.jsonl\"):\n        if f.stem < max_age:  # pragma: no branch\n            f.unlink(missing_ok=True)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/reflection.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"This file can approximately be considered the collection of hypothesis going\nto really unreasonable lengths to produce pretty output.\"\"\"\n\nimport ast\nimport hashlib\nimport inspect\nimport re\nimport textwrap\nimport types\nimport warnings\nfrom collections.abc import Callable, Sequence\nfrom functools import partial, wraps\nfrom inspect import Parameter, Signature\nfrom io import StringIO\nfrom keyword import iskeyword\nfrom random import _inst as global_random_instance\nfrom tokenize import COMMENT, generate_tokens, untokenize\nfrom types import EllipsisType, ModuleType\nfrom typing import TYPE_CHECKING, Any, TypeVar, Union\nfrom unittest.mock import _patch as PatchType\n\nfrom hypothesis.errors import HypothesisWarning\nfrom hypothesis.internal import lambda_sources\nfrom hypothesis.internal.compat import is_typed_named_tuple\nfrom hypothesis.utils.conventions import not_set\nfrom hypothesis.vendor.pretty import pretty\n\nif TYPE_CHECKING:\n    from hypothesis.strategies._internal.strategies import SearchStrategy\n\nT = TypeVar(\"T\")\n\n\ndef is_mock(obj: object) -> bool:\n    \"\"\"Determine if the given argument is a mock type.\"\"\"\n\n    # We want to be able to detect these when dealing with various test\n    # args. As they are sneaky and can look like almost anything else,\n    # we'll check this by looking for an attribute with a name that it's really\n    # unlikely to implement accidentally, and that anyone who implements it\n    # deliberately should know what they're doing. This is more robust than\n    # looking for types.\n    return hasattr(obj, \"hypothesis_internal_is_this_a_mock_check\")\n\n\ndef _clean_source(src: str) -> bytes:\n    \"\"\"Return the source code as bytes, without decorators or comments.\n\n    Because this is part of our database key, we reduce the cache invalidation\n    rate by ignoring decorators, comments, trailing whitespace, and empty lines.\n    We can't just use the (dumped) AST directly because it changes between Python\n    versions (e.g. ast.Constant)\n    \"\"\"\n    # Get the (one-indexed) line number of the function definition, and drop preceding\n    # lines - i.e. any decorators, so that adding `@example()`s keeps the same key.\n    try:\n        funcdef = ast.parse(src).body[0]\n        src = \"\".join(src.splitlines(keepends=True)[funcdef.lineno - 1 :])\n    except Exception:\n        pass\n    # Remove blank lines and use the tokenize module to strip out comments,\n    # so that those can be changed without changing the database key.\n    try:\n        src = untokenize(\n            t for t in generate_tokens(StringIO(src).readline) if t.type != COMMENT\n        )\n    except Exception:\n        pass\n    # Finally, remove any trailing whitespace and empty lines as a last cleanup.\n    return \"\\n\".join(x.rstrip() for x in src.splitlines() if x.rstrip()).encode()\n\n\ndef function_digest(function: Any) -> bytes:\n    \"\"\"Returns a string that is stable across multiple invocations across\n    multiple processes and is prone to changing significantly in response to\n    minor changes to the function.\n\n    No guarantee of uniqueness though it usually will be. Digest collisions\n    lead to unfortunate but not fatal problems during database replay.\n    \"\"\"\n    hasher = hashlib.sha384()\n    try:\n        src = inspect.getsource(function)\n    except (OSError, TypeError):\n        # If we can't actually get the source code, try for the name as a fallback.\n        # NOTE: We might want to change this to always adding function.__qualname__,\n        # to differentiate f.x. two classes having the same function implementation\n        # with class-dependent behaviour.\n        try:\n            hasher.update(function.__name__.encode())\n        except AttributeError:\n            pass\n    else:\n        hasher.update(_clean_source(src))\n    try:\n        # This is additional to the source code because it can include the effects\n        # of decorators, or of post-hoc assignment to the .__signature__ attribute.\n        hasher.update(repr(get_signature(function)).encode())\n    except Exception:\n        pass\n    try:\n        # We set this in order to distinguish e.g. @pytest.mark.parametrize cases.\n        hasher.update(function._hypothesis_internal_add_digest)\n    except AttributeError:\n        pass\n    return hasher.digest()\n\n\ndef check_signature(sig: Signature) -> None:  # pragma: no cover  # 3.10 only\n    # Backport from Python 3.11; see https://github.com/python/cpython/pull/92065\n    for p in sig.parameters.values():\n        if iskeyword(p.name) and p.kind is not p.POSITIONAL_ONLY:\n            raise ValueError(\n                f\"Signature {sig!r} contains a parameter named {p.name!r}, \"\n                f\"but this is a SyntaxError because `{p.name}` is a keyword. \"\n                \"You, or a library you use, must have manually created an \"\n                \"invalid signature - this will be an error in Python 3.11+\"\n            )\n\n\ndef get_signature(\n    target: Any, *, follow_wrapped: bool = True, eval_str: bool = False\n) -> Signature:\n    # Special case for use of `@unittest.mock.patch` decorator, mimicking the\n    # behaviour of getfullargspec instead of reporting unusable arguments.\n    patches = getattr(target, \"patchings\", None)\n    if isinstance(patches, list) and all(isinstance(p, PatchType) for p in patches):\n        return Signature(\n            [\n                Parameter(\"args\", Parameter.VAR_POSITIONAL),\n                Parameter(\"keywargs\", Parameter.VAR_KEYWORD),\n            ]\n        )\n\n    if isinstance(getattr(target, \"__signature__\", None), Signature):\n        # This special case covers unusual codegen like Pydantic models\n        sig = target.__signature__\n        check_signature(sig)\n        # And *this* much more complicated block ignores the `self` argument\n        # if that's been (incorrectly) included in the custom signature.\n        if sig.parameters and (inspect.isclass(target) or inspect.ismethod(target)):\n            selfy = next(iter(sig.parameters.values()))\n            if (\n                selfy.name == \"self\"\n                and selfy.default is Parameter.empty\n                and selfy.kind.name.startswith(\"POSITIONAL_\")\n            ):\n                return sig.replace(\n                    parameters=[v for k, v in sig.parameters.items() if k != \"self\"]\n                )\n        return sig\n    sig = inspect.signature(target, follow_wrapped=follow_wrapped, eval_str=eval_str)\n    check_signature(sig)\n    return sig\n\n\ndef arg_is_required(param: Parameter) -> bool:\n    return param.default is Parameter.empty and param.kind in (\n        Parameter.POSITIONAL_OR_KEYWORD,\n        Parameter.KEYWORD_ONLY,\n    )\n\n\ndef required_args(\n    target: Callable[..., Any],\n    args: tuple[\"SearchStrategy[Any]\", ...] = (),\n    kwargs: dict[str, Union[\"SearchStrategy[Any]\", EllipsisType]] | None = None,\n) -> set[str]:\n    \"\"\"Return a set of names of required args to target that were not supplied\n    in args or kwargs.\n\n    This is used in builds() to determine which arguments to attempt to\n    fill from type hints.  target may be any callable (including classes\n    and bound methods).  args and kwargs should be as they are passed to\n    builds() - that is, a tuple of values and a dict of names: values.\n    \"\"\"\n    kwargs = {} if kwargs is None else kwargs\n    # We start with a workaround for NamedTuples, which don't have nice inits\n    if inspect.isclass(target) and is_typed_named_tuple(target):\n        provided = set(kwargs) | set(target._fields[: len(args)])\n        return set(target._fields) - provided\n    # Then we try to do the right thing with inspect.signature\n    try:\n        sig = get_signature(target)\n    except (ValueError, TypeError):\n        return set()\n    return {\n        name\n        for name, param in list(sig.parameters.items())[len(args) :]\n        if arg_is_required(param) and name not in kwargs\n    }\n\n\ndef convert_keyword_arguments(\n    function: Any, args: Sequence[object], kwargs: dict[str, object]\n) -> tuple[tuple[object, ...], dict[str, object]]:\n    \"\"\"Returns a pair of a tuple and a dictionary which would be equivalent\n    passed as positional and keyword args to the function. Unless function has\n    kwonlyargs or **kwargs the dictionary will always be empty.\n    \"\"\"\n    sig = inspect.signature(function, follow_wrapped=False)\n    bound = sig.bind(*args, **kwargs)\n    return bound.args, bound.kwargs\n\n\ndef convert_positional_arguments(\n    function: Any, args: Sequence[object], kwargs: dict[str, object]\n) -> tuple[tuple[object, ...], dict[str, object]]:\n    \"\"\"Return a tuple (new_args, new_kwargs) where all possible arguments have\n    been moved to kwargs.\n\n    new_args will only be non-empty if function has pos-only args or *args.\n    \"\"\"\n    sig = inspect.signature(function, follow_wrapped=False)\n    bound = sig.bind(*args, **kwargs)\n    new_args = []\n    new_kwargs = dict(bound.arguments)\n    for p in sig.parameters.values():\n        if p.name in new_kwargs:\n            if p.kind is p.POSITIONAL_ONLY:\n                new_args.append(new_kwargs.pop(p.name))\n            elif p.kind is p.VAR_POSITIONAL:\n                new_args.extend(new_kwargs.pop(p.name))\n            elif p.kind is p.VAR_KEYWORD:\n                assert set(new_kwargs[p.name]).isdisjoint(set(new_kwargs) - {p.name})\n                new_kwargs.update(new_kwargs.pop(p.name))\n    return tuple(new_args), new_kwargs\n\n\ndef ast_arguments_matches_signature(args: ast.arguments, sig: Signature) -> bool:\n    expected: list[tuple[str, int]] = []\n    for node in args.posonlyargs:\n        expected.append((node.arg, Parameter.POSITIONAL_ONLY))\n    for node in args.args:\n        expected.append((node.arg, Parameter.POSITIONAL_OR_KEYWORD))\n    if args.vararg is not None:\n        expected.append((args.vararg.arg, Parameter.VAR_POSITIONAL))\n    for node in args.kwonlyargs:\n        expected.append((node.arg, Parameter.KEYWORD_ONLY))\n    if args.kwarg is not None:\n        expected.append((args.kwarg.arg, Parameter.VAR_KEYWORD))\n    return expected == [(p.name, p.kind) for p in sig.parameters.values()]\n\n\ndef is_first_param_referenced_in_function(f: Any) -> bool:\n    \"\"\"Is the given name referenced within f?\"\"\"\n    try:\n        tree = ast.parse(textwrap.dedent(inspect.getsource(f)))\n    except Exception:\n        return True  # Assume it's OK unless we know otherwise\n    name = next(iter(get_signature(f).parameters))\n    return any(\n        isinstance(node, ast.Name)\n        and node.id == name\n        and isinstance(node.ctx, ast.Load)\n        for node in ast.walk(tree)\n    )\n\n\ndef get_pretty_function_description(f: object) -> str:\n    if isinstance(f, partial):\n        return pretty(f)\n    if not hasattr(f, \"__name__\"):\n        return repr(f)\n    name = f.__name__  # type: ignore\n    if name == \"<lambda>\":\n        return lambda_sources.lambda_description(f)\n    elif isinstance(f, (types.MethodType, types.BuiltinMethodType)):\n        self = f.__self__\n        # Some objects, like `builtins.abs` are of BuiltinMethodType but have\n        # their module as __self__.  This might include c-extensions generally?\n        if not (self is None or inspect.isclass(self) or inspect.ismodule(self)):\n            if self is global_random_instance:\n                return f\"random.{name}\"\n            return f\"{self!r}.{name}\"\n    elif isinstance(name, str) and getattr(dict, name, object()) is f:\n        # special case for keys/values views in from_type() / ghostwriter output\n        return f\"dict.{name}\"\n    return name\n\n\ndef nicerepr(v: Any) -> str:\n    if inspect.isfunction(v):\n        return get_pretty_function_description(v)\n    elif isinstance(v, type):\n        return v.__name__\n    else:\n        # With TypeVar T, show List[T] instead of TypeError on List[~T]\n        return re.sub(r\"(\\[)~([A-Z][a-z]*\\])\", r\"\\g<1>\\g<2>\", pretty(v))\n\n\ndef repr_call(\n    f: Any, args: Sequence[object], kwargs: dict[str, object], *, reorder: bool = True\n) -> str:\n    # Note: for multi-line pretty-printing, see RepresentationPrinter.repr_call()\n    if reorder:\n        args, kwargs = convert_positional_arguments(f, args, kwargs)\n\n    bits = [nicerepr(x) for x in args]\n\n    for p in get_signature(f).parameters.values():\n        if p.name in kwargs and not p.kind.name.startswith(\"VAR_\"):\n            bits.append(f\"{p.name}={nicerepr(kwargs.pop(p.name))}\")\n    if kwargs:\n        for a in sorted(kwargs):\n            bits.append(f\"{a}={nicerepr(kwargs[a])}\")\n\n    rep = nicerepr(f)\n    if rep.startswith(\"lambda\") and \":\" in rep:\n        rep = f\"({rep})\"\n    repr_len = len(rep) + sum(len(b) for b in bits)  # approx\n    if repr_len > 30000:\n        warnings.warn(\n            \"Generating overly large repr. This is an expensive operation, and with \"\n            f\"a length of {repr_len//1000} kB is unlikely to be useful. Use -Wignore \"\n            \"to ignore the warning, or -Werror to get a traceback.\",\n            HypothesisWarning,\n            stacklevel=2,\n        )\n    return rep + \"(\" + \", \".join(bits) + \")\"\n\n\ndef check_valid_identifier(identifier: str) -> None:\n    if not identifier.isidentifier():\n        raise ValueError(f\"{identifier!r} is not a valid python identifier\")\n\n\neval_cache: dict[str, ModuleType] = {}\n\n\ndef source_exec_as_module(source: str) -> ModuleType:\n    try:\n        return eval_cache[source]\n    except KeyError:\n        pass\n\n    hexdigest = hashlib.sha384(source.encode()).hexdigest()\n    result = ModuleType(\"hypothesis_temporary_module_\" + hexdigest)\n    assert isinstance(source, str)\n    exec(source, result.__dict__)\n    eval_cache[source] = result\n    return result\n\n\nCOPY_SIGNATURE_SCRIPT = \"\"\"\nfrom hypothesis.utils.conventions import not_set\n\ndef accept({funcname}):\n    def {name}{signature}:\n        return {funcname}({invocation})\n    return {name}\n\"\"\".lstrip()\n\n\ndef get_varargs(\n    sig: Signature, kind: int = Parameter.VAR_POSITIONAL\n) -> Parameter | None:\n    for p in sig.parameters.values():\n        if p.kind is kind:\n            return p\n    return None\n\n\ndef define_function_signature(name, docstring, signature):\n    \"\"\"A decorator which sets the name, signature and docstring of the function\n    passed into it.\"\"\"\n    if name == \"<lambda>\":\n        name = \"_lambda_\"\n    check_valid_identifier(name)\n    for a in signature.parameters:\n        check_valid_identifier(a)\n\n    used_names = {*signature.parameters, name}\n\n    newsig = signature.replace(\n        parameters=[\n            p if p.default is signature.empty else p.replace(default=not_set)\n            for p in (\n                p.replace(annotation=signature.empty)\n                for p in signature.parameters.values()\n            )\n        ],\n        return_annotation=signature.empty,\n    )\n\n    pos_args = [\n        p\n        for p in signature.parameters.values()\n        if p.kind.name.startswith(\"POSITIONAL_\")\n    ]\n\n    def accept(f):\n        fsig = inspect.signature(f, follow_wrapped=False)\n        must_pass_as_kwargs = []\n        invocation_parts = []\n        for p in pos_args:\n            if p.name not in fsig.parameters and get_varargs(fsig) is None:\n                must_pass_as_kwargs.append(p.name)\n            else:\n                invocation_parts.append(p.name)\n        if get_varargs(signature) is not None:\n            invocation_parts.append(\"*\" + get_varargs(signature).name)\n        for k in must_pass_as_kwargs:\n            invocation_parts.append(f\"{k}={k}\")\n        for p in signature.parameters.values():\n            if p.kind is p.KEYWORD_ONLY:\n                invocation_parts.append(f\"{p.name}={p.name}\")\n        varkw = get_varargs(signature, kind=Parameter.VAR_KEYWORD)\n        if varkw:\n            invocation_parts.append(\"**\" + varkw.name)\n\n        candidate_names = [\"f\"] + [f\"f_{i}\" for i in range(1, len(used_names) + 2)]\n\n        for funcname in candidate_names:  # pragma: no branch\n            if funcname not in used_names:\n                break\n\n        source = COPY_SIGNATURE_SCRIPT.format(\n            name=name,\n            funcname=funcname,\n            signature=str(newsig),\n            invocation=\", \".join(invocation_parts),\n        )\n        result = source_exec_as_module(source).accept(f)\n        result.__doc__ = docstring\n        result.__defaults__ = tuple(\n            p.default\n            for p in signature.parameters.values()\n            if p.default is not signature.empty and \"POSITIONAL\" in p.kind.name\n        )\n        kwdefaults = {\n            p.name: p.default\n            for p in signature.parameters.values()\n            if p.default is not signature.empty and p.kind is p.KEYWORD_ONLY\n        }\n        if kwdefaults:\n            result.__kwdefaults__ = kwdefaults\n        annotations = {\n            p.name: p.annotation\n            for p in signature.parameters.values()\n            if p.annotation is not signature.empty\n        }\n        if signature.return_annotation is not signature.empty:\n            annotations[\"return\"] = signature.return_annotation\n        if annotations:\n            result.__annotations__ = annotations\n        return result\n\n    return accept\n\n\ndef impersonate(target):\n    \"\"\"Decorator to update the attributes of a function so that to external\n    introspectors it will appear to be the target function.\n\n    Note that this updates the function in place, it doesn't return a\n    new one.\n    \"\"\"\n\n    def accept(f):\n        # Lie shamelessly about where this code comes from, to hide the hypothesis\n        # internals from pytest, ipython, and other runtime introspection.\n        f.__code__ = f.__code__.replace(\n            co_filename=target.__code__.co_filename,\n            co_firstlineno=target.__code__.co_firstlineno,\n        )\n        f.__name__ = target.__name__\n        f.__module__ = target.__module__\n        f.__doc__ = target.__doc__\n        f.__globals__[\"__hypothesistracebackhide__\"] = True\n        # But leave an breadcrumb for _describe_lambda to follow, it's\n        # just confused by the lies above\n        f.__wrapped_target = target\n        return f\n\n    return accept\n\n\ndef proxies(target: T) -> Callable[[Callable], T]:\n    replace_sig = define_function_signature(\n        target.__name__.replace(\"<lambda>\", \"_lambda_\"),  # type: ignore\n        target.__doc__,\n        get_signature(target, follow_wrapped=False),\n    )\n\n    def accept(proxy):\n        return impersonate(target)(wraps(target)(replace_sig(proxy)))\n\n    return accept\n\n\ndef is_identity_function(f: Callable) -> bool:\n    try:\n        code = f.__code__\n    except AttributeError:\n        try:\n            f = f.__call__  # type: ignore\n            code = f.__code__\n        except AttributeError:\n            return False\n\n    # We only accept a single unbound argument. While it would be possible to\n    # accept extra defaulted arguments, it would be pointless as they couldn't\n    # be referenced at all in the code object (or the co_code check would fail).\n    bound_args = int(inspect.ismethod(f))\n    if code.co_argcount != bound_args + 1 or code.co_kwonlyargcount > 0:\n        return False\n\n    # We know that f accepts a single positional argument, now check that its\n    # code object is simply \"return first unbound argument\".\n    template = (lambda self, x: x) if bound_args else (lambda x: x)  # type: ignore\n    try:\n        return code.co_code == template.__code__.co_code\n    except AttributeError:  # pragma: no cover  # pypy only\n        # In PyPy, some builtin functions have a code object ('builtin-code')\n        # lacking co_code, perhaps because they are native-compiled and don't have\n        # a corresponding bytecode. Regardless, since Python doesn't have any\n        # builtin identity function it seems safe to say that this one isn't\n        return False\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/scrutineer.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport functools\nimport os\nimport re\nimport subprocess\nimport sys\nimport sysconfig\nimport types\nfrom collections import defaultdict\nfrom collections.abc import Iterable\nfrom enum import IntEnum\nfrom functools import lru_cache, reduce\nfrom os import sep\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING, TypeAlias\n\nfrom hypothesis._settings import Phase, Verbosity\nfrom hypothesis.internal.compat import PYPY\nfrom hypothesis.internal.escalation import is_hypothesis_file\n\nif TYPE_CHECKING:\n    from typing_extensions import Self\n\nLocation: TypeAlias = tuple[str, int]\nBranch: TypeAlias = tuple[Location | None, Location]\nTrace: TypeAlias = frozenset[Branch]\n\n\n@functools.cache\ndef should_trace_file(fname: str) -> bool:\n    # fname.startswith(\"<\") indicates runtime code-generation via compile,\n    # e.g. compile(\"def ...\", \"<string>\", \"exec\") in e.g. attrs methods.\n    return not (is_hypothesis_file(fname) or fname.startswith(\"<\"))\n\n\n# where possible, we'll use 3.12's new sys.monitoring module for low-overhead\n# coverage instrumentation; on older python versions we'll use sys.settrace.\n# tool_id = 1 is designated for coverage, but we intentionally choose a\n# non-reserved tool id so we can co-exist with coverage tools.\nMONITORING_TOOL_ID = 3\nif hasattr(sys, \"monitoring\"):\n    MONITORING_EVENTS = {sys.monitoring.events.LINE: \"trace_line\"}\n\n\nclass Tracer:\n    \"\"\"A super-simple branch coverage tracer.\"\"\"\n\n    __slots__ = (\n        \"_branches\",\n        \"_previous_location\",\n        \"_should_trace\",\n        \"_tried_and_failed_to_trace\",\n    )\n\n    def __init__(self, *, should_trace: bool) -> None:\n        self._branches: set[Branch] = set()\n        self._previous_location: Location | None = None\n        self._tried_and_failed_to_trace = False\n        self._should_trace = should_trace and self.can_trace()\n\n    @staticmethod\n    def can_trace() -> bool:\n        if PYPY:\n            return False\n        if hasattr(sys, \"monitoring\"):\n            return sys.monitoring.get_tool(MONITORING_TOOL_ID) is None\n        return sys.gettrace() is None\n\n    @property\n    def branches(self) -> Trace:\n        return frozenset(self._branches)\n\n    def trace(self, frame, event, arg):\n        try:\n            if event == \"call\":\n                return self.trace\n            elif event == \"line\":\n                fname = frame.f_code.co_filename\n                if should_trace_file(fname):\n                    current_location = (fname, frame.f_lineno)\n                    self._branches.add((self._previous_location, current_location))\n                    self._previous_location = current_location\n        except RecursionError:\n            pass\n\n    def trace_line(self, code: types.CodeType, line_number: int) -> None:\n        fname = code.co_filename\n        if not should_trace_file(fname):\n            # this function is only called on 3.12+, but we want to avoid an\n            # assertion to that effect for performance.\n            return sys.monitoring.DISABLE  # type: ignore\n\n        current_location = (fname, line_number)\n        self._branches.add((self._previous_location, current_location))\n        self._previous_location = current_location\n\n    def __enter__(self) -> \"Self\":\n        self._tried_and_failed_to_trace = False\n\n        if not self._should_trace:\n            return self\n\n        if not hasattr(sys, \"monitoring\"):\n            sys.settrace(self.trace)\n            return self\n\n        try:\n            sys.monitoring.use_tool_id(MONITORING_TOOL_ID, \"scrutineer\")\n        except ValueError:\n            # another thread may have registered a tool for MONITORING_TOOL_ID\n            # since we checked in can_trace.\n            self._tried_and_failed_to_trace = True\n            return self\n\n        for event, callback_name in MONITORING_EVENTS.items():\n            sys.monitoring.set_events(MONITORING_TOOL_ID, event)\n            callback = getattr(self, callback_name)\n            sys.monitoring.register_callback(MONITORING_TOOL_ID, event, callback)\n\n        return self\n\n    def __exit__(self, *args, **kwargs):\n        if not self._should_trace:\n            return\n\n        if not hasattr(sys, \"monitoring\"):\n            sys.settrace(None)\n            return\n\n        if self._tried_and_failed_to_trace:\n            return\n\n        sys.monitoring.free_tool_id(MONITORING_TOOL_ID)\n        for event in MONITORING_EVENTS:\n            sys.monitoring.register_callback(MONITORING_TOOL_ID, event, None)\n\n\nUNHELPFUL_LOCATIONS = (\n    # There's a branch which is only taken when an exception is active while exiting\n    # a contextmanager; this is probably after the fault has been triggered.\n    # Similar reasoning applies to a few other standard-library modules: even\n    # if the fault was later, these still aren't useful locations to report!\n    # Note: The list is post-processed, so use plain \"/\" for separator here.\n    \"/contextlib.py\",\n    \"/inspect.py\",\n    \"/re.py\",\n    \"/re/__init__.py\",  # refactored in Python 3.11\n    \"/warnings.py\",\n    # Quite rarely, the first AFNP line is in Pytest's internals.\n    \"/_pytest/**\",\n    \"/pluggy/_*.py\",\n    # used by pytest for failure formatting in the terminal.\n    # seen: pygments/lexer.py, pygments/formatters/, pygments/filter.py.\n    \"/pygments/*\",\n    # used by pytest for failure formatting\n    \"/difflib.py\",\n    \"/reprlib.py\",\n    \"/typing.py\",\n    \"/conftest.py\",\n    \"/pprint.py\",\n)\n\n\ndef _glob_to_re(locs: Iterable[str]) -> str:\n    \"\"\"Translate a list of glob patterns to a combined regular expression.\n    Only the * and ** wildcards are supported, and patterns including special\n    characters will only work by chance.\"\"\"\n    # fnmatch.translate is not an option since its \"*\" consumes path sep\n    return \"|\".join(\n        loc.replace(\".\", re.escape(\".\"))\n        .replace(\"**\", r\".+\")\n        .replace(\"*\", r\"[^/]+\")\n        .replace(\"/\", re.escape(sep))\n        + r\"\\Z\"  # right anchored\n        for loc in locs\n    )\n\n\ndef get_explaining_locations(traces):\n    # Traces is a dict[interesting_origin | None, set[frozenset[tuple[str, int]]]]\n    # Each trace in the set might later become a Counter instead of frozenset.\n    if not traces:\n        return {}\n\n    unions = {origin: set().union(*values) for origin, values in traces.items()}\n    seen_passing = {None}.union(*unions.pop(None, set()))\n\n    always_failing_never_passing = {\n        origin: reduce(set.intersection, [set().union(*v) for v in values])\n        - seen_passing\n        for origin, values in traces.items()\n        if origin is not None\n    }\n\n    # Build the observed parts of the control-flow graph for each origin\n    cf_graphs = {origin: defaultdict(set) for origin in unions}\n    for origin, seen_arcs in unions.items():\n        for src, dst in seen_arcs:\n            cf_graphs[origin][src].add(dst)\n        assert cf_graphs[origin][None], \"Expected start node with >=1 successor\"\n\n    # For each origin, our explanation is the always_failing_never_passing lines\n    # which are reachable from the start node (None) without passing through another\n    # AFNP line.  So here's a whatever-first search with early stopping:\n    explanations = defaultdict(set)\n    for origin in unions:\n        queue = {None}\n        seen = set()\n        while queue:\n            assert queue.isdisjoint(seen), f\"Intersection: {queue & seen}\"\n            src = queue.pop()\n            seen.add(src)\n            if src in always_failing_never_passing[origin]:\n                explanations[origin].add(src)\n            else:\n                queue.update(cf_graphs[origin][src] - seen)\n\n    # The last step is to filter out explanations that we know would be uninformative.\n    # When this is the first AFNP location, we conclude that Scrutineer missed the\n    # real divergence (earlier in the trace) and drop that unhelpful explanation.\n    filter_regex = re.compile(_glob_to_re(UNHELPFUL_LOCATIONS))\n    return {\n        origin: {loc for loc in afnp_locs if not filter_regex.search(loc[0])}\n        for origin, afnp_locs in explanations.items()\n    }\n\n\n# see e.g. https://docs.python.org/3/library/sysconfig.html#posix-user\n# for examples of these path schemes\nSTDLIB_DIRS = {\n    Path(sysconfig.get_path(\"platstdlib\")).resolve(),\n    Path(sysconfig.get_path(\"stdlib\")).resolve(),\n}\nSITE_PACKAGES_DIRS = {\n    Path(sysconfig.get_path(\"purelib\")).resolve(),\n    Path(sysconfig.get_path(\"platlib\")).resolve(),\n}\n\nEXPLANATION_STUB = (\n    \"Explanation:\",\n    \"    These lines were always and only run by failing examples:\",\n)\n\n\nclass ModuleLocation(IntEnum):\n    LOCAL = 0\n    SITE_PACKAGES = 1\n    STDLIB = 2\n\n    @classmethod\n    @lru_cache(1024)\n    def from_path(cls, path: str) -> \"ModuleLocation\":\n        path = Path(path).resolve()\n        # site-packages may be a subdir of stdlib or platlib, so it's important to\n        # check is_relative_to for this before the stdlib.\n        if any(path.is_relative_to(p) for p in SITE_PACKAGES_DIRS):\n            return cls.SITE_PACKAGES\n        if any(path.is_relative_to(p) for p in STDLIB_DIRS):\n            return cls.STDLIB\n        return cls.LOCAL\n\n\n# show local files first, then site-packages, then stdlib\ndef _sort_key(path: str, lineno: int) -> tuple[int, str, int]:\n    return (ModuleLocation.from_path(path), path, lineno)\n\n\ndef make_report(explanations, *, cap_lines_at=5):\n    report = defaultdict(list)\n    for origin, locations in explanations.items():\n        locations = list(locations)\n        locations.sort(key=lambda v: _sort_key(v[0], v[1]))\n        report_lines = [f\"        {fname}:{lineno}\" for fname, lineno in locations]\n        if len(report_lines) > cap_lines_at + 1:\n            msg = \"        (and {} more with settings.verbosity >= verbose)\"\n            report_lines[cap_lines_at:] = [msg.format(len(report_lines[cap_lines_at:]))]\n        if report_lines:  # We might have filtered out every location as uninformative.\n            report[origin] = list(EXPLANATION_STUB) + report_lines\n    return report\n\n\ndef explanatory_lines(traces, settings):\n    if Phase.explain in settings.phases and sys.gettrace() and not traces:\n        return defaultdict(list)\n    # Return human-readable report lines summarising the traces\n    explanations = get_explaining_locations(traces)\n    max_lines = 5 if settings.verbosity <= Verbosity.normal else float(\"inf\")\n    return make_report(explanations, cap_lines_at=max_lines)\n\n\n# beware the code below; we're using some heuristics to make a nicer report...\n\n\n@functools.lru_cache\ndef _get_git_repo_root() -> Path:\n    try:\n        where = subprocess.run(\n            [\"git\", \"rev-parse\", \"--show-toplevel\"],\n            check=True,\n            timeout=10,\n            capture_output=True,\n            text=True,\n            encoding=\"utf-8\",\n        ).stdout.strip()\n    except Exception:  # pragma: no cover\n        return Path().absolute().parents[-1]\n    else:\n        return Path(where)\n\n\ndef tractable_coverage_report(trace: Trace) -> dict[str, list[int]]:\n    \"\"\"Report a simple coverage map which is (probably most) of the user's code.\"\"\"\n    coverage: dict = {}\n    t = dict(trace)\n    for file, line in set(t.keys()).union(t.values()) - {None}:  # type: ignore\n        # On Python <= 3.11, we can use coverage.py xor Hypothesis' tracer,\n        # so the trace will be empty and this line never run under coverage.\n        coverage.setdefault(file, set()).add(line)  # pragma: no cover\n    stdlib_fragment = f\"{os.sep}lib{os.sep}python3.{sys.version_info.minor}{os.sep}\"\n    return {\n        k: sorted(v)\n        for k, v in coverage.items()\n        if stdlib_fragment not in k\n        and (p := Path(k)).is_relative_to(_get_git_repo_root())\n        and \"site-packages\" not in p.parts\n    }\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/internal/validation.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport decimal\nimport math\nfrom numbers import Rational, Real\n\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.coverage import check_function\n\n\n@check_function\ndef check_type(typ: type | tuple[type, ...], arg: object, name: str) -> None:\n    if not isinstance(arg, typ):\n        if isinstance(typ, tuple):\n            assert len(typ) >= 2, \"Use bare type instead of len-1 tuple\"\n            typ_string = \"one of \" + \", \".join(t.__name__ for t in typ)\n        else:\n            typ_string = typ.__name__\n\n            if typ_string == \"SearchStrategy\":\n                from hypothesis.strategies import SearchStrategy\n\n                # Use hypothesis.strategies._internal.strategies.check_strategy\n                # instead, as it has some helpful \"did you mean...\" logic.\n                assert typ is not SearchStrategy, \"use check_strategy instead\"\n\n        raise InvalidArgument(\n            f\"Expected {typ_string} but got {name}={arg!r} (type={type(arg).__name__})\"\n        )\n\n\n@check_function\ndef check_valid_integer(value, name):\n    \"\"\"Checks that value is either unspecified, or a valid integer.\n\n    Otherwise raises InvalidArgument.\n    \"\"\"\n    if value is None:\n        return\n    check_type(int, value, name)\n\n\n@check_function\ndef check_valid_bound(value, name):\n    \"\"\"Checks that value is either unspecified, or a valid interval bound.\n\n    Otherwise raises InvalidArgument.\n    \"\"\"\n    if value is None or isinstance(value, (int, Rational)):\n        return\n    if not isinstance(value, (Real, decimal.Decimal)):\n        raise InvalidArgument(f\"{name}={value!r} must be a real number.\")\n    if math.isnan(value):\n        raise InvalidArgument(f\"Invalid end point {name}={value!r}\")\n\n\n@check_function\ndef check_valid_magnitude(value, name):\n    \"\"\"Checks that value is either unspecified, or a non-negative valid\n    interval bound.\n\n    Otherwise raises InvalidArgument.\n    \"\"\"\n    check_valid_bound(value, name)\n    if value is not None and value < 0:\n        raise InvalidArgument(f\"{name}={value!r} must not be negative.\")\n    elif value is None and name == \"min_magnitude\":\n        raise InvalidArgument(\"Use min_magnitude=0 or omit the argument entirely.\")\n\n\n@check_function\ndef try_convert(typ, value, name):\n    if value is None:\n        return None\n    if isinstance(value, typ):\n        return value\n    try:\n        return typ(value)\n    except (TypeError, ValueError, ArithmeticError) as err:\n        raise InvalidArgument(\n            f\"Cannot convert {name}={value!r} of type \"\n            f\"{type(value).__name__} to type {typ.__name__}\"\n        ) from err\n\n\n@check_function\ndef check_valid_size(value, name):\n    \"\"\"Checks that value is either unspecified, or a valid non-negative size\n    expressed as an integer.\n\n    Otherwise raises InvalidArgument.\n    \"\"\"\n    if value is None and name not in (\"min_size\", \"size\"):\n        return\n    check_type(int, value, name)\n    if value < 0:\n        raise InvalidArgument(f\"Invalid size {name}={value!r} < 0\")\n\n\n@check_function\ndef check_valid_interval(lower_bound, upper_bound, lower_name, upper_name):\n    \"\"\"Checks that lower_bound and upper_bound are either unspecified, or they\n    define a valid interval on the number line.\n\n    Otherwise raises InvalidArgument.\n    \"\"\"\n    if lower_bound is None or upper_bound is None:\n        return\n    if upper_bound < lower_bound:\n        raise InvalidArgument(\n            f\"Cannot have {upper_name}={upper_bound!r} < {lower_name}={lower_bound!r}\"\n        )\n\n\n@check_function\ndef check_valid_sizes(min_size, max_size):\n    check_valid_size(min_size, \"min_size\")\n    check_valid_size(max_size, \"max_size\")\n    check_valid_interval(min_size, max_size, \"min_size\", \"max_size\")\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/provisional.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"This module contains various provisional APIs and strategies.\n\nIt is intended for internal use, to ease code reuse, and is not stable.\nPoint releases may move or break the contents at any time!\n\nInternet strategies should conform to :rfc:`3986` or the authoritative\ndefinitions it links to.  If not, report the bug!\n\"\"\"\n# https://tools.ietf.org/html/rfc3696\n\nimport string\nfrom functools import lru_cache\nfrom importlib import resources\n\nfrom hypothesis import strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.conjecture import utils as cu\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.strategies import DrawFn\nfrom hypothesis.strategies._internal.utils import defines_strategy\n\nURL_SAFE_CHARACTERS = frozenset(string.ascii_letters + string.digits + \"$-_.+!*'(),~\")\nFRAGMENT_SAFE_CHARACTERS = URL_SAFE_CHARACTERS | {\"?\", \"/\"}\n\n\n@lru_cache(maxsize=1)\ndef get_top_level_domains() -> tuple[str, ...]:\n    # This file is sourced from http://data.iana.org/TLD/tlds-alpha-by-domain.txt\n    # The file contains additional information about the date that it was last updated.\n    traversable = resources.files(\"hypothesis.vendor\") / \"tlds-alpha-by-domain.txt\"\n    _comment, *_tlds = traversable.read_text(encoding=\"utf-8\").splitlines()\n    assert _comment.startswith(\"#\")\n\n    # Remove special-use domain names from the list. For more discussion\n    # see https://github.com/HypothesisWorks/hypothesis/pull/3572\n    return (\"COM\", *sorted((d for d in _tlds if d != \"ARPA\"), key=len))\n\n\n@st.composite\ndef _recase_randomly(draw: DrawFn, tld: str) -> str:\n    tld = list(tld)\n    changes = draw(st.tuples(*(st.booleans() for _ in range(len(tld)))))\n    for i, change_case in enumerate(changes):\n        if change_case:\n            tld[i] = tld[i].lower() if tld[i].isupper() else tld[i].upper()\n    return \"\".join(tld)\n\n\nclass DomainNameStrategy(st.SearchStrategy[str]):\n    @staticmethod\n    def clean_inputs(\n        minimum: int, maximum: int, value: int | None, variable_name: str\n    ) -> int:\n        if value is None:\n            value = maximum\n        elif not isinstance(value, int):\n            raise InvalidArgument(\n                f\"Expected integer but {variable_name} is a {type(value).__name__}\"\n            )\n        elif not minimum <= value <= maximum:\n            raise InvalidArgument(\n                f\"Invalid value {minimum!r} < {variable_name}={value!r} < {maximum!r}\"\n            )\n        return value\n\n    def __init__(\n        self, max_length: int | None = None, max_element_length: int | None = None\n    ) -> None:\n        \"\"\"\n        A strategy for :rfc:`1035` fully qualified domain names.\n\n        The upper limit for max_length is 255 in accordance with :rfc:`1035#section-2.3.4`\n        The lower limit for max_length is 4, corresponding to a two letter domain\n        with a single letter subdomain.\n        The upper limit for max_element_length is 63 in accordance with :rfc:`1035#section-2.3.4`\n        The lower limit for max_element_length is 1 in accordance with :rfc:`1035#section-2.3.4`\n        \"\"\"\n        # https://tools.ietf.org/html/rfc1035#section-2.3.4\n\n        max_length = self.clean_inputs(4, 255, max_length, \"max_length\")\n        max_element_length = self.clean_inputs(\n            1, 63, max_element_length, \"max_element_length\"\n        )\n\n        super().__init__()\n        self.max_length = max_length\n        self.max_element_length = max_element_length\n\n        # These regular expressions are constructed to match the documented\n        # information in https://tools.ietf.org/html/rfc1035#section-2.3.1\n        # which defines the allowed syntax of a subdomain string.\n        if self.max_element_length == 1:\n            label_regex = r\"[a-zA-Z]\"\n        elif self.max_element_length == 2:\n            label_regex = r\"[a-zA-Z][a-zA-Z0-9]?\"\n        else:\n            maximum_center_character_pattern_repetitions = self.max_element_length - 2\n            label_regex = r\"[a-zA-Z]([a-zA-Z0-9\\-]{0,%d}[a-zA-Z0-9])?\" % (\n                maximum_center_character_pattern_repetitions,\n            )\n\n        # Construct reusable strategies here to avoid a performance hit by doing\n        # so repeatedly in do_draw.\n\n        # 1 - Select a valid top-level domain (TLD) name\n        # 2 - Check that the number of characters in our selected TLD won't\n        # prevent us from generating at least a 1 character subdomain.\n        # 3 - Randomize the TLD between upper and lower case characters.\n\n        self.domain_strategy = (\n            st.sampled_from(get_top_level_domains())\n            .filter(lambda tld: len(tld) + 2 <= self.max_length)\n            .flatmap(_recase_randomly)\n        )\n\n        # RFC-5890 s2.3.1 says such labels are reserved, and since we don't\n        # want to bother with xn-- punycode labels we'll exclude them all.\n        self.elem_strategy = st.from_regex(label_regex, fullmatch=True).filter(\n            lambda label: len(label) < 4 or label[2:4] != \"--\"\n        )\n\n    def do_draw(self, data: ConjectureData) -> str:\n        domain = data.draw(self.domain_strategy)\n        # The maximum possible number of subdomains is 126,\n        # 1 character subdomain + 1 '.' character, * 126 = 252,\n        # with a max of 255, that leaves 3 characters for a TLD.\n        # Allowing any more subdomains would not leave enough\n        # characters for even the shortest possible TLDs.\n        elements = cu.many(data, min_size=1, average_size=3, max_size=126)\n        while elements.more():\n            # Generate a new valid subdomain using the regex strategy.\n            sub_domain = data.draw(self.elem_strategy)\n            if len(domain) + len(sub_domain) >= self.max_length:\n                data.stop_span(discard=True)\n                break\n            domain = sub_domain + \".\" + domain\n        return domain\n\n\n@defines_strategy(force_reusable_values=True)\ndef domains(\n    *, max_length: int = 255, max_element_length: int = 63\n) -> st.SearchStrategy[str]:\n    \"\"\"Generate :rfc:`1035` compliant fully qualified domain names.\"\"\"\n    return DomainNameStrategy(\n        max_length=max_length, max_element_length=max_element_length\n    )\n\n\n# The `urls()` strategy uses this to generate URL fragments (e.g. \"#foo\").\n# It has been extracted to top-level so that we can test it independently\n# of `urls()`, which helps with getting non-flaky coverage of the lambda.\n_url_fragments_strategy = (\n    st.lists(\n        st.builds(\n            lambda char, encode: (\n                f\"%{ord(char):02X}\"\n                if (encode or char not in FRAGMENT_SAFE_CHARACTERS)\n                else char\n            ),\n            st.characters(min_codepoint=0, max_codepoint=255),\n            st.booleans(),\n        ),\n        min_size=1,\n    )\n    .map(\"\".join)\n    .map(\"#{}\".format)\n)\n\n\n@defines_strategy(force_reusable_values=True)\ndef urls() -> st.SearchStrategy[str]:\n    \"\"\"A strategy for :rfc:`3986`, generating http/https URLs.\n\n    The generated URLs could, at least in theory, be passed to an HTTP client\n    and fetched.\n\n    \"\"\"\n\n    def url_encode(s: str) -> str:\n        return \"\".join(c if c in URL_SAFE_CHARACTERS else f\"%{ord(c):02X}\" for c in s)\n\n    schemes = st.sampled_from([\"http\", \"https\"])\n    ports = st.integers(min_value=1, max_value=2**16 - 1).map(\":{}\".format)\n    paths = st.lists(st.text(string.printable).map(url_encode)).map(\"/\".join)\n\n    return st.builds(\n        \"{}://{}{}/{}{}\".format,\n        schemes,\n        domains(),\n        st.just(\"\") | ports,\n        paths,\n        st.just(\"\") | _url_fragments_strategy,\n    )\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/py.typed",
    "content": ""
  },
  {
    "path": "hypothesis-python/src/hypothesis/reporting.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections.abc import Callable\nfrom contextlib import AbstractContextManager\nfrom typing import TypeAlias\n\nfrom hypothesis._settings import Verbosity, settings\nfrom hypothesis.internal.compat import escape_unicode_characters\nfrom hypothesis.utils.dynamicvariables import DynamicVariable\n\n\ndef default(value: object) -> None:\n    try:\n        print(value)\n    except UnicodeEncodeError:\n        print(escape_unicode_characters(str(value)))\n\n\nReporterT: TypeAlias = Callable[[object], None]\nreporter = DynamicVariable[ReporterT](default)\n\n\ndef current_reporter() -> ReporterT:\n    return reporter.value\n\n\ndef with_reporter(new_reporter: ReporterT) -> AbstractContextManager[None]:\n    return reporter.with_value(new_reporter)\n\n\ndef current_verbosity() -> Verbosity:\n    assert settings.default is not None\n    return settings.default.verbosity\n\n\ndef verbose_report(text: str) -> None:\n    if current_verbosity() >= Verbosity.verbose:\n        base_report(text)\n\n\ndef debug_report(text: str) -> None:\n    if current_verbosity() >= Verbosity.debug:\n        base_report(text)\n\n\ndef report(text: str) -> None:\n    if current_verbosity() >= Verbosity.normal:\n        base_report(text)\n\n\ndef base_report(text: str) -> None:\n    assert isinstance(text, str), f\"unexpected non-str {text=}\"\n    current_reporter()(text)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/stateful.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"This module provides support for a stateful style of testing, where tests\nattempt to find a sequence of operations that cause a breakage rather than just\na single value.\n\nNotably, the set of steps available at any point may depend on the\nexecution to date.\n\"\"\"\n\nimport collections\nimport dataclasses\nimport inspect\nfrom collections.abc import Callable, Iterable, Sequence\nfrom dataclasses import dataclass, field\nfrom functools import lru_cache\nfrom io import StringIO\nfrom time import perf_counter\nfrom typing import Any, ClassVar, TypeVar, overload\nfrom unittest import TestCase\n\nfrom hypothesis import strategies as st\nfrom hypothesis._settings import HealthCheck, Verbosity, settings as Settings\nfrom hypothesis.control import _current_build_context, current_build_context\nfrom hypothesis.core import TestFunc, given\nfrom hypothesis.errors import (\n    FlakyStrategyDefinition,\n    InvalidArgument,\n    InvalidDefinition,\n)\nfrom hypothesis.internal.compat import add_note, batched\nfrom hypothesis.internal.conjecture.engine import BUFFER_SIZE\nfrom hypothesis.internal.conjecture.junkdrawer import gc_cumulative_time\nfrom hypothesis.internal.conjecture.utils import calc_label_from_name\nfrom hypothesis.internal.healthcheck import fail_health_check\nfrom hypothesis.internal.observability import observability_enabled\nfrom hypothesis.internal.reflection import (\n    function_digest,\n    get_pretty_function_description,\n    nicerepr,\n    proxies,\n)\nfrom hypothesis.internal.validation import check_type\nfrom hypothesis.reporting import current_verbosity, report\nfrom hypothesis.strategies._internal.featureflags import FeatureStrategy\nfrom hypothesis.strategies._internal.strategies import (\n    Ex,\n    OneOfStrategy,\n    SearchStrategy,\n    check_strategy,\n)\nfrom hypothesis.utils.deprecation import note_deprecation\nfrom hypothesis.vendor.pretty import RepresentationPrinter\n\nT = TypeVar(\"T\")\nSTATE_MACHINE_RUN_LABEL = calc_label_from_name(\"another state machine step\")\n\n\ndef _is_singleton(obj: object) -> bool:\n    \"\"\"\n    Returns True if two separately created instances of v will have the same id\n    (due to interning).\n    \"\"\"\n    # The range [-5, 256] is a cpython implementation detail. This may not work\n    # well on other platforms.\n    if isinstance(obj, int) and -5 <= obj <= 256:\n        return True\n    # cpython also interns compile-time strings, but let's just ignore those for\n    # now.\n    return isinstance(obj, bool) or obj is None\n\n\nclass _OmittedArgument:\n    \"\"\"Sentinel class to prevent overlapping overloads in type hints. See comments\n    above the overloads of @rule.\"\"\"\n\n\nclass TestCaseProperty:  # pragma: no cover\n    def __get__(self, obj, typ=None):\n        if obj is not None:\n            typ = type(obj)\n        return typ._to_test_case()\n\n    def __set__(self, obj, value):\n        raise AttributeError(\"Cannot set TestCase\")\n\n    def __delete__(self, obj):\n        raise AttributeError(\"Cannot delete TestCase\")\n\n\ndef get_state_machine_test(\n    state_machine_factory, *, settings=None, _min_steps=0, _flaky_state=None\n):\n    # This function is split out from run_state_machine_as_test so that\n    # HypoFuzz can get and call the test function directly.\n    if settings is None:\n        try:\n            settings = state_machine_factory.TestCase.settings\n            check_type(Settings, settings, \"state_machine_factory.TestCase.settings\")\n        except AttributeError:\n            settings = Settings(deadline=None, suppress_health_check=list(HealthCheck))\n    check_type(Settings, settings, \"settings\")\n    check_type(int, _min_steps, \"_min_steps\")\n    if _min_steps < 0:\n        # Because settings can vary via e.g. profiles, settings.stateful_step_count\n        # overrides this argument and we don't bother cross-validating.\n        raise InvalidArgument(f\"_min_steps={_min_steps} must be non-negative.\")\n    _flaky_state = _flaky_state or {}\n\n    @settings\n    @given(st.data())\n    def run_state_machine(data):\n        cd = data.conjecture_data\n        machine: RuleBasedStateMachine = state_machine_factory()\n        check_type(RuleBasedStateMachine, machine, \"state_machine_factory()\")\n        cd.hypothesis_runner = machine\n        machine._observability_predicates = cd._observability_predicates  # alias\n\n        print_steps = (\n            current_build_context().is_final or current_verbosity() >= Verbosity.debug\n        )\n        cd._stateful_repr_parts = []\n\n        def output(s):\n            if print_steps:\n                report(s)\n            if observability_enabled():\n                cd._stateful_repr_parts.append(s)\n\n        try:\n            output(f\"state = {machine.__class__.__name__}()\")\n            machine.check_invariants(settings, output, cd._stateful_run_times)\n            max_steps = settings.stateful_step_count\n            steps_run = 0\n\n            while True:\n                # We basically always want to run the maximum number of steps,\n                # but need to leave a small probability of terminating early\n                # in order to allow for reducing the number of steps once we\n                # find a failing test case, so we stop with probability of\n                # 2 ** -16 during normal operation but force a stop when we've\n                # generated enough steps.\n                cd.start_span(STATE_MACHINE_RUN_LABEL)\n                must_stop = None\n                if steps_run >= max_steps:\n                    must_stop = True\n                elif steps_run <= _min_steps:\n                    must_stop = False\n                elif cd.length > (0.8 * BUFFER_SIZE):\n                    # Better to stop after fewer steps, than always overrun and retry.\n                    # See https://github.com/HypothesisWorks/hypothesis/issues/3618\n                    must_stop = True\n\n                start_draw = perf_counter()\n                start_gc = gc_cumulative_time()\n                if cd.draw_boolean(p=2**-16, forced=must_stop):\n                    break\n                steps_run += 1\n\n                # Choose a rule to run, preferring an initialize rule if there are\n                # any which have not been run yet.\n                _flaky_state[\"selecting_rule\"] = True\n                if machine._initialize_rules_to_run:\n                    init_rules = [\n                        st.tuples(st.just(rule), st.fixed_dictionaries(rule.arguments))\n                        for rule in machine._initialize_rules_to_run\n                    ]\n                    rule, data = cd.draw(st.one_of(init_rules))\n                    machine._initialize_rules_to_run.remove(rule)\n                else:\n                    rule, data = cd.draw(machine._rules_strategy)\n                _flaky_state[\"selecting_rule\"] = False\n                draw_label = f\"generate:rule:{rule.function.__name__}\"\n                cd.draw_times.setdefault(draw_label, 0.0)\n                in_gctime = gc_cumulative_time() - start_gc\n                cd.draw_times[draw_label] += perf_counter() - start_draw - in_gctime\n\n                # Pretty-print the values this rule was called with *before* calling\n                # _add_results_to_targets, to avoid printing arguments which are also\n                # a return value using the variable name they are assigned to.\n                # See https://github.com/HypothesisWorks/hypothesis/issues/2341\n                if print_steps or observability_enabled():\n                    data_to_print = {\n                        k: machine._pretty_print(v) for k, v in data.items()\n                    }\n\n                # Assign 'result' here in case executing the rule fails below\n                result = multiple()\n                try:\n                    data = dict(data)\n                    for k, v in list(data.items()):\n                        if isinstance(v, VarReference):\n                            data[k] = machine.names_to_values[v.name]\n                        elif isinstance(v, list) and all(\n                            isinstance(item, VarReference) for item in v\n                        ):\n                            data[k] = [machine.names_to_values[item.name] for item in v]\n\n                    label = f\"execute:rule:{rule.function.__name__}\"\n                    start = perf_counter()\n                    start_gc = gc_cumulative_time()\n                    result = rule.function(machine, **data)\n                    in_gctime = gc_cumulative_time() - start_gc\n                    cd._stateful_run_times[label] += perf_counter() - start - in_gctime\n\n                    if rule.targets:\n                        if isinstance(result, MultipleResults):\n                            machine._add_results_to_targets(rule.targets, result.values)\n                        else:\n                            machine._add_results_to_targets(rule.targets, [result])\n                    elif result is not None:\n                        fail_health_check(\n                            settings,\n                            \"Rules should return None if they have no target bundle, \"\n                            f\"but {rule.function.__qualname__} returned {result!r}\",\n                            HealthCheck.return_value,\n                        )\n                finally:\n                    if print_steps or observability_enabled():\n                        # 'result' is only used if the step has target bundles.\n                        # If it does, and the result is a 'MultipleResult',\n                        # then 'print_step' prints a multi-variable assignment.\n                        output(machine._repr_step(rule, data_to_print, result))\n                machine.check_invariants(settings, output, cd._stateful_run_times)\n                cd.stop_span()\n        finally:\n            output(\"state.teardown()\")\n            machine.teardown()\n\n    # Use a machine digest to identify stateful tests in the example database\n    run_state_machine.hypothesis.inner_test._hypothesis_internal_add_digest = (\n        function_digest(state_machine_factory)\n    )\n    # Copy some attributes so @seed and @reproduce_failure \"just work\"\n    run_state_machine._hypothesis_internal_use_seed = getattr(\n        state_machine_factory, \"_hypothesis_internal_use_seed\", None\n    )\n    run_state_machine._hypothesis_internal_use_reproduce_failure = getattr(\n        state_machine_factory, \"_hypothesis_internal_use_reproduce_failure\", None\n    )\n    run_state_machine._hypothesis_internal_print_given_args = False\n    return run_state_machine\n\n\ndef run_state_machine_as_test(state_machine_factory, *, settings=None, _min_steps=0):\n    \"\"\"Run a state machine definition as a test, either silently doing nothing\n    or printing a minimal breaking program and raising an exception.\n\n    state_machine_factory is anything which returns an instance of\n    RuleBasedStateMachine when called with no arguments - it can be a class or a\n    function. settings will be used to control the execution of the test.\n    \"\"\"\n    flaky_state = {\"selecting_rule\": False}\n    state_machine_test = get_state_machine_test(\n        state_machine_factory,\n        settings=settings,\n        _min_steps=_min_steps,\n        _flaky_state=flaky_state,\n    )\n    try:\n        state_machine_test()\n    except FlakyStrategyDefinition as err:\n        if flaky_state[\"selecting_rule\"]:\n            add_note(\n                err,\n                \"while selecting a rule to run. This is usually caused by \"\n                \"a flaky precondition, or a bundle that was unexpectedly empty.\",\n            )\n        raise\n\n\nclass StateMachineMeta(type):\n    def __setattr__(cls, name, value):\n        if name == \"settings\" and isinstance(value, Settings):\n            descr = f\"settings({value.show_changed()})\"\n            raise AttributeError(\n                f\"Assigning {cls.__name__}.settings = {descr} does nothing. Assign \"\n                f\"to {cls.__name__}.TestCase.settings, or use @{descr} as a decorator \"\n                f\"on the {cls.__name__} class.\"\n            )\n        return super().__setattr__(name, value)\n\n\n@dataclass(slots=True, frozen=True)\nclass _SetupState:\n    rules: list[\"Rule\"]\n    invariants: list[\"Invariant\"]\n    initializers: list[\"Rule\"]\n\n\nclass RuleBasedStateMachine(metaclass=StateMachineMeta):\n    \"\"\"A RuleBasedStateMachine gives you a structured way to define state machines.\n\n    The idea is that a state machine carries the system under test and some supporting\n    data. This data can be stored in instance variables or\n    divided into Bundles. The state machine has a set of rules which may read data\n    from bundles (or just from normal strategies), push data onto\n    bundles, change the state of the machine, or verify properties.\n    At any given point a random applicable rule will be executed.\n    \"\"\"\n\n    _setup_state_per_class: ClassVar[dict[type, _SetupState]] = {}\n\n    def __init__(self) -> None:\n        setup_state = self.setup_state()\n        if not setup_state.rules:\n            raise InvalidDefinition(\n                f\"State machine {type(self).__name__} defines no rules\"\n            )\n\n        if isinstance(s := vars(type(self)).get(\"settings\"), Settings):\n            tname = type(self).__name__\n            descr = f\"settings({s.show_changed()})\"\n            raise InvalidDefinition(\n                f\"Assigning settings = {descr} as a class attribute does nothing. \"\n                f\"Assign to {tname}.TestCase.settings, or use @{descr} as a decorator \"\n                f\"on the {tname} class.\"\n            )\n\n        self.rules = setup_state.rules\n        self.invariants = setup_state.invariants\n        # copy since we pop from this as we run initialize rules.\n        self._initialize_rules_to_run = setup_state.initializers.copy()\n\n        self.bundles: dict[str, list] = {}\n        self.names_counters: collections.Counter = collections.Counter()\n        self.names_list: list[str] = []\n        self.names_to_values: dict[str, Any] = {}\n        self.__stream = StringIO()\n        self.__printer = RepresentationPrinter(\n            self.__stream, context=_current_build_context.value\n        )\n        self._rules_strategy = RuleStrategy(self)\n\n    def _pretty_print(self, value):\n        if isinstance(value, VarReference):\n            return value.name\n        elif isinstance(value, list) and all(\n            isinstance(item, VarReference) for item in value\n        ):\n            return \"[\" + \", \".join([item.name for item in value]) + \"]\"\n        self.__stream.seek(0)\n        self.__stream.truncate(0)\n        self.__printer.output_width = 0\n        self.__printer.buffer_width = 0\n        self.__printer.buffer.clear()\n        self.__printer.pretty(value)\n        self.__printer.flush()\n        return self.__stream.getvalue()\n\n    def __repr__(self):\n        return f\"{type(self).__name__}({nicerepr(self.bundles)})\"\n\n    def _new_name(self, target):\n        result = f\"{target}_{self.names_counters[target]}\"\n        self.names_counters[target] += 1\n        self.names_list.append(result)\n        return result\n\n    def _last_names(self, n: int) -> list[str]:\n        len_ = len(self.names_list)\n        assert len_ >= n\n        return self.names_list[len_ - n :]\n\n    def bundle(self, name):\n        return self.bundles.setdefault(name, [])\n\n    @classmethod\n    def setup_state(cls):\n        try:\n            return cls._setup_state_per_class[cls]\n        except KeyError:\n            pass\n\n        rules: list[Rule] = []\n        initializers: list[Rule] = []\n        invariants: list[Invariant] = []\n\n        for _name, f in inspect.getmembers(cls):\n            rule = getattr(f, RULE_MARKER, None)\n            initializer = getattr(f, INITIALIZE_RULE_MARKER, None)\n            invariant = getattr(f, INVARIANT_MARKER, None)\n            if rule is not None:\n                rules.append(rule)\n            if initializer is not None:\n                initializers.append(initializer)\n            if invariant is not None:\n                invariants.append(invariant)\n\n            if (\n                getattr(f, PRECONDITIONS_MARKER, None) is not None\n                and rule is None\n                and invariant is None\n            ):\n                raise InvalidDefinition(\n                    f\"{_rule_qualname(f)} has been decorated with @precondition, \"\n                    \"but not @rule (or @invariant), which is not allowed. A \"\n                    \"precondition must be combined with a rule or an invariant, \"\n                    \"since it has no effect alone.\"\n                )\n\n        state = _SetupState(\n            rules=rules, initializers=initializers, invariants=invariants\n        )\n        cls._setup_state_per_class[cls] = state\n        return state\n\n    def _repr_step(self, rule: \"Rule\", data: Any, result: Any) -> str:\n        output_assignment = \"\"\n        extra_assignment_lines = []\n        if rule.targets:\n            number_of_results = (\n                len(result.values) if isinstance(result, MultipleResults) else 1\n            )\n            number_of_last_names = len(rule.targets) * number_of_results\n            last_names = self._last_names(number_of_last_names)\n            if isinstance(result, MultipleResults):\n                if len(result.values) == 1:\n                    # len-1 tuples\n                    output_per_target = [f\"({name},)\" for name in last_names]\n                    output_assignment = \" = \".join(output_per_target) + \" = \"\n                elif result.values:\n                    # multiple values, multiple targets -- use the first target\n                    # for the assignment from function, and do the other target\n                    # assignments on separate lines\n                    names_per_target = list(batched(last_names, number_of_results))\n                    first_target_output = \", \".join(names_per_target[0])\n                    output_assignment = first_target_output + \" = \"\n                    for other_target_names in names_per_target[1:]:\n                        other_target_output = \", \".join(other_target_names)\n                        extra_assignment_lines.append(\n                            other_target_output + \" = \" + first_target_output\n                        )\n            else:\n                output_assignment = \" = \".join(last_names) + \" = \"\n        args = \", \".join(f\"{k}={v}\" for k, v in data.items())\n        output_line = f\"{output_assignment}state.{rule.function.__name__}({args})\"\n        return \"\\n\".join([output_line] + extra_assignment_lines)\n\n    def _add_results_to_targets(self, targets, results):\n        # Note, the assignment order here is reflected in _repr_step\n        for target in targets:\n            for result in results:\n                name = self._new_name(target)\n\n                def printer(obj, p, cycle, name=name):\n                    return p.text(name)\n\n                # see\n                # https://github.com/HypothesisWorks/hypothesis/pull/4266#discussion_r1949619102\n                if not _is_singleton(result):\n                    self.__printer.singleton_pprinters.setdefault(id(result), printer)\n                self.names_to_values[name] = result\n                self.bundles.setdefault(target, []).append(VarReference(name))\n\n    def check_invariants(self, settings, output, runtimes):\n        for invar in self.invariants:\n            if self._initialize_rules_to_run and not invar.check_during_init:\n                continue\n            if not all(precond(self) for precond in invar.preconditions):\n                continue\n            name = invar.function.__name__\n            if (\n                current_build_context().is_final\n                or settings.verbosity >= Verbosity.debug\n                or observability_enabled()\n            ):\n                output(f\"state.{name}()\")\n            start = perf_counter()\n            result = invar.function(self)\n            runtimes[f\"execute:invariant:{name}\"] += perf_counter() - start\n            if result is not None:\n                fail_health_check(\n                    settings,\n                    \"The return value of an @invariant is always ignored, but \"\n                    f\"{invar.function.__qualname__} returned {result!r} \"\n                    \"instead of None\",\n                    HealthCheck.return_value,\n                )\n\n    def teardown(self):\n        \"\"\"Called after a run has finished executing to clean up any necessary\n        state.\n\n        Does nothing by default.\n        \"\"\"\n\n    TestCase = TestCaseProperty()\n\n    @classmethod\n    @lru_cache\n    def _to_test_case(cls):\n        class StateMachineTestCase(TestCase):\n            settings = Settings(deadline=None, suppress_health_check=list(HealthCheck))\n\n            def runTest(self):\n                run_state_machine_as_test(cls, settings=self.settings)\n\n            runTest.is_hypothesis_test = True\n            runTest._hypothesis_state_machine_class = cls\n\n        StateMachineTestCase.__name__ = cls.__name__ + \".TestCase\"\n        StateMachineTestCase.__qualname__ = cls.__qualname__ + \".TestCase\"\n        return StateMachineTestCase\n\n\n@dataclass(slots=True, frozen=False)\nclass Rule:\n    targets: Any\n    function: Any\n    arguments: Any\n    preconditions: Any\n    bundles: tuple[\"Bundle\", ...] = field(init=False)\n    _cached_hash: int | None = field(init=False, default=None)\n    _cached_repr: str | None = field(init=False, default=None)\n    arguments_strategies: dict[Any, Any] = field(init=False, default_factory=dict)\n\n    def __post_init__(self):\n        bundles = []\n        for k, v in sorted(self.arguments.items()):\n            assert not isinstance(v, BundleReferenceStrategy)\n            if isinstance(v, Bundle):\n                bundles.append(v)\n                consume = isinstance(v, BundleConsumer)\n                v = BundleReferenceStrategy(v.name, consume=consume)\n            self.arguments_strategies[k] = v\n        self.bundles = tuple(bundles)\n\n    def __repr__(self) -> str:\n        if self._cached_repr is None:\n            bits = [\n                f\"{field.name}=\"\n                f\"{get_pretty_function_description(getattr(self, field.name))}\"\n                for field in dataclasses.fields(self)\n                if getattr(self, field.name)\n            ]\n            self._cached_repr = f\"{self.__class__.__name__}({', '.join(bits)})\"\n        return self._cached_repr\n\n    def __hash__(self):\n        # sampled_from uses hash in calc_label, and we want this to be fast when\n        # sampling stateful rules, so we cache here.\n        if self._cached_hash is None:\n            self._cached_hash = hash(\n                (\n                    self.targets,\n                    self.function,\n                    tuple(self.arguments.items()),\n                    self.preconditions,\n                    self.bundles,\n                )\n            )\n        return self._cached_hash\n\n\nself_strategy = st.runner()\n\n\nclass BundleReferenceStrategy(SearchStrategy):\n    def __init__(self, name: str, *, consume: bool = False):\n        super().__init__()\n        self.name = name\n        self.consume = consume\n\n    def do_draw(self, data):\n        machine = data.draw(self_strategy)\n        bundle = machine.bundle(self.name)\n        if not bundle:\n            data.mark_invalid(f\"Cannot draw from empty bundle {self.name!r}\")\n        # Shrink towards the right rather than the left. This makes it easier\n        # to delete data generated earlier, as when the error is towards the\n        # end there can be a lot of hard to remove padding.\n        position = data.draw_integer(0, len(bundle) - 1, shrink_towards=len(bundle))\n        if self.consume:\n            return bundle.pop(position)  # pragma: no cover  # coverage is flaky here\n        else:\n            return bundle[position]\n\n\nclass Bundle(SearchStrategy[Ex]):\n    \"\"\"A collection of values for use in stateful testing.\n\n    Bundles are a kind of strategy where values can be added by rules,\n    and (like any strategy) used as inputs to future rules.\n\n    The ``name`` argument they are passed is the they are referred to\n    internally by the state machine; no two bundles may have\n    the same name. It is idiomatic to use the attribute\n    being assigned to as the name of the Bundle::\n\n        class MyStateMachine(RuleBasedStateMachine):\n            keys = Bundle(\"keys\")\n\n    Bundles can contain the same value more than once; this becomes\n    relevant when using :func:`~hypothesis.stateful.consumes` to remove\n    values again.\n\n    If the ``consume`` argument is set to True, then all values that are\n    drawn from this bundle will be consumed (as above) when requested.\n    \"\"\"\n\n    def __init__(\n        self, name: str, *, consume: bool = False, draw_references: bool = True\n    ) -> None:\n        super().__init__()\n        self.name = name\n        self.__reference_strategy = BundleReferenceStrategy(name, consume=consume)\n        self.draw_references = draw_references\n\n    def do_draw(self, data):\n        machine = data.draw(self_strategy)\n        reference = data.draw(self.__reference_strategy)\n        return machine.names_to_values[reference.name]\n\n    def __repr__(self):\n        consume = self.__reference_strategy.consume\n        if consume is False:\n            return f\"Bundle(name={self.name!r})\"\n        return f\"Bundle(name={self.name!r}, {consume=})\"\n\n    def calc_is_empty(self, recur):\n        # We assume that a bundle will grow over time\n        return False\n\n    def is_currently_empty(self, data):\n        # ``self_strategy`` is an instance of the ``st.runner()`` strategy.\n        # Hence drawing from it only returns the current state machine without\n        # modifying the underlying choice sequence.\n        machine = data.draw(self_strategy)\n        return not bool(machine.bundle(self.name))\n\n    def flatmap(self, expand):\n        if self.draw_references:\n            return type(self)(\n                self.name,\n                consume=self.__reference_strategy.consume,\n                draw_references=False,\n            ).flatmap(expand)\n        return super().flatmap(expand)\n\n    def __hash__(self):\n        # Making this hashable means we hit the fast path of \"everything is\n        # hashable\" in st.sampled_from label calculation when sampling which rule\n        # to invoke next.\n\n        # Mix in \"Bundle\" for collision resistance\n        return hash((\"Bundle\", self.name))\n\n\nclass BundleConsumer(Bundle[Ex]):\n    def __init__(self, bundle: Bundle[Ex]) -> None:\n        super().__init__(bundle.name, consume=True)\n\n\ndef consumes(bundle: Bundle[Ex]) -> SearchStrategy[Ex]:\n    \"\"\"When introducing a rule in a RuleBasedStateMachine, this function can\n    be used to mark bundles from which each value used in a step with the\n    given rule should be removed. This function returns a strategy object\n    that can be manipulated and combined like any other.\n\n    For example, a rule declared with\n\n    ``@rule(value1=b1, value2=consumes(b2), value3=lists(consumes(b3)))``\n\n    will consume a value from Bundle ``b2`` and several values from Bundle\n    ``b3`` to populate ``value2`` and ``value3`` each time it is executed.\n    \"\"\"\n    if not isinstance(bundle, Bundle):\n        raise TypeError(\"Argument to be consumed must be a bundle.\")\n    return BundleConsumer(bundle)\n\n\n@dataclass(slots=True, frozen=True)\nclass MultipleResults(Iterable[Ex]):\n    values: tuple[Ex, ...]\n\n    def __iter__(self):\n        return iter(self.values)\n\n\ndef multiple(*args: T) -> MultipleResults[T]:\n    \"\"\"This function can be used to pass multiple results to the target(s) of\n    a rule. Just use ``return multiple(result1, result2, ...)`` in your rule.\n\n    It is also possible to use ``return multiple()`` with no arguments in\n    order to end a rule without passing any result.\n    \"\"\"\n    return MultipleResults(args)\n\n\ndef _convert_targets(targets, target):\n    \"\"\"Single validator and converter for target arguments.\"\"\"\n    if target is not None:\n        if targets:\n            raise InvalidArgument(\n                f\"Passing both targets={targets!r} and target={target!r} is \"\n                f\"redundant - pass targets={(*targets, target)!r} instead.\"\n            )\n        targets = (target,)\n\n    converted_targets = []\n    for t in targets:\n        if not isinstance(t, Bundle):\n            msg = \"Got invalid target %r of type %r, but all targets must be Bundles.\"\n            if isinstance(t, OneOfStrategy):\n                msg += (\n                    \"\\nIt looks like you passed `one_of(a, b)` or `a | b` as \"\n                    \"a target.  You should instead pass `targets=(a, b)` to \"\n                    \"add the return value of this rule to both the `a` and \"\n                    \"`b` bundles, or define a rule for each target if it \"\n                    \"should be added to exactly one.\"\n                )\n            raise InvalidArgument(msg % (t, type(t)))\n        while isinstance(t, Bundle):\n            if isinstance(t, BundleConsumer):\n                note_deprecation(\n                    f\"Using consumes({t.name}) doesn't makes sense in this context.  \"\n                    \"This will be an error in a future version of Hypothesis.\",\n                    since=\"2021-09-08\",\n                    has_codemod=False,\n                    stacklevel=2,\n                )\n            t = t.name\n        converted_targets.append(t)\n    return tuple(converted_targets)\n\n\nRULE_MARKER = \"hypothesis_stateful_rule\"\nINITIALIZE_RULE_MARKER = \"hypothesis_stateful_initialize_rule\"\nPRECONDITIONS_MARKER = \"hypothesis_stateful_preconditions\"\nINVARIANT_MARKER = \"hypothesis_stateful_invariant\"\n\n\n_RuleType = Callable[..., MultipleResults[Ex] | Ex]\n_RuleWrapper = Callable[[_RuleType[Ex]], _RuleType[Ex]]\n\n\ndef _rule_qualname(f: Any) -> str:\n    # we define rules / invariants / initializes inside of wrapper functions, which\n    # makes f.__qualname__ look like:\n    #   test_precondition.<locals>.BadStateMachine.has_precondition_but_no_rule\n    # which is not ideal. This function returns just\n    #   BadStateMachine.has_precondition_but_no_rule\n    # instead.\n    return f.__qualname__.rsplit(\"<locals>.\")[-1]\n\n\n# We cannot exclude `target` or `targets` from any of these signatures because\n# otherwise they would be matched against the `kwargs`, either leading to\n# overlapping overloads of incompatible return types, or a concrete\n# implementation that does not accept all overloaded variant signatures.\n# Although it is possible to reorder the variants to fix the former, it will\n# always lead to the latter, as then the omitted parameter could be typed as\n# a `SearchStrategy`, which the concrete implementation does not accept.\n#\n# Omitted `targets` parameters, where the default value is used, are typed with\n# a special `_OmittedArgument` type. We cannot type them as `tuple[()]`, because\n# `tuple[()]` is a subtype of `Sequence[Bundle[Ex]]`, leading to signature\n# overlaps with incompatible return types. The `_OmittedArgument` type will never be\n# encountered at runtime, and exists solely to annotate the default of `targets`.\n# PEP 661 (Sentinel Values) might provide a more elegant alternative in the future.\n#\n# We could've also annotated `targets` as `tuple[_OmittedArgument]`, but then when\n# both `target` and `targets` are provided, mypy describes the type error as an\n# invalid argument type for `targets` (expected `tuple[_OmittedArgument]`, got ...).\n# By annotating it as a bare `_OmittedArgument` type, mypy's error will warn that\n# there is no overloaded signature matching the call, which is more descriptive.\n#\n# When `target` xor `targets` is provided, the function to decorate must return\n# a value whose type matches the one stored in the bundle. When neither are\n# provided, the function to decorate must return nothing. There is no variant\n# for providing `target` and `targets`, as these parameters are mutually exclusive.\n@overload\ndef rule(\n    *,\n    targets: Sequence[Bundle[Ex]],\n    target: None = ...,\n    **kwargs: SearchStrategy,\n) -> _RuleWrapper[Ex]:  # pragma: no cover\n    ...\n\n\n@overload\ndef rule(\n    *, target: Bundle[Ex], targets: _OmittedArgument = ..., **kwargs: SearchStrategy\n) -> _RuleWrapper[Ex]:  # pragma: no cover\n    ...\n\n\n@overload\ndef rule(\n    *,\n    target: None = ...,\n    targets: _OmittedArgument = ...,\n    **kwargs: SearchStrategy,\n) -> Callable[[Callable[..., None]], Callable[..., None]]:  # pragma: no cover\n    ...\n\n\ndef rule(\n    *,\n    targets: Sequence[Bundle[Ex]] | _OmittedArgument = (),\n    target: Bundle[Ex] | None = None,\n    **kwargs: SearchStrategy,\n) -> _RuleWrapper[Ex] | Callable[[Callable[..., None]], Callable[..., None]]:\n    \"\"\"Decorator for RuleBasedStateMachine. Any Bundle present in ``target`` or\n    ``targets`` will define where the end result of this function should go. If\n    both are empty then the end result will be discarded.\n\n    ``target`` must be a Bundle, or if the result should be replicated to multiple\n    bundles you can pass a tuple of them as the ``targets`` argument.\n    It is invalid to use both arguments for a single rule.  If the result\n    should go to exactly one of several bundles, define a separate rule for\n    each case.\n\n    kwargs then define the arguments that will be passed to the function\n    invocation. If their value is a Bundle, or if it is ``consumes(b)``\n    where ``b`` is a Bundle, then values that have previously been produced\n    for that bundle will be provided. If ``consumes`` is used, the value\n    will also be removed from the bundle.\n\n    Any other kwargs should be strategies and values from them will be\n    provided.\n    \"\"\"\n    converted_targets = _convert_targets(targets, target)\n    for k, v in kwargs.items():\n        check_strategy(v, name=k)\n\n    def accept(f):\n        if getattr(f, INVARIANT_MARKER, None):\n            raise InvalidDefinition(\n                f\"{_rule_qualname(f)} is used with both @rule and @invariant, \"\n                \"which is not allowed. A function may be either a rule or an \"\n                \"invariant, but not both.\"\n            )\n        existing_rule = getattr(f, RULE_MARKER, None)\n        existing_initialize_rule = getattr(f, INITIALIZE_RULE_MARKER, None)\n        if existing_rule is not None:\n            raise InvalidDefinition(\n                f\"{_rule_qualname(f)} has been decorated with @rule twice, which is \"\n                \"not allowed.\"\n            )\n        if existing_initialize_rule is not None:\n            raise InvalidDefinition(\n                f\"{_rule_qualname(f)} has been decorated with both @rule and \"\n                \"@initialize, which is not allowed.\"\n            )\n\n        preconditions = getattr(f, PRECONDITIONS_MARKER, ())\n        rule = Rule(\n            targets=converted_targets,\n            arguments=kwargs,\n            function=f,\n            preconditions=preconditions,\n        )\n\n        @proxies(f)\n        def rule_wrapper(*args, **kwargs):\n            return f(*args, **kwargs)\n\n        setattr(rule_wrapper, RULE_MARKER, rule)\n        return rule_wrapper\n\n    return accept\n\n\n# See also comments of `rule`'s overloads.\n@overload\ndef initialize(\n    *,\n    targets: Sequence[Bundle[Ex]],\n    target: None = ...,\n    **kwargs: SearchStrategy,\n) -> _RuleWrapper[Ex]:  # pragma: no cover\n    ...\n\n\n@overload\ndef initialize(\n    *, target: Bundle[Ex], targets: _OmittedArgument = ..., **kwargs: SearchStrategy\n) -> _RuleWrapper[Ex]:  # pragma: no cover\n    ...\n\n\n@overload\ndef initialize(\n    *,\n    target: None = ...,\n    targets: _OmittedArgument = ...,\n    **kwargs: SearchStrategy,\n) -> Callable[[Callable[..., None]], Callable[..., None]]:  # pragma: no cover\n    ...\n\n\ndef initialize(\n    *,\n    targets: Sequence[Bundle[Ex]] | _OmittedArgument = (),\n    target: Bundle[Ex] | None = None,\n    **kwargs: SearchStrategy,\n) -> _RuleWrapper[Ex] | Callable[[Callable[..., None]], Callable[..., None]]:\n    \"\"\"Decorator for RuleBasedStateMachine.\n\n    An initialize decorator behaves like a rule, but all ``@initialize()`` decorated\n    methods will be called before any ``@rule()`` decorated methods, in an arbitrary\n    order.  Each ``@initialize()`` method will be called exactly once per run, unless\n    one raises an exception - after which only the ``.teardown()`` method will be run.\n    ``@initialize()`` methods may not have preconditions.\n    \"\"\"\n    converted_targets = _convert_targets(targets, target)\n    for k, v in kwargs.items():\n        check_strategy(v, name=k)\n\n    def accept(f):\n        if getattr(f, INVARIANT_MARKER, None):\n            raise InvalidDefinition(\n                f\"{_rule_qualname(f)} is used with both @initialize and @invariant, \"\n                \"which is not allowed. A function may be either an initialization \"\n                \"rule or an invariant, but not both.\"\n            )\n        existing_rule = getattr(f, RULE_MARKER, None)\n        existing_initialize_rule = getattr(f, INITIALIZE_RULE_MARKER, None)\n        if existing_rule is not None:\n            raise InvalidDefinition(\n                f\"{_rule_qualname(f)} has been decorated with both @rule and \"\n                \"@initialize, which is not allowed.\"\n            )\n        if existing_initialize_rule is not None:\n            raise InvalidDefinition(\n                f\"{_rule_qualname(f)} has been decorated with @initialize twice, \"\n                \"which is not allowed.\"\n            )\n        preconditions = getattr(f, PRECONDITIONS_MARKER, ())\n        if preconditions:\n            raise InvalidDefinition(\n                f\"{_rule_qualname(f)} has been decorated with both @initialize and \"\n                \"@precondition, which is not allowed. An initialization rule \"\n                \"runs unconditionally and may not have a precondition.\"\n            )\n        rule = Rule(\n            targets=converted_targets,\n            arguments=kwargs,\n            function=f,\n            preconditions=preconditions,\n        )\n\n        @proxies(f)\n        def rule_wrapper(*args, **kwargs):\n            return f(*args, **kwargs)\n\n        setattr(rule_wrapper, INITIALIZE_RULE_MARKER, rule)\n        return rule_wrapper\n\n    return accept\n\n\n@dataclass(slots=True, frozen=True)\nclass VarReference:\n    name: str\n\n\n# There are multiple alternatives for annotating the `precond` type, all of them\n# have drawbacks. See https://github.com/HypothesisWorks/hypothesis/pull/3068#issuecomment-906642371\ndef precondition(precond: Callable[[Any], bool]) -> Callable[[TestFunc], TestFunc]:\n    \"\"\"Decorator to apply a precondition for rules in a RuleBasedStateMachine.\n    Specifies a precondition for a rule to be considered as a valid step in the\n    state machine, which is more efficient than using :func:`~hypothesis.assume`\n    within the rule.  The ``precond`` function will be called with the instance of\n    RuleBasedStateMachine and should return True or False. Usually it will need\n    to look at attributes on that instance.\n\n    For example::\n\n        class MyTestMachine(RuleBasedStateMachine):\n            state = 1\n\n            @precondition(lambda self: self.state != 0)\n            @rule(numerator=integers())\n            def divide_with(self, numerator):\n                self.state = numerator / self.state\n\n    If multiple preconditions are applied to a single rule, it is only considered\n    a valid step when all of them return True.  Preconditions may be applied to\n    invariants as well as rules.\n    \"\"\"\n\n    def decorator(f):\n        @proxies(f)\n        def precondition_wrapper(*args, **kwargs):\n            return f(*args, **kwargs)\n\n        existing_initialize_rule = getattr(f, INITIALIZE_RULE_MARKER, None)\n        if existing_initialize_rule is not None:\n            raise InvalidDefinition(\n                f\"{_rule_qualname(f)} has been decorated with both @initialize and \"\n                \"@precondition, which is not allowed. An initialization rule \"\n                \"runs unconditionally and may not have a precondition.\"\n            )\n\n        rule = getattr(f, RULE_MARKER, None)\n        invariant = getattr(f, INVARIANT_MARKER, None)\n        if rule is not None:\n            assert invariant is None\n            new_rule = dataclasses.replace(\n                rule, preconditions=(*rule.preconditions, precond)\n            )\n            setattr(precondition_wrapper, RULE_MARKER, new_rule)\n        elif invariant is not None:\n            assert rule is None\n            new_invariant = dataclasses.replace(\n                invariant, preconditions=(*invariant.preconditions, precond)\n            )\n            setattr(precondition_wrapper, INVARIANT_MARKER, new_invariant)\n        else:\n            setattr(\n                precondition_wrapper,\n                PRECONDITIONS_MARKER,\n                (*getattr(f, PRECONDITIONS_MARKER, ()), precond),\n            )\n\n        return precondition_wrapper\n\n    return decorator\n\n\n@dataclass(slots=True, frozen=True)\nclass Invariant:\n    function: Any\n    preconditions: Any\n    check_during_init: bool\n\n    def __repr__(self) -> str:\n        parts = [\n            f\"function={get_pretty_function_description(self.function)}\",\n            f\"{self.preconditions=}\",\n            f\"{self.check_during_init=}\",\n        ]\n        return f\"Invariant({', '.join(parts)})\"\n\n\ndef invariant(*, check_during_init: bool = False) -> Callable[[TestFunc], TestFunc]:\n    \"\"\"Decorator to apply an invariant for rules in a RuleBasedStateMachine.\n    The decorated function will be run after every rule and can raise an\n    exception to indicate failed invariants.\n\n    For example::\n\n        class MyTestMachine(RuleBasedStateMachine):\n            state = 1\n\n            @invariant()\n            def is_nonzero(self):\n                assert self.state != 0\n\n    By default, invariants are only checked after all\n    :func:`@initialize() <hypothesis.stateful.initialize>` rules have been run.\n    Pass ``check_during_init=True`` for invariants which can also be checked\n    during initialization.\n    \"\"\"\n    check_type(bool, check_during_init, \"check_during_init\")\n\n    def accept(f):\n        if getattr(f, RULE_MARKER, None) or getattr(f, INITIALIZE_RULE_MARKER, None):\n            raise InvalidDefinition(\n                f\"{_rule_qualname(f)} has been decorated with both @invariant and \"\n                \"@rule, which is not allowed.\"\n            )\n        existing_invariant = getattr(f, INVARIANT_MARKER, None)\n        if existing_invariant is not None:\n            raise InvalidDefinition(\n                f\"{_rule_qualname(f)} has been decorated with @invariant twice, \"\n                \"which is not allowed.\"\n            )\n        preconditions = getattr(f, PRECONDITIONS_MARKER, ())\n        invar = Invariant(\n            function=f,\n            preconditions=preconditions,\n            check_during_init=check_during_init,\n        )\n\n        @proxies(f)\n        def invariant_wrapper(*args, **kwargs):\n            return f(*args, **kwargs)\n\n        setattr(invariant_wrapper, INVARIANT_MARKER, invar)\n        return invariant_wrapper\n\n    return accept\n\n\nclass RuleStrategy(SearchStrategy):\n    def __init__(self, machine: RuleBasedStateMachine) -> None:\n        super().__init__()\n        self.machine = machine\n        self.rules = machine.rules.copy()\n\n        self.enabled_rules_strategy = st.shared(\n            FeatureStrategy(at_least_one_of={r.function.__name__ for r in self.rules}),\n            key=(\"enabled rules\", machine),\n        )\n\n        # The order is a bit arbitrary. Primarily we're trying to group rules\n        # that write to the same location together, and to put rules with no\n        # target first as they have less effect on the structure. We order from\n        # fewer to more arguments on grounds that it will plausibly need less\n        # data. This probably won't work especially well and we could be\n        # smarter about it, but it's better than just doing it in definition\n        # order.\n        self.rules.sort(\n            key=lambda rule: (\n                sorted(rule.targets),\n                len(rule.arguments),\n                rule.function.__name__,\n            )\n        )\n        self.rules_strategy = st.sampled_from(self.rules)\n\n    def __repr__(self):\n        return f\"{self.__class__.__name__}(machine={self.machine.__class__.__name__}({{...}}))\"\n\n    def do_draw(self, data):\n        if not any(self.is_valid(rule) for rule in self.rules):\n            rules = \", \".join([rule.function.__name__ for rule in self.rules])\n            msg = (\n                f\"No progress can be made from state {self.machine!r}, because no \"\n                f\"available rule had a True precondition. rules: {rules}\"\n            )\n            raise InvalidDefinition(msg) from None\n\n        feature_flags = data.draw(self.enabled_rules_strategy)\n\n        def rule_is_enabled(r):\n            # Note: The order of the filters here is actually quite important,\n            # because checking is_enabled makes choices, so increases the size of\n            # the choice sequence. This means that if we are in a case where many\n            # rules are invalid we would make a lot more choices if we ask if they\n            # are enabled before we ask if they are valid, so our test cases would\n            # be artificially large.\n            return self.is_valid(r) and feature_flags.is_enabled(r.function.__name__)\n\n        rule = data.draw(self.rules_strategy.filter(rule_is_enabled))\n\n        arguments = {}\n        for k, strat in rule.arguments_strategies.items():\n            try:\n                arguments[k] = data.draw(strat)\n            except Exception as err:\n                rname = rule.function.__name__\n                add_note(err, f\"while generating {k!r} from {strat!r} for rule {rname}\")\n                raise\n        return (rule, arguments)\n\n    def is_valid(self, rule):\n        for b in rule.bundles:\n            if not self.machine.bundle(b.name):\n                return False\n\n        predicates = self.machine._observability_predicates\n        desc = f\"{self.machine.__class__.__qualname__}, rule {rule.function.__name__},\"\n        for pred in rule.preconditions:\n            meets_precond = pred(self.machine)\n            where = f\"{desc} precondition {get_pretty_function_description(pred)}\"\n            predicates[where].update_count(condition=meets_precond)\n            if not meets_precond:\n                return False\n\n        return True\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/statistics.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nfrom collections import Counter\nfrom collections.abc import Iterable\nfrom typing import TYPE_CHECKING, cast\n\nfrom hypothesis._settings import Phase\nfrom hypothesis.utils.dynamicvariables import DynamicVariable\n\nif TYPE_CHECKING:\n    from hypothesis.internal.conjecture.engine import PhaseStatistics, StatisticsDict\n\ncollector = DynamicVariable(None)\n\n\ndef note_statistics(stats_dict: \"StatisticsDict\") -> None:\n    callback = collector.value\n    if callback is not None:\n        callback(stats_dict)\n\n\ndef describe_targets(best_targets: dict[str, float]) -> list[str]:\n    \"\"\"Return a list of lines describing the results of `target`, if any.\"\"\"\n    # These lines are included in the general statistics description below,\n    # but also printed immediately below failing examples to alleviate the\n    # \"threshold problem\" where shrinking can make severe bug look trivial.\n    # See https://github.com/HypothesisWorks/hypothesis/issues/2180\n    if not best_targets:\n        return []\n    elif len(best_targets) == 1:\n        label, score = next(iter(best_targets.items()))\n        return [f\"Highest target score: {score:g}  ({label=})\"]\n    else:\n        lines = [\"Highest target scores:\"]\n        for label, score in sorted(best_targets.items(), key=lambda x: x[::-1]):\n            lines.append(f\"{score:>16g}  ({label=})\")\n        return lines\n\n\ndef format_ms(times: Iterable[float]) -> str:\n    \"\"\"Format `times` into a string representing approximate milliseconds.\n\n    `times` is a collection of durations in seconds.\n    \"\"\"\n    ordered = sorted(times)\n    n = len(ordered) - 1\n    if n < 0 or any(math.isnan(t) for t in ordered):  # pragma: no cover\n        return \"NaN ms\"\n    lower = int(ordered[math.floor(n * 0.05)] * 1000)\n    upper = int(ordered[math.ceil(n * 0.95)] * 1000)\n    if upper == 0:\n        return \"< 1ms\"\n    elif lower == upper:\n        return f\"~ {lower}ms\"\n    else:\n        return f\"~ {lower}-{upper} ms\"\n\n\ndef describe_statistics(stats_dict: \"StatisticsDict\") -> str:\n    \"\"\"Return a multi-line string describing the passed run statistics.\n\n    `stats_dict` must be a dictionary of data in the format collected by\n    `hypothesis.internal.conjecture.engine.ConjectureRunner.statistics`.\n\n    We DO NOT promise that this format will be stable or supported over\n    time, but do aim to make it reasonably useful for downstream users.\n    It's also meant to support benchmarking for research purposes.\n\n    This function is responsible for the report which is printed in the\n    terminal for our pytest --hypothesis-show-statistics option.\n    \"\"\"\n    lines = [stats_dict[\"nodeid\"] + \":\\n\"] if \"nodeid\" in stats_dict else []\n    prev_failures = 0\n    for phase in (p.name for p in list(Phase)[1:]):\n        d = cast(\"PhaseStatistics\", stats_dict.get(phase + \"-phase\", {}))\n        # Basic information we report for every phase\n        cases = d.get(\"test-cases\", [])\n        if not cases:\n            continue\n        statuses = Counter(t[\"status\"] for t in cases)\n        runtime_ms = format_ms(t[\"runtime\"] for t in cases)\n        drawtime_ms = format_ms(t[\"drawtime\"] for t in cases)\n        lines.append(\n            f\"  - during {phase} phase ({d['duration-seconds']:.2f} seconds):\\n\"\n            f\"    - Typical runtimes: {runtime_ms}, of which {drawtime_ms} in data generation\\n\"\n            f\"    - {statuses['valid']} passing examples, {statuses['interesting']} \"\n            f\"failing examples, {statuses['invalid'] + statuses['overrun']} invalid examples\"\n        )\n        # If we've found new distinct failures in this phase, report them\n        distinct_failures = d[\"distinct-failures\"] - prev_failures\n        if distinct_failures:\n            plural = distinct_failures > 1\n            lines.append(\n                \"    - Found {}{} distinct error{} in this phase\".format(\n                    distinct_failures, \" more\" * bool(prev_failures), \"s\" * plural\n                )\n            )\n        prev_failures = d[\"distinct-failures\"]\n        # Report events during the generate phase, if there were any\n        if phase == \"generate\":\n            events = Counter(sum((t[\"events\"] for t in cases), []))\n            if events:\n                lines.append(\"    - Events:\")\n                lines += [\n                    f\"      * {100 * v / len(cases):.2f}%, {k}\"\n                    for k, v in sorted(events.items(), key=lambda x: (-x[1], x[0]))\n                ]\n        # Some additional details on the shrinking phase\n        if phase == \"shrink\":\n            lines.append(\n                \"    - Tried {} shrinks of which {} were successful\".format(\n                    len(cases), d[\"shrinks-successful\"]\n                )\n            )\n        lines.append(\"\")\n\n    target_lines = describe_targets(stats_dict.get(\"targets\", {}))\n    if target_lines:\n        lines.append(\"  - \" + target_lines[0])\n        lines.extend(\"    \" + l for l in target_lines[1:])\n    lines.append(\"  - Stopped because \" + stats_dict[\"stopped-because\"])\n    return \"\\n\".join(lines)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.strategies._internal import SearchStrategy\nfrom hypothesis.strategies._internal.collections import tuples\nfrom hypothesis.strategies._internal.core import (\n    DataObject,\n    DrawFn,\n    binary,\n    booleans,\n    builds,\n    characters,\n    complex_numbers,\n    composite,\n    data,\n    decimals,\n    deferred,\n    dictionaries,\n    emails,\n    fixed_dictionaries,\n    fractions,\n    from_regex,\n    from_type,\n    frozensets,\n    functions,\n    iterables,\n    lists,\n    permutations,\n    random_module,\n    randoms,\n    recursive,\n    register_type_strategy,\n    runner,\n    sampled_from,\n    sets,\n    shared,\n    slices,\n    text,\n    uuids,\n)\nfrom hypothesis.strategies._internal.datetime import (\n    dates,\n    datetimes,\n    timedeltas,\n    times,\n    timezone_keys,\n    timezones,\n)\nfrom hypothesis.strategies._internal.ipaddress import ip_addresses\nfrom hypothesis.strategies._internal.misc import just, none, nothing\nfrom hypothesis.strategies._internal.numbers import floats, integers\nfrom hypothesis.strategies._internal.strategies import one_of\nfrom hypothesis.strategies._internal.utils import _all_strategies\n\n# The implementation of all of these lives in `_strategies.py`, but we\n# re-export them via this module to avoid exposing implementation details\n# to over-zealous tab completion in editors that do not respect __all__.\n\n\n__all__ = [\n    \"DataObject\",\n    \"DrawFn\",\n    \"SearchStrategy\",\n    \"binary\",\n    \"booleans\",\n    \"builds\",\n    \"characters\",\n    \"complex_numbers\",\n    \"composite\",\n    \"data\",\n    \"dates\",\n    \"datetimes\",\n    \"decimals\",\n    \"deferred\",\n    \"dictionaries\",\n    \"emails\",\n    \"fixed_dictionaries\",\n    \"floats\",\n    \"fractions\",\n    \"from_regex\",\n    \"from_type\",\n    \"frozensets\",\n    \"functions\",\n    \"integers\",\n    \"ip_addresses\",\n    \"iterables\",\n    \"just\",\n    \"lists\",\n    \"none\",\n    \"nothing\",\n    \"one_of\",\n    \"permutations\",\n    \"random_module\",\n    \"randoms\",\n    \"recursive\",\n    \"register_type_strategy\",\n    \"runner\",\n    \"sampled_from\",\n    \"sets\",\n    \"shared\",\n    \"slices\",\n    \"text\",\n    \"timedeltas\",\n    \"times\",\n    \"timezone_keys\",\n    \"timezones\",\n    \"tuples\",\n    \"uuids\",\n]\n\n\ndef _check_exports(_public):\n    assert set(__all__) == _public, (set(__all__) - _public, _public - set(__all__))\n\n    # Verify that all exported strategy functions were registered with\n    # @declares_strategy.\n\n    existing_strategies = set(_all_strategies) - {\"_maybe_nil_uuids\"}\n\n    exported_strategies = set(__all__) - {\n        \"DataObject\",\n        \"DrawFn\",\n        \"SearchStrategy\",\n        \"composite\",\n        \"register_type_strategy\",\n    }\n    assert existing_strategies == exported_strategies, (\n        existing_strategies - exported_strategies,\n        exported_strategies - existing_strategies,\n    )\n\n\n_check_exports({n for n in dir() if n[0] not in \"_@\"})\ndel _check_exports\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"Package defining SearchStrategy, which is the core type that Hypothesis uses\nto explore data.\"\"\"\n\nfrom .strategies import SearchStrategy, check_strategy\n\n__all__ = [\"SearchStrategy\", \"check_strategy\"]\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/attrs.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n# Since Hypothesis doesn't have a hard dependency on attrs, be careful to only import\n# this file when attrs is in sys.modules.\n\nfrom collections.abc import Collection, Generator, Iterable, Sequence\nfrom functools import reduce\nfrom itertools import chain\nfrom types import EllipsisType\nfrom typing import Any, TypeVar\n\nimport attr\n\n# attr/validators.pyi does not expose types for these, even though they exist\n# in source.\nfrom attr.validators import (  # type: ignore\n    _AndValidator,\n    _InstanceOfValidator,\n    _InValidator,\n    _OptionalValidator,\n)\nfrom attrs import Attribute, AttrsInstance, Factory\n\nfrom hypothesis import strategies as st\nfrom hypothesis.errors import ResolutionFailed\nfrom hypothesis.internal.compat import get_type_hints\nfrom hypothesis.strategies._internal.core import BuildsStrategy\nfrom hypothesis.strategies._internal.strategies import SearchStrategy\nfrom hypothesis.strategies._internal.types import is_a_type, type_sorting_key\nfrom hypothesis.utils.conventions import infer\n\nT = TypeVar(\"T\")\n\n\ndef get_attribute_by_alias(\n    fields: Iterable[Attribute],\n    alias: str,\n    *,\n    target: type[AttrsInstance] | None = None,\n) -> Attribute:\n    \"\"\"\n    Get an attrs attribute by its alias, rather than its name (compare\n    getattr(fields, name)).\n\n    ``target`` is used only to provide a nicer error message, and can be safely\n    omitted.\n    \"\"\"\n    # attrs supports defining an alias for a field, which is the name used when\n    # defining __init__. The init args are what we pull from when determining\n    # what parameters we need to supply to the class, so it's what we need to\n    # match against as well, rather than the class-level attribute name.\n    matched_fields = [f for f in fields if f.alias == alias]\n    if not matched_fields:\n        raise TypeError(\n            f\"Unexpected keyword argument {alias} for attrs class\"\n            f\"{f' {target}' if target else ''}. Expected one of \"\n            f\"{[f.name for f in fields]}\"\n        )\n    # alias is used as an arg in __init__, so it is guaranteed to be unique, if\n    # it exists.\n    assert len(matched_fields) == 1\n    return matched_fields[0]\n\n\ndef from_attrs(\n    target: type[AttrsInstance],\n    args: tuple[SearchStrategy[Any], ...],\n    kwargs: dict[str, SearchStrategy[Any] | EllipsisType],\n    to_infer: Iterable[str],\n) -> SearchStrategy:\n    \"\"\"An internal version of builds(), specialised for Attrs classes.\"\"\"\n    attributes: tuple[Attribute, ...] = attr.fields(target)\n    kwargs = {k: v for k, v in kwargs.items() if v is not infer}\n    for name in to_infer:\n        attrib = get_attribute_by_alias(attributes, name, target=target)\n        kwargs[name] = from_attrs_attribute(attrib, target)\n    # We might make this strategy more efficient if we added a layer here that\n    # retries drawing if validation fails, for improved composition.\n    # The treatment of timezones in datetimes() provides a precedent.\n    return BuildsStrategy(target, args, kwargs)\n\n\ndef from_attrs_attribute(\n    attrib: Attribute, target: type[AttrsInstance]\n) -> SearchStrategy:\n    \"\"\"Infer a strategy from the metadata on an attr.Attribute object.\"\"\"\n    # Try inferring from the default argument.  Note that this will only help if\n    # the user passed `...` to builds() for this attribute, but in that case\n    # we use it as the minimal example.\n    default: SearchStrategy = st.nothing()\n    # attr/__init__.pyi uses overloads to declare Factory as a function, not a\n    # class. This is a fib - at runtime and always, it is a class.\n    if isinstance(attrib.default, Factory):  # type: ignore\n        assert attrib.default is not None\n        if not attrib.default.takes_self:\n            default = st.builds(attrib.default.factory)\n    elif attrib.default is not attr.NOTHING:\n        default = st.just(attrib.default)\n\n    # Try inferring None, exact values, or type from attrs provided validators.\n\n    # updated to none() on seeing an OptionalValidator\n    null: SearchStrategy = st.nothing()\n    # list of in_ validator collections to sample from\n    in_collections = []\n    # type constraints to pass to types_to_strategy()\n    validator_types = set()\n    if attrib.validator is not None:\n        validator = attrib.validator\n        if isinstance(validator, _OptionalValidator):\n            null = st.none()\n            validator = validator.validator\n        if isinstance(validator, _AndValidator):\n            vs = validator._validators\n        else:\n            vs = [validator]\n        for v in vs:\n            if isinstance(v, _InValidator):\n                if isinstance(v.options, str):\n                    in_collections.append(list(all_substrings(v.options)))\n                else:\n                    in_collections.append(v.options)\n            elif isinstance(v, _InstanceOfValidator):\n                validator_types.add(v.type)\n\n    # This is the important line.  We compose the final strategy from various\n    # parts.  The default value, if any, is the minimal shrink, followed by\n    # None (again, if allowed).  We then prefer to sample from values passed\n    # to an in_ validator if available, but infer from a type otherwise.\n    # Pick one because (sampled_from((1, 2)) | from_type(int)) would usually\n    # fail validation by generating e.g. zero!\n    if in_collections:\n        sample = st.sampled_from(list(ordered_intersection(in_collections)))\n        strat = default | null | sample\n    else:\n        strat = default | null | types_to_strategy(attrib, validator_types)\n\n    # Better to give a meaningful error here than an opaque \"could not draw\"\n    # when we try to get a value but have lost track of where this was created.\n    if strat.is_empty:\n        raise ResolutionFailed(\n            \"Cannot infer a strategy from the default, validator, type, or \"\n            f\"converter for attribute={attrib!r} of class={target!r}\"\n        )\n    return strat\n\n\ndef types_to_strategy(attrib: Attribute, types: Collection[Any]) -> SearchStrategy:\n    \"\"\"Find all the type metadata for this attribute, reconcile it, and infer a\n    strategy from the mess.\"\"\"\n    # If we know types from the validator(s), that's sufficient.\n    if len(types) == 1:\n        (typ,) = types\n        if isinstance(typ, tuple):\n            return st.one_of(*map(st.from_type, typ))\n        return st.from_type(typ)\n    elif types:\n        # We have a list of tuples of types, and want to find a type\n        # (or tuple of types) that is a subclass of all of them.\n        type_tuples = [k if isinstance(k, tuple) else (k,) for k in types]\n        # Flatten the list, filter types that would fail validation, and\n        # sort so that ordering is stable between runs and shrinks well.\n        allowed = [\n            t\n            for t in set(sum(type_tuples, ()))\n            if all(issubclass(t, tup) for tup in type_tuples)\n        ]\n        allowed.sort(key=type_sorting_key)\n        return st.one_of([st.from_type(t) for t in allowed])\n\n    # Otherwise, try the `type` attribute as a fallback, and finally try\n    # the type hints on a converter (desperate!) before giving up.\n    if is_a_type(getattr(attrib, \"type\", None)):\n        assert attrib.type is not None\n        # The convoluted test is because variable annotations may be stored\n        # in string form; attrs doesn't evaluate them and we don't handle them.\n        # See PEP 526, PEP 563, and Hypothesis issue #1004 for details.\n        return st.from_type(attrib.type)\n\n    converter = getattr(attrib, \"converter\", None)\n    if isinstance(converter, type):\n        return st.from_type(converter)\n    elif callable(converter):\n        hints = get_type_hints(converter)\n        if \"return\" in hints:\n            return st.from_type(hints[\"return\"])\n\n    return st.nothing()\n\n\ndef ordered_intersection(in_: Sequence[Iterable[T]]) -> Generator[T, None, None]:\n    \"\"\"Set union of n sequences, ordered for reproducibility across runs.\"\"\"\n    intersection = reduce(set.intersection, in_, set(in_[0]))\n    for x in chain.from_iterable(in_):\n        if x in intersection:\n            yield x\n            intersection.remove(x)\n\n\ndef all_substrings(s: str) -> Generator[str, None, None]:\n    \"\"\"Generate all substrings of `s`, in order of length then occurrence.\n    Includes the empty string (first), and any duplicates that are present.\n\n    >>> list(all_substrings('010'))\n    ['', '0', '1', '0', '01', '10', '010']\n    \"\"\"\n    yield s[:0]\n    for n, _ in enumerate(s):\n        for i in range(len(s) - n):\n            yield s[i : i + n + 1]\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/collections.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport copy\nimport math\nfrom collections.abc import Callable, Iterable\nfrom typing import Any, overload\n\nfrom hypothesis import strategies as st\nfrom hypothesis.control import current_build_context\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.conjecture import utils as cu\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.conjecture.engine import BUFFER_SIZE\nfrom hypothesis.internal.conjecture.junkdrawer import LazySequenceCopy\nfrom hypothesis.internal.conjecture.utils import combine_labels\nfrom hypothesis.internal.filtering import get_integer_predicate_bounds\nfrom hypothesis.internal.reflection import is_identity_function\nfrom hypothesis.strategies._internal.strategies import (\n    T3,\n    T4,\n    T5,\n    Ex,\n    FilteredStrategy,\n    RecurT,\n    SampledFromStrategy,\n    SearchStrategy,\n    T,\n    check_strategy,\n    filter_not_satisfied,\n)\nfrom hypothesis.strategies._internal.utils import cacheable, defines_strategy\nfrom hypothesis.utils.conventions import UniqueIdentifier\nfrom hypothesis.vendor.pretty import (\n    ArgLabelsT,\n    IDKey,\n    _fixeddict_pprinter,\n    _tuple_pprinter,\n)\n\n\nclass TupleStrategy(SearchStrategy[tuple[Ex, ...]]):\n    \"\"\"A strategy responsible for fixed length tuples based on heterogeneous\n    strategies for each of their elements.\"\"\"\n\n    def __init__(self, strategies: Iterable[SearchStrategy[Any]]):\n        super().__init__()\n        self.element_strategies = tuple(strategies)\n\n    def do_validate(self) -> None:\n        for s in self.element_strategies:\n            s.validate()\n\n    def calc_label(self) -> int:\n        return combine_labels(\n            self.class_label, *(s.label for s in self.element_strategies)\n        )\n\n    def __repr__(self) -> str:\n        tuple_string = \", \".join(map(repr, self.element_strategies))\n        return f\"TupleStrategy(({tuple_string}))\"\n\n    def calc_has_reusable_values(self, recur: RecurT) -> bool:\n        return all(recur(e) for e in self.element_strategies)\n\n    def do_draw(self, data: ConjectureData) -> tuple[Ex, ...]:\n        context = current_build_context()\n        arg_labels: ArgLabelsT = {}\n        result = []\n        for i, strategy in enumerate(self.element_strategies):\n            with context.track_arg_label(f\"arg[{i}]\") as arg_label:\n                result.append(data.draw(strategy))\n            arg_labels |= arg_label\n\n        result = tuple(result)\n        if arg_labels:\n            context.known_object_printers[IDKey(result)].append(\n                _tuple_pprinter(arg_labels)\n            )\n        return result\n\n    def calc_is_empty(self, recur: RecurT) -> bool:\n        return any(recur(e) for e in self.element_strategies)\n\n\n@overload\ndef tuples() -> SearchStrategy[tuple[()]]:  # pragma: no cover\n    ...\n\n\n@overload\ndef tuples(__a1: SearchStrategy[Ex]) -> SearchStrategy[tuple[Ex]]:  # pragma: no cover\n    ...\n\n\n@overload\ndef tuples(\n    __a1: SearchStrategy[Ex], __a2: SearchStrategy[T]\n) -> SearchStrategy[tuple[Ex, T]]:  # pragma: no cover\n    ...\n\n\n@overload\ndef tuples(\n    __a1: SearchStrategy[Ex], __a2: SearchStrategy[T], __a3: SearchStrategy[T3]\n) -> SearchStrategy[tuple[Ex, T, T3]]:  # pragma: no cover\n    ...\n\n\n@overload\ndef tuples(\n    __a1: SearchStrategy[Ex],\n    __a2: SearchStrategy[T],\n    __a3: SearchStrategy[T3],\n    __a4: SearchStrategy[T4],\n) -> SearchStrategy[tuple[Ex, T, T3, T4]]:  # pragma: no cover\n    ...\n\n\n@overload\ndef tuples(\n    __a1: SearchStrategy[Ex],\n    __a2: SearchStrategy[T],\n    __a3: SearchStrategy[T3],\n    __a4: SearchStrategy[T4],\n    __a5: SearchStrategy[T5],\n) -> SearchStrategy[tuple[Ex, T, T3, T4, T5]]:  # pragma: no cover\n    ...\n\n\n@overload\ndef tuples(\n    *args: SearchStrategy[Any],\n) -> SearchStrategy[tuple[Any, ...]]:  # pragma: no cover\n    ...\n\n\n@cacheable\n@defines_strategy()\ndef tuples(*args: SearchStrategy[Any]) -> SearchStrategy[tuple[Any, ...]]:\n    \"\"\"Return a strategy which generates a tuple of the same length as args by\n    generating the value at index i from args[i].\n\n    e.g. tuples(integers(), integers()) would generate a tuple of length\n    two with both values an integer.\n\n    Examples from this strategy shrink by shrinking their component parts.\n    \"\"\"\n    for arg in args:\n        check_strategy(arg)\n\n    return TupleStrategy(args)\n\n\nclass ListStrategy(SearchStrategy[list[Ex]]):\n    \"\"\"A strategy for lists which takes a strategy for its elements and the\n    allowed lengths, and generates lists with the correct size and contents.\"\"\"\n\n    _nonempty_filters: tuple[Callable[[Any], Any], ...] = (bool, len, tuple, list)\n\n    def __init__(\n        self,\n        elements: SearchStrategy[Ex],\n        min_size: int = 0,\n        max_size: float | int | None = math.inf,\n    ):\n        super().__init__()\n        self.min_size = min_size or 0\n        self.max_size = max_size if max_size is not None else math.inf\n        assert 0 <= self.min_size <= self.max_size\n        self.average_size = min(\n            max(self.min_size * 2, self.min_size + 5),\n            0.5 * (self.min_size + self.max_size),\n        )\n        self.element_strategy = elements\n        if min_size > BUFFER_SIZE:\n            raise InvalidArgument(\n                f\"{self!r} can never generate an example, because min_size is larger \"\n                \"than Hypothesis supports.  Including it is at best slowing down your \"\n                \"tests for no benefit; at worst making them fail (maybe flakily) with \"\n                \"a HealthCheck error.\"\n            )\n\n    def calc_label(self) -> int:\n        return combine_labels(self.class_label, self.element_strategy.label)\n\n    def do_validate(self) -> None:\n        self.element_strategy.validate()\n        if self.is_empty:\n            raise InvalidArgument(\n                \"Cannot create non-empty lists with elements drawn from \"\n                f\"strategy {self.element_strategy!r} because it has no values.\"\n            )\n        if self.element_strategy.is_empty and 0 < self.max_size < float(\"inf\"):\n            raise InvalidArgument(\n                f\"Cannot create a collection of max_size={self.max_size!r}, \"\n                \"because no elements can be drawn from the element strategy \"\n                f\"{self.element_strategy!r}\"\n            )\n\n    def calc_is_empty(self, recur: RecurT) -> bool:\n        if self.min_size == 0:\n            return False\n        return recur(self.element_strategy)\n\n    def do_draw(self, data: ConjectureData) -> list[Ex]:\n        if self.element_strategy.is_empty:\n            assert self.min_size == 0\n            return []\n\n        elements = cu.many(\n            data,\n            min_size=self.min_size,\n            max_size=self.max_size,\n            average_size=self.average_size,\n        )\n        result = []\n        while elements.more():\n            result.append(data.draw(self.element_strategy))\n        return result\n\n    def __repr__(self) -> str:\n        return (\n            f\"{self.__class__.__name__}({self.element_strategy!r}, \"\n            f\"min_size={self.min_size:_}, max_size={self.max_size:_})\"\n        )\n\n    def filter(self, condition: Callable[[list[Ex]], Any]) -> SearchStrategy[list[Ex]]:\n        if condition in self._nonempty_filters or is_identity_function(condition):\n            assert self.max_size >= 1, \"Always-empty is special cased in st.lists()\"\n            if self.min_size >= 1:\n                return self\n            new = copy.copy(self)\n            new.min_size = 1\n            return new\n\n        constraints, pred = get_integer_predicate_bounds(condition)\n        if constraints.get(\"len\") and (\n            \"min_value\" in constraints or \"max_value\" in constraints\n        ):\n            new = copy.copy(self)\n            new.min_size = max(\n                self.min_size, constraints.get(\"min_value\", self.min_size)\n            )\n            new.max_size = min(\n                self.max_size, constraints.get(\"max_value\", self.max_size)\n            )\n            # Unsatisfiable filters are easiest to understand without rewriting.\n            if new.min_size > new.max_size:\n                return SearchStrategy.filter(self, condition)\n            # Recompute average size; this is cheaper than making it into a property.\n            new.average_size = min(\n                max(new.min_size * 2, new.min_size + 5),\n                0.5 * (new.min_size + new.max_size),\n            )\n            if pred is None:\n                return new\n            return SearchStrategy.filter(new, condition)\n\n        return SearchStrategy.filter(self, condition)\n\n\nclass UniqueListStrategy(ListStrategy[Ex]):\n    def __init__(\n        self,\n        elements: SearchStrategy[Ex],\n        min_size: int,\n        max_size: float | int | None,\n        # TODO: keys are guaranteed to be Hashable, not just Any, but this makes\n        # other things harder to type\n        keys: tuple[Callable[[Ex], Any], ...],\n        tuple_suffixes: SearchStrategy[tuple[Ex, ...]] | None,\n    ):\n        super().__init__(elements, min_size, max_size)\n        self.keys = keys\n        self.tuple_suffixes = tuple_suffixes\n\n    def do_draw(self, data: ConjectureData) -> list[Ex]:\n        if self.element_strategy.is_empty:\n            assert self.min_size == 0\n            return []\n\n        elements = cu.many(\n            data,\n            min_size=self.min_size,\n            max_size=self.max_size,\n            average_size=self.average_size,\n        )\n        seen_sets: tuple[set[Ex], ...] = tuple(set() for _ in self.keys)\n        # actually list[Ex], but if self.tuple_suffixes is present then Ex is a\n        # tuple[T, ...] because self.element_strategy is a TuplesStrategy, and\n        # appending a concrete tuple to `result: list[Ex]` makes mypy unhappy\n        # without knowing that Ex = tuple.\n        result: list[Any] = []\n\n        # We construct a filtered strategy here rather than using a check-and-reject\n        # approach because some strategies have special logic for generation under a\n        # filter, and FilteredStrategy can consolidate multiple filters.\n        def not_yet_in_unique_list(val: Ex) -> bool:  # type: ignore # covariant type param\n            return all(\n                key(val) not in seen\n                for key, seen in zip(self.keys, seen_sets, strict=True)\n            )\n\n        filtered = FilteredStrategy(\n            self.element_strategy, conditions=(not_yet_in_unique_list,)\n        )\n        while elements.more():\n            value = filtered.do_filtered_draw(data)\n            if value is filter_not_satisfied:\n                elements.reject(f\"Aborted test because unable to satisfy {filtered!r}\")\n            else:\n                assert not isinstance(value, UniqueIdentifier)\n                for key, seen in zip(self.keys, seen_sets, strict=True):\n                    seen.add(key(value))\n                if self.tuple_suffixes is not None:\n                    value = (value, *data.draw(self.tuple_suffixes))  # type: ignore\n                result.append(value)\n        assert self.max_size >= len(result) >= self.min_size\n        return result\n\n\nclass UniqueSampledListStrategy(UniqueListStrategy):\n    def do_draw(self, data: ConjectureData) -> list[Ex]:\n        assert isinstance(self.element_strategy, SampledFromStrategy)\n\n        should_draw = cu.many(\n            data,\n            min_size=self.min_size,\n            max_size=self.max_size,\n            average_size=self.average_size,\n        )\n        seen_sets: tuple[set[Ex], ...] = tuple(set() for _ in self.keys)\n        result: list[Any] = []\n\n        remaining = LazySequenceCopy(self.element_strategy.elements)\n\n        while remaining and should_draw.more():\n            j = data.draw_integer(0, len(remaining) - 1)\n            value = self.element_strategy._transform(remaining.pop(j))\n            if value is not filter_not_satisfied and all(\n                key(value) not in seen\n                for key, seen in zip(self.keys, seen_sets, strict=True)\n            ):\n                for key, seen in zip(self.keys, seen_sets, strict=True):\n                    seen.add(key(value))\n                if self.tuple_suffixes is not None:\n                    value = (value, *data.draw(self.tuple_suffixes))\n                result.append(value)\n            else:\n                should_draw.reject(\n                    \"UniqueSampledListStrategy filter not satisfied or value already seen\"\n                )\n        assert self.max_size >= len(result) >= self.min_size\n        return result\n\n\nclass FixedDictStrategy(SearchStrategy[dict[Any, Any]]):\n    \"\"\"A strategy which produces dicts with a fixed set of keys, given a\n    strategy for each of their equivalent values.\n\n    e.g. {'foo' : some_int_strategy} would generate dicts with the single\n    key 'foo' mapping to some integer.\n    \"\"\"\n\n    def __init__(\n        self,\n        mapping: dict[Any, SearchStrategy[Any]],\n        *,\n        optional: dict[Any, SearchStrategy[Any]] | None,\n    ):\n        super().__init__()\n        dict_type = type(mapping)\n        self.mapping = mapping\n        keys = tuple(mapping.keys())\n        self.fixed = st.tuples(*[mapping[k] for k in keys]).map(\n            lambda value: dict_type(zip(keys, value, strict=True))\n        )\n        self.optional = optional\n\n    def do_draw(self, data: ConjectureData) -> dict[Any, Any]:\n        context = current_build_context()\n        arg_labels: ArgLabelsT = {}\n        value = type(self.mapping)()\n\n        for key, strategy in self.mapping.items():\n            with context.track_arg_label(str(key)) as arg_label:\n                value[key] = data.draw(strategy)\n            arg_labels |= arg_label\n\n        if self.optional is not None:\n            remaining = [k for k, v in self.optional.items() if not v.is_empty]\n            should_draw = cu.many(\n                data,\n                min_size=0,\n                max_size=len(remaining),\n                average_size=len(remaining) / 2,\n            )\n            while should_draw.more():\n                j = data.draw_integer(0, len(remaining) - 1)\n                remaining[-1], remaining[j] = remaining[j], remaining[-1]\n                key = remaining.pop()\n                with context.track_arg_label(str(key)) as arg_label:\n                    value[key] = data.draw(self.optional[key])\n                arg_labels |= arg_label\n\n        if arg_labels:\n            context.known_object_printers[IDKey(value)].append(\n                _fixeddict_pprinter(arg_labels, self.mapping)\n            )\n        return value\n\n    def calc_is_empty(self, recur: RecurT) -> bool:\n        return recur(self.fixed)\n\n    def __repr__(self) -> str:\n        if self.optional is not None:\n            return f\"fixed_dictionaries({self.mapping!r}, optional={self.optional!r})\"\n        return f\"fixed_dictionaries({self.mapping!r})\"\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/core.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport codecs\nimport enum\nimport math\nimport operator\nimport random\nimport re\nimport string\nimport sys\nimport typing\nimport warnings\nfrom collections.abc import Callable, Collection, Hashable, Iterable, Sequence\nfrom contextvars import ContextVar\nfrom decimal import Context, Decimal, localcontext\nfrom fractions import Fraction\nfrom functools import reduce\nfrom inspect import Parameter, Signature, isabstract, isclass\nfrom re import Pattern\nfrom types import EllipsisType, FunctionType, GenericAlias\nfrom typing import (\n    Annotated,\n    Any,\n    AnyStr,\n    Concatenate,\n    Literal,\n    NewType,\n    NoReturn,\n    ParamSpec,\n    Protocol,\n    TypeAlias,\n    TypeVar,\n    cast,\n    get_args,\n    get_origin,\n    overload,\n)\nfrom uuid import UUID\n\nfrom hypothesis.control import (\n    cleanup,\n    current_build_context,\n    deprecate_random_in_strategy,\n    note,\n    should_note,\n)\nfrom hypothesis.errors import (\n    HypothesisSideeffectWarning,\n    HypothesisWarning,\n    InvalidArgument,\n    ResolutionFailed,\n    RewindRecursive,\n    SmallSearchSpaceWarning,\n)\nfrom hypothesis.internal.cathetus import cathetus\nfrom hypothesis.internal.charmap import (\n    Categories,\n    CategoryName,\n    as_general_categories,\n    categories as all_categories,\n)\nfrom hypothesis.internal.compat import (\n    bit_count,\n    ceil,\n    floor,\n    get_type_hints,\n    is_typed_named_tuple,\n)\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.conjecture.utils import (\n    calc_label_from_callable,\n    calc_label_from_name,\n    check_sample,\n    combine_labels,\n    identity,\n)\nfrom hypothesis.internal.entropy import get_seeder_and_restorer\nfrom hypothesis.internal.floats import float_of\nfrom hypothesis.internal.reflection import (\n    define_function_signature,\n    get_pretty_function_description,\n    get_signature,\n    is_first_param_referenced_in_function,\n    nicerepr,\n    repr_call,\n    required_args,\n)\nfrom hypothesis.internal.validation import (\n    check_type,\n    check_valid_integer,\n    check_valid_interval,\n    check_valid_magnitude,\n    check_valid_size,\n    check_valid_sizes,\n    try_convert,\n)\nfrom hypothesis.strategies._internal import SearchStrategy, check_strategy\nfrom hypothesis.strategies._internal.collections import (\n    FixedDictStrategy,\n    ListStrategy,\n    TupleStrategy,\n    UniqueListStrategy,\n    UniqueSampledListStrategy,\n    tuples,\n)\nfrom hypothesis.strategies._internal.deferred import DeferredStrategy\nfrom hypothesis.strategies._internal.functions import FunctionStrategy\nfrom hypothesis.strategies._internal.lazy import LazyStrategy, unwrap_strategies\nfrom hypothesis.strategies._internal.misc import BooleansStrategy, just, none, nothing\nfrom hypothesis.strategies._internal.numbers import (\n    IntegersStrategy,\n    Real,\n    floats,\n    integers,\n)\nfrom hypothesis.strategies._internal.recursive import RecursiveStrategy\nfrom hypothesis.strategies._internal.shared import SharedStrategy\nfrom hypothesis.strategies._internal.strategies import (\n    Ex,\n    SampledFromStrategy,\n    T,\n    one_of,\n)\nfrom hypothesis.strategies._internal.strings import (\n    BytesStrategy,\n    OneCharStringStrategy,\n    TextStrategy,\n    _check_is_single_character,\n)\nfrom hypothesis.strategies._internal.utils import cacheable, defines_strategy\nfrom hypothesis.utils.conventions import not_set\nfrom hypothesis.utils.deprecation import note_deprecation\nfrom hypothesis.vendor.pretty import ArgLabelsT, RepresentationPrinter\n\n\n@cacheable\n@defines_strategy(force_reusable_values=True)\ndef booleans() -> SearchStrategy[bool]:\n    \"\"\"Returns a strategy which generates instances of :class:`python:bool`.\n\n    Examples from this strategy will shrink towards ``False`` (i.e.\n    shrinking will replace ``True`` with ``False`` where possible).\n    \"\"\"\n    return BooleansStrategy()\n\n\n@overload\ndef sampled_from(elements: Sequence[T]) -> SearchStrategy[T]:  # pragma: no cover\n    ...\n\n\n@overload\ndef sampled_from(elements: type[enum.Enum]) -> SearchStrategy[Any]:  # pragma: no cover\n    # `SearchStrategy[Enum]` is unreliable due to metaclass issues.\n    ...\n\n\n@overload\ndef sampled_from(\n    elements: type[enum.Enum] | Sequence[Any],\n) -> SearchStrategy[Any]:  # pragma: no cover\n    ...\n\n\n@defines_strategy(eager=\"try\")\ndef sampled_from(\n    elements: type[enum.Enum] | Sequence[Any],\n) -> SearchStrategy[Any]:\n    \"\"\"Returns a strategy which generates any value present in ``elements``.\n\n    Note that as with :func:`~hypothesis.strategies.just`, values will not be\n    copied and thus you should be careful of using mutable data.\n\n    ``sampled_from`` supports ordered collections, as well as\n    :class:`~python:enum.Enum` objects.  :class:`~python:enum.Flag` objects\n    may also generate any combination of their members.\n\n    Examples from this strategy shrink by replacing them with values earlier in\n    the list. So e.g. ``sampled_from([10, 1])`` will shrink by trying to replace\n    1 values with 10, and ``sampled_from([1, 10])`` will shrink by trying to\n    replace 10 values with 1.\n\n    It is an error to sample from an empty sequence, because returning :func:`nothing`\n    makes it too easy to silently drop parts of compound strategies.  If you need\n    that behaviour, use ``sampled_from(seq) if seq else nothing()``.\n    \"\"\"\n    values = check_sample(elements, \"sampled_from\")\n    force_repr = None\n    # check_sample converts to tuple unconditionally, but we want to preserve\n    # square braces for list reprs.\n    # This will not cover custom sequence implementations which return different\n    # braces (or other, more unusual things) for their reprs, but this is a tradeoff\n    # between repr accuracy and greedily-evaluating all sequence reprs (at great\n    # cost for large sequences).\n    force_repr_braces = (\"[\", \"]\") if isinstance(elements, list) else None\n    if isinstance(elements, type) and issubclass(elements, enum.Enum):\n        force_repr = f\"sampled_from({elements.__module__}.{elements.__name__})\"\n\n    if isclass(elements) and issubclass(elements, enum.Flag):\n        # Combinations of enum.Flag members (including empty) are also members.  We generate these\n        # dynamically, because static allocation takes O(2^n) memory.  LazyStrategy is used for the\n        # ease of force_repr.\n        # Add all named values, both flag bits (== list(elements)) and aliases. The aliases are\n        # necessary for full coverage for flags that would fail enum.NAMED_FLAGS check, and they\n        # are also nice values to shrink to.\n        flags = sorted(\n            set(elements.__members__.values()),\n            key=lambda v: (bit_count(v.value), v.value),\n        )\n        # Finally, try to construct the empty state if it is not named. It's placed at the\n        # end so that we shrink to named values.\n        flags_with_empty = flags\n        if not flags or flags[0].value != 0:\n            try:\n                flags_with_empty = [*flags, elements(0)]\n            except TypeError:  # pragma: no cover\n                # Happens on some python versions (at least 3.12) when there are no named values\n                pass\n        inner = [\n            # Consider one or no named flags set, with shrink-to-named-flag behaviour.\n            # Special cases (length zero or one) are handled by the inner sampled_from.\n            sampled_from(flags_with_empty),\n        ]\n        if len(flags) > 1:\n            inner += [\n                # Uniform distribution over number of named flags or combinations set. The overlap\n                # at r=1 is intentional, it may lead to oversampling but gives consistent shrinking\n                # behaviour.\n                integers(min_value=1, max_value=len(flags))\n                .flatmap(lambda r: sets(sampled_from(flags), min_size=r, max_size=r))\n                .map(lambda s: elements(reduce(operator.or_, s))),\n            ]\n        return LazyStrategy(one_of, args=inner, kwargs={}, force_repr=force_repr)\n    if not values:\n\n        def has_annotations(elements):\n            if sys.version_info[:2] < (3, 14):\n                return vars(elements).get(\"__annotations__\")\n            else:  # pragma: no cover  # covered by 3.14 tests\n                import annotationlib\n\n                return bool(annotationlib.get_annotations(elements))\n\n        if (\n            isinstance(elements, type)\n            and issubclass(elements, enum.Enum)\n            and has_annotations(elements)\n        ):\n            # See https://github.com/HypothesisWorks/hypothesis/issues/2923\n            raise InvalidArgument(\n                f\"Cannot sample from {elements.__module__}.{elements.__name__} \"\n                \"because it contains no elements.  It does however have annotations, \"\n                \"so maybe you tried to write an enum as if it was a dataclass?\"\n            )\n        raise InvalidArgument(\"Cannot sample from a length-zero sequence.\")\n    if len(values) == 1:\n        return just(values[0])\n    return SampledFromStrategy(\n        values, force_repr=force_repr, force_repr_braces=force_repr_braces\n    )\n\n\ndef _gets_first_item(fn: Callable) -> bool:\n    # Introspection for either `itemgetter(0)`, or `lambda x: x[0]`\n    if isinstance(fn, FunctionType):\n        s = get_pretty_function_description(fn)\n        return bool(re.fullmatch(s, r\"lambda ([a-z]+): \\1\\[0\\]\"))\n    return isinstance(fn, operator.itemgetter) and repr(fn) == \"operator.itemgetter(0)\"\n\n\n@cacheable\n@defines_strategy()\ndef lists(\n    elements: SearchStrategy[Ex],\n    *,\n    min_size: int = 0,\n    max_size: int | None = None,\n    unique_by: (\n        None | Callable[[Ex], Hashable] | tuple[Callable[[Ex], Hashable], ...]\n    ) = None,\n    unique: bool = False,\n) -> SearchStrategy[list[Ex]]:\n    \"\"\"Returns a list containing values drawn from elements with length in the\n    interval [min_size, max_size] (no bounds in that direction if these are\n    None). If max_size is 0, only the empty list will be drawn.\n\n    If ``unique`` is True (or something that evaluates to True), we compare direct\n    object equality, as if unique_by was ``lambda x: x``. This comparison only\n    works for hashable types.\n\n    If ``unique_by`` is not None it must be a callable or tuple of callables\n    returning a hashable type when given a value drawn from elements. The\n    resulting list will satisfy the condition that for ``i`` != ``j``,\n    ``unique_by(result[i])`` != ``unique_by(result[j])``.\n\n    If ``unique_by`` is a tuple of callables the uniqueness will be respective\n    to each callable.\n\n    For example, the following will produce two columns of integers with both\n    columns being unique respectively.\n\n    .. code-block:: pycon\n\n        >>> twoints = st.tuples(st.integers(), st.integers())\n        >>> st.lists(twoints, unique_by=(lambda x: x[0], lambda x: x[1]))\n\n    Examples from this strategy shrink by trying to remove elements from the\n    list, and by shrinking each individual element of the list.\n    \"\"\"\n    check_valid_sizes(min_size, max_size)\n    check_strategy(elements, \"elements\")\n    if unique:\n        if unique_by is not None:\n            raise InvalidArgument(\n                \"cannot specify both unique and unique_by \"\n                \"(you probably only want to set unique_by)\"\n            )\n        else:\n            unique_by = identity\n\n    if max_size == 0:\n        return builds(list)\n    if unique_by is not None:\n        if not (callable(unique_by) or isinstance(unique_by, tuple)):\n            raise InvalidArgument(\n                f\"{unique_by=} is not a callable or tuple of callables\"\n            )\n        if callable(unique_by):\n            unique_by = (unique_by,)\n        if len(unique_by) == 0:\n            raise InvalidArgument(\"unique_by is empty\")\n        for i, f in enumerate(unique_by):\n            if not callable(f):\n                raise InvalidArgument(f\"unique_by[{i}]={f!r} is not a callable\")\n        # Note that lazy strategies automatically unwrap when passed to a defines_strategy\n        # function.\n        tuple_suffixes = None\n        if (\n            # We're generating a list of tuples unique by the first element, perhaps\n            # via st.dictionaries(), and this will be more efficient if we rearrange\n            # our strategy somewhat to draw the first element then draw add the rest.\n            isinstance(elements, TupleStrategy)\n            and len(elements.element_strategies) >= 1\n            and all(_gets_first_item(fn) for fn in unique_by)\n        ):\n            unique_by = (identity,)\n            tuple_suffixes = TupleStrategy(elements.element_strategies[1:])\n            elements = elements.element_strategies[0]\n\n        # UniqueSampledListStrategy offers a substantial performance improvement for\n        # unique arrays with few possible elements, e.g. of eight-bit integer types.\n        if (\n            isinstance(elements, IntegersStrategy)\n            and elements.start is not None\n            and elements.end is not None\n            and (elements.end - elements.start) <= 255\n        ):\n            elements = SampledFromStrategy(\n                sorted(range(elements.start, elements.end + 1), key=abs)  # type: ignore\n                if elements.end < 0 or elements.start > 0\n                else (\n                    list(range(elements.end + 1))\n                    + list(range(-1, elements.start - 1, -1))\n                )\n            )\n\n        if isinstance(elements, SampledFromStrategy):\n            element_count = len(elements.elements)\n            if min_size > element_count:\n                raise InvalidArgument(\n                    f\"Cannot create a collection of {min_size=} unique \"\n                    f\"elements with values drawn from only {element_count} distinct \"\n                    \"elements\"\n                )\n\n            if max_size is not None:\n                max_size = min(max_size, element_count)\n            else:\n                max_size = element_count\n\n            return UniqueSampledListStrategy(\n                elements=elements,\n                max_size=max_size,\n                min_size=min_size,\n                keys=unique_by,\n                tuple_suffixes=tuple_suffixes,\n            )\n\n        return UniqueListStrategy(\n            elements=elements,\n            max_size=max_size,\n            min_size=min_size,\n            keys=unique_by,\n            tuple_suffixes=tuple_suffixes,\n        )\n    return ListStrategy(elements, min_size=min_size, max_size=max_size)\n\n\n@cacheable\n@defines_strategy()\ndef sets(\n    elements: SearchStrategy[Ex],\n    *,\n    min_size: int = 0,\n    max_size: int | None = None,\n) -> SearchStrategy[set[Ex]]:\n    \"\"\"This has the same behaviour as lists, but returns sets instead.\n\n    Note that Hypothesis cannot tell if values are drawn from elements\n    are hashable until running the test, so you can define a strategy\n    for sets of an unhashable type but it will fail at test time.\n\n    Examples from this strategy shrink by trying to remove elements from the\n    set, and by shrinking each individual element of the set.\n    \"\"\"\n    return lists(\n        elements=elements, min_size=min_size, max_size=max_size, unique=True\n    ).map(set)\n\n\n@cacheable\n@defines_strategy()\ndef frozensets(\n    elements: SearchStrategy[Ex],\n    *,\n    min_size: int = 0,\n    max_size: int | None = None,\n) -> SearchStrategy[frozenset[Ex]]:\n    \"\"\"This is identical to the sets function but instead returns\n    frozensets.\"\"\"\n    return lists(\n        elements=elements, min_size=min_size, max_size=max_size, unique=True\n    ).map(frozenset)\n\n\nclass PrettyIter:\n    def __init__(self, values):\n        self._values = values\n        self._iter = iter(self._values)\n\n    def __iter__(self):\n        return self._iter\n\n    def __next__(self):\n        return next(self._iter)\n\n    def __repr__(self) -> str:\n        return f\"iter({self._values!r})\"\n\n\n@defines_strategy()\ndef iterables(\n    elements: SearchStrategy[Ex],\n    *,\n    min_size: int = 0,\n    max_size: int | None = None,\n    unique_by: (\n        None | Callable[[Ex], Hashable] | tuple[Callable[[Ex], Hashable], ...]\n    ) = None,\n    unique: bool = False,\n) -> SearchStrategy[Iterable[Ex]]:\n    \"\"\"This has the same behaviour as lists, but returns iterables instead.\n\n    Some iterables cannot be indexed (e.g. sets) and some do not have a\n    fixed length (e.g. generators). This strategy produces iterators,\n    which cannot be indexed and do not have a fixed length. This ensures\n    that you do not accidentally depend on sequence behaviour.\n    \"\"\"\n    return lists(\n        elements=elements,\n        min_size=min_size,\n        max_size=max_size,\n        unique_by=unique_by,\n        unique=unique,\n    ).map(PrettyIter)\n\n\n# this type definition is imprecise, in multiple ways:\n# * mapping and optional can be of different types:\n#      s: dict[str | int, int] = st.fixed_dictionaries(\n#         {\"a\": st.integers()}, optional={1: st.integers()}\n#     )\n# * the values in either mapping or optional need not all be of the same type:\n#      s: dict[str, int | bool] = st.fixed_dictionaries(\n#         {\"a\": st.integers(), \"b\": st.booleans()}\n#     )\n# * the arguments may be of any dict-compatible type, in which case the return\n#  value will be of that type instead of dit\n#\n# Overloads may help here, but I doubt we'll be able to satisfy all these\n# constraints.\n#\n# Here's some platonic ideal test cases for revealed_types.py, with the understanding\n# that some may not be achievable:\n#\n#   (\"fixed_dictionaries({'a': booleans()})\", \"dict[str, bool]\"),\n#   (\"fixed_dictionaries({'a': booleans(), 'b': integers()})\", \"dict[str, bool | int]\"),\n#   (\"fixed_dictionaries({}, optional={'a': booleans()})\", \"dict[str, bool]\"),\n#   (\n#       \"fixed_dictionaries({'a': booleans()}, optional={1: booleans()})\",\n#       \"dict[str | int, bool]\",\n#   ),\n#   (\n#       \"fixed_dictionaries({'a': booleans()}, optional={1: integers()})\",\n#       \"dict[str | int, bool | int]\",\n#   ),\n\n\n@defines_strategy()\ndef fixed_dictionaries(\n    mapping: dict[T, SearchStrategy[Ex]],\n    *,\n    optional: dict[T, SearchStrategy[Ex]] | None = None,\n) -> SearchStrategy[dict[T, Ex]]:\n    \"\"\"Generates a dictionary of the same type as mapping with a fixed set of\n    keys mapping to strategies. ``mapping`` must be a dict subclass.\n\n    Generated values have all keys present in mapping, in iteration order,\n    with the corresponding values drawn from mapping[key].\n\n    If ``optional`` is passed, the generated value *may or may not* contain each\n    key from ``optional`` and a value drawn from the corresponding strategy.\n    Generated values may contain optional keys in an arbitrary order.\n\n    Examples from this strategy shrink by shrinking each individual value in\n    the generated dictionary, and omitting optional key-value pairs.\n    \"\"\"\n    check_type(dict, mapping, \"mapping\")\n    for k, v in mapping.items():\n        check_strategy(v, f\"mapping[{k!r}]\")\n\n    if optional is not None:\n        check_type(dict, optional, \"optional\")\n        for k, v in optional.items():\n            check_strategy(v, f\"optional[{k!r}]\")\n        if type(mapping) != type(optional):\n            raise InvalidArgument(\n                f\"Got arguments of different types: \"\n                f\"mapping={nicerepr(type(mapping))}, \"\n                f\"optional={nicerepr(type(optional))}\"\n            )\n        if set(mapping) & set(optional):\n            raise InvalidArgument(\n                \"The following keys were in both mapping and optional, \"\n                f\"which is invalid: {set(mapping) & set(optional)!r}\"\n            )\n\n    return FixedDictStrategy(mapping, optional=optional)\n\n\n_get_first_item = operator.itemgetter(0)\n\n\n@cacheable\n@defines_strategy()\ndef dictionaries(\n    keys: SearchStrategy[Ex],\n    values: SearchStrategy[T],\n    *,\n    dict_class: type = dict,\n    min_size: int = 0,\n    max_size: int | None = None,\n) -> SearchStrategy[dict[Ex, T]]:\n    # Describing the exact dict_class to Mypy drops the key and value types,\n    # so we report Dict[K, V] instead of Mapping[Any, Any] for now.  Sorry!\n    \"\"\"Generates dictionaries of type ``dict_class`` with keys drawn from the ``keys``\n    argument and values drawn from the ``values`` argument.\n\n    The size parameters have the same interpretation as for\n    :func:`~hypothesis.strategies.lists`.\n\n    Examples from this strategy shrink by trying to remove keys from the\n    generated dictionary, and by shrinking each generated key and value.\n    \"\"\"\n    check_valid_sizes(min_size, max_size)\n    if max_size == 0:\n        return fixed_dictionaries(dict_class())\n    check_strategy(keys, \"keys\")\n    check_strategy(values, \"values\")\n\n    return lists(\n        tuples(keys, values),\n        min_size=min_size,\n        max_size=max_size,\n        unique_by=_get_first_item,\n    ).map(dict_class)\n\n\n@cacheable\n@defines_strategy(force_reusable_values=True)\ndef characters(\n    *,\n    codec: str | None = None,\n    min_codepoint: int | None = None,\n    max_codepoint: int | None = None,\n    categories: Collection[CategoryName] | None = None,\n    exclude_categories: Collection[CategoryName] | None = None,\n    exclude_characters: Collection[str] | None = None,\n    include_characters: Collection[str] | None = None,\n    # Note: these arguments are deprecated aliases for backwards compatibility\n    blacklist_categories: Collection[CategoryName] | None = None,\n    whitelist_categories: Collection[CategoryName] | None = None,\n    blacklist_characters: Collection[str] | None = None,\n    whitelist_characters: Collection[str] | None = None,\n) -> SearchStrategy[str]:\n    r\"\"\"Generates characters, length-one :class:`python:str`\\ ings,\n    following specified filtering rules.\n\n    - When no filtering rules are specified, any character can be produced.\n    - If ``min_codepoint`` or ``max_codepoint`` is specified, then only\n      characters having a codepoint in that range will be produced.\n    - If ``categories`` is specified, then only characters from those\n      Unicode categories will be produced. This is a further restriction,\n      characters must also satisfy ``min_codepoint`` and ``max_codepoint``.\n    - If ``exclude_categories`` is specified, then any character from those\n      categories will not be produced.  You must not pass both ``categories``\n      and ``exclude_categories``; these arguments are alternative ways to\n      specify exactly the same thing.\n    - If ``include_characters`` is specified, then any additional characters\n      in that list will also be produced.\n    - If ``exclude_characters`` is specified, then any characters in\n      that list will be not be produced. Any overlap between\n      ``include_characters`` and ``exclude_characters`` will raise an\n      exception.\n    - If ``codec`` is specified, only characters in the specified `codec encodings`_\n      will be produced.\n\n    The ``_codepoint`` arguments must be integers between zero and\n    :obj:`python:sys.maxunicode`.  The ``_characters`` arguments must be\n    collections of length-one unicode strings, such as a unicode string.\n\n    The ``_categories`` arguments must be used to specify either the\n    one-letter Unicode major category or the two-letter Unicode\n    `general category`_.  For example, ``('Nd', 'Lu')`` signifies \"Number,\n    decimal digit\" and \"Letter, uppercase\".  A single letter ('major category')\n    can be given to match all corresponding categories, for example ``'P'``\n    for characters in any punctuation category.\n\n    We allow codecs from the :mod:`codecs` module and their aliases, platform\n    specific and user-registered codecs if they are available, and\n    `python-specific text encodings`_ (but not text or binary transforms).\n    ``include_characters`` which cannot be encoded using this codec will\n    raise an exception.  If non-encodable codepoints or categories are\n    explicitly allowed, the ``codec`` argument will exclude them without\n    raising an exception.\n\n    .. _general category: https://en.wikipedia.org/wiki/Unicode_character_property\n    .. _codec encodings: https://docs.python.org/3/library/codecs.html#encodings-and-unicode\n    .. _python-specific text encodings: https://docs.python.org/3/library/codecs.html#python-specific-encodings\n\n    Examples from this strategy shrink towards the codepoint for ``'0'``,\n    or the first allowable codepoint after it if ``'0'`` is excluded.\n    \"\"\"\n    check_valid_size(min_codepoint, \"min_codepoint\")\n    check_valid_size(max_codepoint, \"max_codepoint\")\n    check_valid_interval(min_codepoint, max_codepoint, \"min_codepoint\", \"max_codepoint\")\n    categories = cast(Categories | None, categories)\n    if categories is not None and exclude_categories is not None:\n        raise InvalidArgument(\n            f\"Pass at most one of {categories=} and {exclude_categories=} - \"\n            \"these arguments both specify which categories are allowed, so it \"\n            \"doesn't make sense to use both in a single call.\"\n        )\n\n    # Handle deprecation of whitelist/blacklist arguments\n    has_old_arg = any(v is not None for k, v in locals().items() if \"list\" in k)\n    has_new_arg = any(v is not None for k, v in locals().items() if \"lude\" in k)\n    if has_old_arg and has_new_arg:\n        raise InvalidArgument(\n            \"The deprecated blacklist/whitelist arguments cannot be used in \"\n            \"the same call as their replacement include/exclude arguments.\"\n        )\n    if blacklist_categories is not None:\n        exclude_categories = blacklist_categories\n    if whitelist_categories is not None:\n        categories = whitelist_categories\n    if blacklist_characters is not None:\n        exclude_characters = blacklist_characters\n    if whitelist_characters is not None:\n        include_characters = whitelist_characters\n\n    if (\n        min_codepoint is None\n        and max_codepoint is None\n        and categories is None\n        and exclude_categories is None\n        and include_characters is not None\n        and codec is None\n    ):\n        raise InvalidArgument(\n            \"Nothing is excluded by other arguments, so passing only \"\n            f\"{include_characters=} would have no effect.  \"\n            \"Also pass categories=(), or use \"\n            f\"sampled_from({include_characters!r}) instead.\"\n        )\n    exclude_characters = exclude_characters or \"\"\n    include_characters = include_characters or \"\"\n    if not_one_char := [c for c in exclude_characters if len(c) != 1]:\n        raise InvalidArgument(\n            \"Elements of exclude_characters are required to be a single character, \"\n            f\"but {not_one_char!r} passed in {exclude_characters=} was not.\"\n        )\n    if not_one_char := [c for c in include_characters if len(c) != 1]:\n        raise InvalidArgument(\n            \"Elements of include_characters are required to be a single character, \"\n            f\"but {not_one_char!r} passed in {include_characters=} was not.\"\n        )\n    overlap = set(exclude_characters).intersection(include_characters)\n    if overlap:\n        raise InvalidArgument(\n            f\"Characters {sorted(overlap)!r} are present in both \"\n            f\"{include_characters=} and {exclude_characters=}\"\n        )\n    if categories is not None:\n        categories = as_general_categories(categories, \"categories\")\n    if exclude_categories is not None:\n        exclude_categories = as_general_categories(\n            exclude_categories, \"exclude_categories\"\n        )\n    if categories is not None and not categories and not include_characters:\n        raise InvalidArgument(\n            \"When `categories` is an empty collection and there are \"\n            \"no characters specified in include_characters, nothing can \"\n            \"be generated by the characters() strategy.\"\n        )\n    both_cats = set(exclude_categories or ()).intersection(categories or ())\n    if both_cats:\n        # Note: we check that exactly one of `categories` or `exclude_categories` is\n        # passed above, but retain this older check for the deprecated arguments.\n        raise InvalidArgument(\n            f\"Categories {sorted(both_cats)!r} are present in both \"\n            f\"{categories=} and {exclude_categories=}\"\n        )\n    elif exclude_categories is not None:\n        categories = set(all_categories()) - set(exclude_categories)\n    del exclude_categories\n\n    if codec is not None:\n        try:\n            codec = codecs.lookup(codec).name\n            # Check this is not a str-to-str or bytes-to-bytes codec; see\n            # https://docs.python.org/3/library/codecs.html#binary-transforms\n            \"\".encode(codec)\n        except LookupError:\n            raise InvalidArgument(f\"{codec=} is not valid on this system\") from None\n        except Exception:\n            raise InvalidArgument(f\"{codec=} is not a valid codec\") from None\n\n        for char in include_characters:\n            try:\n                char.encode(encoding=codec, errors=\"strict\")\n            except UnicodeEncodeError:\n                raise InvalidArgument(\n                    f\"Character {char!r} in {include_characters=} \"\n                    f\"cannot be encoded with {codec=}\"\n                ) from None\n\n        # ascii and utf-8 are sufficient common that we have faster special handling\n        if codec == \"ascii\":\n            if (max_codepoint is None) or (max_codepoint > 127):\n                max_codepoint = 127\n            codec = None\n        elif codec == \"utf-8\":\n            if categories is None:\n                categories = all_categories()\n            categories = tuple(c for c in categories if c != \"Cs\")\n\n    return OneCharStringStrategy.from_characters_args(\n        categories=categories,\n        exclude_characters=exclude_characters,\n        min_codepoint=min_codepoint,\n        max_codepoint=max_codepoint,\n        include_characters=include_characters,\n        codec=codec,\n    )\n\n\n# Hide the deprecated aliases from documentation and casual inspection\ncharacters.__signature__ = (__sig := get_signature(characters)).replace(  # type: ignore\n    parameters=[p for p in __sig.parameters.values() if \"list\" not in p.name]\n)\n\n\n@cacheable\n@defines_strategy(force_reusable_values=True)\ndef text(\n    alphabet: Collection[str] | SearchStrategy[str] = characters(codec=\"utf-8\"),\n    *,\n    min_size: int = 0,\n    max_size: int | None = None,\n) -> SearchStrategy[str]:\n    \"\"\"Generates strings with characters drawn from ``alphabet``, which should\n    be a collection of length one strings or a strategy generating such strings.\n\n    The default alphabet strategy can generate the full unicode range but\n    excludes surrogate characters because they are invalid in the UTF-8\n    encoding.  You can use :func:`~hypothesis.strategies.characters` without\n    arguments to find surrogate-related bugs such as :bpo:`34454`.\n\n    ``min_size`` and ``max_size`` have the usual interpretations.\n    Note that Python measures string length by counting codepoints: U+00C5\n    ``Å`` is a single character, while U+0041 U+030A ``Å`` is two - the ``A``,\n    and a combining ring above.\n\n    Examples from this strategy shrink towards shorter strings, and with the\n    characters in the text shrinking as per the alphabet strategy.\n    This strategy does not :func:`~python:unicodedata.normalize` examples,\n    so generated strings may be in any or none of the 'normal forms'.\n    \"\"\"\n    check_valid_sizes(min_size, max_size)\n    if isinstance(alphabet, SearchStrategy):\n        char_strategy = unwrap_strategies(alphabet)\n        if isinstance(char_strategy, SampledFromStrategy):\n            # Check this via the up-front validation logic below, and incidentally\n            # convert into a `characters()` strategy for standard text shrinking.\n            return text(char_strategy.elements, min_size=min_size, max_size=max_size)\n        elif not isinstance(char_strategy, OneCharStringStrategy):\n            char_strategy = char_strategy.map(_check_is_single_character)\n    else:\n        non_string = [c for c in alphabet if not isinstance(c, str)]\n        if non_string:\n            raise InvalidArgument(\n                \"The following elements in alphabet are not unicode \"\n                f\"strings:  {non_string!r}\"\n            )\n        not_one_char = [c for c in alphabet if len(c) != 1]\n        if not_one_char:\n            raise InvalidArgument(\n                \"The following elements in alphabet are not of length one, \"\n                f\"which leads to violation of size constraints:  {not_one_char!r}\"\n            )\n        if alphabet in [\"ascii\", \"utf-8\"]:\n            warnings.warn(\n                f\"st.text({alphabet!r}): it seems like you are trying to use the \"\n                f\"codec {alphabet!r}. st.text({alphabet!r}) instead generates \"\n                f\"strings using the literal characters {list(alphabet)!r}. To specify \"\n                f\"the {alphabet} codec, use st.text(st.characters(codec={alphabet!r})). \"\n                \"If you intended to use character literals, you can silence this \"\n                \"warning by reordering the characters.\",\n                HypothesisWarning,\n                # this stacklevel is of course incorrect, but breaking out of the\n                # levels of LazyStrategy and validation isn't worthwhile.\n                stacklevel=1,\n            )\n        char_strategy = (\n            characters(categories=(), include_characters=alphabet)\n            if alphabet\n            else nothing()\n        )\n    if (max_size == 0 or char_strategy.is_empty) and not min_size:\n        return just(\"\")\n    # mypy is unhappy with ListStrategy(SearchStrategy[list[Ex]]) and then TextStrategy\n    # setting Ex = str. Mypy is correct to complain because we have an LSP violation\n    # here in the TextStrategy.do_draw override. Would need refactoring to resolve.\n    return TextStrategy(char_strategy, min_size=min_size, max_size=max_size)  # type: ignore\n\n\n@overload\ndef from_regex(\n    regex: bytes | Pattern[bytes],\n    *,\n    fullmatch: bool = False,\n) -> SearchStrategy[bytes]:  # pragma: no cover\n    ...\n\n\n@overload\ndef from_regex(\n    regex: str | Pattern[str],\n    *,\n    fullmatch: bool = False,\n    alphabet: str | SearchStrategy[str] = characters(codec=\"utf-8\"),\n) -> SearchStrategy[str]:  # pragma: no cover\n    ...\n\n\n@cacheable\n@defines_strategy()\ndef from_regex(\n    regex: AnyStr | Pattern[AnyStr],\n    *,\n    fullmatch: bool = False,\n    alphabet: str | SearchStrategy[str] | None = None,\n) -> SearchStrategy[AnyStr]:\n    r\"\"\"Generates strings that contain a match for the given regex (i.e. ones\n    for which :func:`python:re.search` will return a non-None result).\n\n    ``regex`` may be a pattern or :func:`compiled regex <python:re.compile>`.\n    Both byte-strings and unicode strings are supported, and will generate\n    examples of the same type.\n\n    You can use regex flags such as :obj:`python:re.IGNORECASE` or\n    :obj:`python:re.DOTALL` to control generation. Flags can be passed either\n    in compiled regex or inside the pattern with a ``(?iLmsux)`` group.\n\n    Some regular expressions are only partly supported - the underlying\n    strategy checks local matching and relies on filtering to resolve\n    context-dependent expressions.  Using too many of these constructs may\n    cause health-check errors as too many examples are filtered out. This\n    mainly includes (positive or negative) lookahead and lookbehind groups.\n\n    If you want the generated string to match the whole regex you should use\n    boundary markers. So e.g. ``r\"\\A.\\Z\"`` will return a single character\n    string, while ``\".\"`` will return any string, and ``r\"\\A.$\"`` will return\n    a single character optionally followed by a ``\"\\n\"``.\n    Alternatively, passing ``fullmatch=True`` will ensure that the whole\n    string is a match, as if you had used the ``\\A`` and ``\\Z`` markers.\n\n    The ``alphabet=`` argument constrains the characters in the generated\n    string, as for :func:`text`, and is only supported for unicode strings.\n\n    Examples from this strategy shrink towards shorter strings and lower\n    character values, with exact behaviour that may depend on the pattern.\n    \"\"\"\n    check_type((str, bytes, re.Pattern), regex, \"regex\")\n    check_type(bool, fullmatch, \"fullmatch\")\n    pattern = regex.pattern if isinstance(regex, re.Pattern) else regex\n    if alphabet is not None:\n        check_type((str, SearchStrategy), alphabet, \"alphabet\")\n        if not isinstance(pattern, str):\n            raise InvalidArgument(\"alphabet= is not supported for bytestrings\")\n        alphabet = OneCharStringStrategy.from_alphabet(alphabet)\n    elif isinstance(pattern, str):\n        alphabet = characters(codec=\"utf-8\")\n\n    # TODO: We would like to move this to the top level, but pending some major\n    # refactoring it's hard to do without creating circular imports.\n    from hypothesis.strategies._internal.regex import regex_strategy\n\n    return regex_strategy(regex, fullmatch, alphabet=alphabet)\n\n\n@cacheable\n@defines_strategy(force_reusable_values=True)\ndef binary(\n    *,\n    min_size: int = 0,\n    max_size: int | None = None,\n) -> SearchStrategy[bytes]:\n    \"\"\"Generates :class:`python:bytes`.\n\n    The generated :class:`python:bytes` will have a length of at least ``min_size``\n    and at most ``max_size``.  If ``max_size`` is None there is no upper limit.\n\n    Examples from this strategy shrink towards smaller strings and lower byte\n    values.\n    \"\"\"\n    check_valid_sizes(min_size, max_size)\n    return BytesStrategy(min_size, max_size)\n\n\n@cacheable\n@defines_strategy()\ndef randoms(\n    *,\n    note_method_calls: bool = False,\n    use_true_random: bool = False,\n) -> SearchStrategy[random.Random]:\n    \"\"\"Generates instances of ``random.Random``. The generated Random instances\n    are of a special HypothesisRandom subclass.\n\n    - If ``note_method_calls`` is set to ``True``, Hypothesis will print the\n      randomly drawn values in any falsifying test case. This can be helpful\n      for debugging the behaviour of randomized algorithms.\n    - If ``use_true_random`` is set to ``True`` then values will be drawn from\n      their usual distribution, otherwise they will actually be Hypothesis\n      generated values (and will be shrunk accordingly for any failing test\n      case). Setting ``use_true_random=False`` will tend to expose bugs that\n      would occur with very low probability when it is set to True, and this\n      flag should only be set to True when your code relies on the distribution\n      of values for correctness.\n\n    For managing global state, see the :func:`~hypothesis.strategies.random_module`\n    strategy and :func:`~hypothesis.register_random` function.\n    \"\"\"\n    check_type(bool, note_method_calls, \"note_method_calls\")\n    check_type(bool, use_true_random, \"use_true_random\")\n\n    from hypothesis.strategies._internal.random import RandomStrategy\n\n    return RandomStrategy(\n        use_true_random=use_true_random, note_method_calls=note_method_calls\n    )\n\n\nclass RandomSeeder:\n    def __init__(self, seed):\n        self.seed = seed\n\n    def __repr__(self):\n        return f\"RandomSeeder({self.seed!r})\"\n\n\nclass RandomModule(SearchStrategy):\n    def do_draw(self, data: ConjectureData) -> RandomSeeder:\n        # It would be unsafe to do run this method more than once per test case,\n        # because cleanup() runs tasks in FIFO order (at time of writing!).\n        # Fortunately, the random_module() strategy wraps us in shared(), so\n        # it's cached for all but the first of any number of calls.\n        seed = data.draw(integers(0, 2**32 - 1))\n        seed_all, restore_all = get_seeder_and_restorer(seed)\n        seed_all()\n        cleanup(restore_all)\n        return RandomSeeder(seed)\n\n\n@cacheable\n@defines_strategy()\ndef random_module() -> SearchStrategy[RandomSeeder]:\n    \"\"\"Hypothesis always seeds global PRNGs before running a test, and restores the\n    previous state afterwards.\n\n    If having a fixed seed would unacceptably weaken your tests, and you\n    cannot use a ``random.Random`` instance provided by\n    :func:`~hypothesis.strategies.randoms`, this strategy calls\n    :func:`python:random.seed` with an arbitrary integer and passes you\n    an opaque object whose repr displays the seed value for debugging.\n    If ``numpy.random`` is available, that state is also managed, as is anything\n    managed by :func:`hypothesis.register_random`.\n\n    Examples from these strategy shrink to seeds closer to zero.\n    \"\"\"\n    return shared(RandomModule(), key=\"hypothesis.strategies.random_module()\")\n\n\nclass BuildsStrategy(SearchStrategy[Ex]):\n    def __init__(\n        self,\n        target: Callable[..., Ex],\n        args: tuple[SearchStrategy[Any], ...],\n        kwargs: dict[str, SearchStrategy[Any]],\n    ):\n        super().__init__()\n        self.target = target\n        self.args = args\n        self.kwargs = kwargs\n\n    def calc_label(self) -> int:\n        return combine_labels(\n            self.class_label,\n            calc_label_from_callable(self.target),\n            *[strat.label for strat in self.args],\n            *[calc_label_from_name(k) for k in self.kwargs],\n            *[strat.label for strat in self.kwargs.values()],\n        )\n\n    def do_draw(self, data: ConjectureData) -> Ex:\n        context = current_build_context()\n        arg_labels: ArgLabelsT = {}\n\n        args = []\n        for i, s in enumerate(self.args):\n            with context.track_arg_label(f\"arg[{i}]\") as arg_label:\n                args.append(data.draw(s))\n            arg_labels |= arg_label\n\n        kwargs = {}\n        for k, v in self.kwargs.items():\n            with context.track_arg_label(k) as arg_label:\n                kwargs[k] = data.draw(v)\n            arg_labels |= arg_label\n\n        try:\n            obj = self.target(*args, **kwargs)\n        except TypeError as err:\n            if (\n                isinstance(self.target, type)\n                and issubclass(self.target, enum.Enum)\n                and not (self.args or self.kwargs)\n            ):\n                name = self.target.__module__ + \".\" + self.target.__qualname__\n                raise InvalidArgument(\n                    f\"Calling {name} with no arguments raised an error - \"\n                    f\"try using sampled_from({name}) instead of builds({name})\"\n                ) from err\n            if not (self.args or self.kwargs):\n                from .types import is_generic_type\n\n                if isinstance(self.target, NewType) or is_generic_type(self.target):\n                    raise InvalidArgument(\n                        f\"Calling {self.target!r} with no arguments raised an \"\n                        f\"error - try using from_type({self.target!r}) instead \"\n                        f\"of builds({self.target!r})\"\n                    ) from err\n            if getattr(self.target, \"__no_type_check__\", None) is True:\n                # Note: could use PEP-678 __notes__ here.  Migrate over once we're\n                # using an `exceptiongroup` backport with support for that.\n                raise TypeError(\n                    \"This might be because the @no_type_check decorator prevented \"\n                    \"Hypothesis from inferring a strategy for some required arguments.\"\n                ) from err\n            raise\n\n        context.record_call(\n            obj, self.target, args=args, kwargs=kwargs, arg_labels=arg_labels\n        )\n        return obj\n\n    def do_validate(self) -> None:\n        tuples(*self.args).validate()\n        fixed_dictionaries(self.kwargs).validate()\n\n    def __repr__(self) -> str:\n        bits = [get_pretty_function_description(self.target)]\n        bits.extend(map(repr, self.args))\n        bits.extend(f\"{k}={v!r}\" for k, v in self.kwargs.items())\n        return f\"builds({', '.join(bits)})\"\n\n\n@cacheable\n@defines_strategy()\ndef builds(\n    target: Callable[..., Ex],\n    /,\n    *args: SearchStrategy[Any],\n    **kwargs: SearchStrategy[Any] | EllipsisType,\n) -> SearchStrategy[Ex]:\n    \"\"\"Generates values by drawing from ``args`` and ``kwargs`` and passing\n    them to the callable (provided as the first positional argument) in the\n    appropriate argument position.\n\n    e.g. ``builds(target, integers(), flag=booleans())`` would draw an\n    integer ``i`` and a boolean ``b`` and call ``target(i, flag=b)``.\n\n    If the callable has type annotations, they will be used to infer a strategy\n    for required arguments that were not passed to builds.  You can also tell\n    builds to infer a strategy for an optional argument by passing ``...``\n    (:obj:`python:Ellipsis`) as a keyword argument to builds, instead of a strategy for\n    that argument to the callable.\n\n    If the callable is a class defined with :pypi:`attrs`, missing required\n    arguments will be inferred from the attribute on a best-effort basis,\n    e.g. by checking :ref:`attrs standard validators <attrs:api-validators>`.\n    Dataclasses are handled natively by the inference from type hints.\n\n    Examples from this strategy shrink by shrinking the argument values to\n    the callable.\n    \"\"\"\n    if not callable(target):\n        from hypothesis.strategies._internal.types import is_a_union\n\n        # before 3.14, unions were callable, so it got an error message in\n        # BuildsStrategy.do_draw. In 3.14+, unions are not callable, so\n        # we error earlier here instead.\n        suggestion = (\n            f\" Try using from_type({target}) instead?\" if is_a_union(target) else \"\"\n        )\n        raise InvalidArgument(\n            \"The first positional argument to builds() must be a callable \"\n            f\"target to construct.{suggestion}\"\n        )\n\n    if ... in args:  # type: ignore  # we only annotated the allowed types\n        # Avoid an implementation nightmare juggling tuples and worse things\n        raise InvalidArgument(\n            \"... was passed as a positional argument to \"\n            \"builds(), but is only allowed as a keyword arg\"\n        )\n    required = required_args(target, args, kwargs)\n    to_infer = {k for k, v in kwargs.items() if v is ...}\n    if required or to_infer:\n        if (\n            isinstance(target, type)\n            and (attr := sys.modules.get(\"attr\")) is not None\n            and attr.has(target)\n        ):  # pragma: no cover  # covered by our attrs tests in check-niche\n            # Use our custom introspection for attrs classes\n            from hypothesis.strategies._internal.attrs import from_attrs\n\n            return from_attrs(target, args, kwargs, required | to_infer)\n        # Otherwise, try using type hints\n        hints = get_type_hints(target)\n        if to_infer - set(hints):\n            badargs = \", \".join(sorted(to_infer - set(hints)))\n            raise InvalidArgument(\n                f\"passed ... for {badargs}, but we cannot infer a strategy \"\n                \"because these arguments have no type annotation\"\n            )\n        infer_for = {k: v for k, v in hints.items() if k in (required | to_infer)}\n        if infer_for:\n            from hypothesis.strategies._internal.types import _global_type_lookup\n\n            for kw, t in infer_for.items():\n                if t in _global_type_lookup:\n                    kwargs[kw] = from_type(t)\n                else:\n                    # We defer resolution of these type annotations so that the obvious\n                    # approach to registering recursive types just works.  I.e.,\n                    # if we're inside `register_type_strategy(cls, builds(cls, ...))`\n                    # and `...` contains recursion on `cls`.  See\n                    # https://github.com/HypothesisWorks/hypothesis/issues/3026\n                    kwargs[kw] = deferred(lambda t=t: from_type(t))  # type: ignore\n\n    # validated by handling all EllipsisType in the to_infer case\n    kwargs = cast(dict[str, SearchStrategy], kwargs)\n    return BuildsStrategy(target, args, kwargs)\n\n\n@cacheable\n@defines_strategy(eager=True)\ndef from_type(thing: type[T]) -> SearchStrategy[T]:\n    \"\"\"Looks up the appropriate search strategy for the given type.\n\n    |st.from_type| is used internally to fill in missing arguments to\n    |st.builds| and can be used interactively\n    to explore what strategies are available or to debug type resolution.\n\n    You can use |st.register_type_strategy| to\n    handle your custom types, or to globally redefine certain strategies -\n    for example excluding NaN from floats, or use timezone-aware instead of\n    naive time and datetime strategies.\n\n    |st.from_type| looks up a strategy in the following order:\n\n    1. If ``thing`` is in the default lookup mapping or user-registered lookup,\n       return the corresponding strategy.  The default lookup covers all types\n       with Hypothesis strategies, including extras where possible.\n    2. If ``thing`` is from the :mod:`python:typing` module, return the\n       corresponding strategy (special logic).\n    3. If ``thing`` has one or more subtypes in the merged lookup, return\n       the union of the strategies for those types that are not subtypes of\n       other elements in the lookup.\n    4. Finally, if ``thing`` has type annotations for all required arguments,\n       and is not an abstract class, it is resolved via\n       |st.builds|.\n    5. Because :mod:`abstract types <python:abc>` cannot be instantiated,\n       we treat abstract types as the union of their concrete subclasses.\n       Note that this lookup works via inheritance but not via\n       :obj:`~python:abc.ABCMeta.register`, so you may still need to use\n       |st.register_type_strategy|.\n\n    There is a valuable recipe for leveraging |st.from_type| to generate\n    \"everything except\" values from a specified type. I.e.\n\n    .. code-block:: python\n\n        def everything_except(excluded_types):\n            return (\n                from_type(type)\n                .flatmap(from_type)\n                .filter(lambda x: not isinstance(x, excluded_types))\n            )\n\n    For example, ``everything_except(int)`` returns a strategy that can\n    generate anything that |st.from_type| can ever generate, except for\n    instances of |int|, and excluding instances of types\n    added via |st.register_type_strategy|.\n\n    This is useful when writing tests which check that invalid input is\n    rejected in a certain way.\n    \"\"\"\n    try:\n        with warnings.catch_warnings():\n            warnings.simplefilter(\"error\")\n            return _from_type(thing)\n    except Exception:\n        return _from_type_deferred(thing)\n\n\ndef _from_type_deferred(thing: type[Ex]) -> SearchStrategy[Ex]:\n    # This tricky little dance is because we want to show the repr of the actual\n    # underlying strategy wherever possible, as a form of user education, but\n    # would prefer to fall back to the default \"from_type(...)\" repr instead of\n    # \"deferred(...)\" for recursive types or invalid arguments.\n    try:\n        thing_repr = nicerepr(thing)\n        if hasattr(thing, \"__module__\"):\n            module_prefix = f\"{thing.__module__}.\"\n            if not thing_repr.startswith(module_prefix):\n                thing_repr = module_prefix + thing_repr\n        repr_ = f\"from_type({thing_repr})\"\n    except Exception:  # pragma: no cover\n        repr_ = None\n    return LazyStrategy(\n        lambda thing: deferred(lambda: _from_type(thing)),\n        (thing,),\n        {},\n        force_repr=repr_,\n    )\n\n\n_recurse_guard: ContextVar = ContextVar(\"recurse_guard\")\n\n\ndef _from_type(thing: type[Ex]) -> SearchStrategy[Ex]:\n    # TODO: We would like to move this to the top level, but pending some major\n    # refactoring it's hard to do without creating circular imports.\n    from hypothesis.strategies._internal import types\n\n    def as_strategy(strat_or_callable, thing):\n        # User-provided strategies need some validation, and callables even more\n        # of it.  We do this in three places, hence the helper function\n        if not isinstance(strat_or_callable, SearchStrategy):\n            assert callable(strat_or_callable)  # Validated in register_type_strategy\n            strategy = strat_or_callable(thing)\n        else:\n            strategy = strat_or_callable\n        if strategy is NotImplemented:\n            return NotImplemented\n        if not isinstance(strategy, SearchStrategy):\n            raise ResolutionFailed(\n                f\"Error: {thing} was registered for {nicerepr(strat_or_callable)}, \"\n                f\"but returned non-strategy {strategy!r}\"\n            )\n        if strategy.is_empty:\n            raise ResolutionFailed(f\"Error: {thing!r} resolved to an empty strategy\")\n        return strategy\n\n    def from_type_guarded(thing):\n        \"\"\"Returns the result of producer, or ... if recursion on thing is encountered\"\"\"\n        try:\n            recurse_guard = _recurse_guard.get()\n        except LookupError:\n            # We can't simply define the contextvar with default=[], as the\n            # default object would be shared across contexts\n            _recurse_guard.set(recurse_guard := [])\n        if thing in recurse_guard:\n            raise RewindRecursive(thing)\n        recurse_guard.append(thing)\n        try:\n            return _from_type(thing)\n        except RewindRecursive as rr:\n            if rr.target != thing:\n                raise\n            return ...  # defer resolution\n        finally:\n            recurse_guard.pop()\n\n    # Let registered extra modules handle their own recognized types first, before\n    # e.g. Unions are resolved\n    try:\n        known = thing in types._global_type_lookup\n    except TypeError:\n        # thing is not always hashable!\n        pass\n    else:\n        if not known:\n            for module, resolver in types._global_extra_lookup.items():\n                if module in sys.modules:\n                    strat = resolver(thing)\n                    if strat is not None:\n                        return strat\n\n    if isinstance(thing, NewType):\n        # Check if we have an explicitly registered strategy for this thing,\n        # resolve it so, and otherwise resolve as for the base type.\n        if thing in types._global_type_lookup:\n            strategy = as_strategy(types._global_type_lookup[thing], thing)\n            if strategy is not NotImplemented:\n                return strategy\n        return _from_type(thing.__supertype__)\n    if types.is_a_type_alias_type(thing):  # pragma: no cover # covered by 3.12+ tests\n        if thing in types._global_type_lookup:\n            strategy = as_strategy(types._global_type_lookup[thing], thing)\n            if strategy is not NotImplemented:\n                return strategy\n        return _from_type(thing.__value__)  # type: ignore\n    if types.is_a_type_alias_type(origin := get_origin(thing)):  # pragma: no cover\n        # Handle parametrized type aliases like `type A[T] = list[T]; thing = A[int]`.\n        # In this case, `thing` is a GenericAlias whose origin is a TypeAliasType.\n        #\n        # covered by 3.12+ tests.\n        if origin in types._global_type_lookup:\n            strategy = as_strategy(types._global_type_lookup[origin], thing)\n            if strategy is not NotImplemented:\n                return strategy\n        return _from_type(types.evaluate_type_alias_type(thing))\n    if types.is_a_union(thing):\n        args = sorted(thing.__args__, key=types.type_sorting_key)  # type: ignore\n        return one_of([_from_type(t) for t in args])\n    if thing in types.LiteralStringTypes:  # pragma: no cover\n        # We can't really cover this because it needs either\n        # typing-extensions or python3.11+ typing.\n        # `LiteralString` from runtime's point of view is just a string.\n        # Fallback to regular text.\n        return text()  # type: ignore\n\n    # We also have a special case for TypeVars.\n    # They are represented as instances like `~T` when they come here.\n    # We need to work with their type instead.\n    if isinstance(thing, TypeVar) and type(thing) in types._global_type_lookup:\n        strategy = as_strategy(types._global_type_lookup[type(thing)], thing)\n        if strategy is not NotImplemented:\n            return strategy\n\n    if not types.is_a_type(thing):\n        if isinstance(thing, str):\n            # See https://github.com/HypothesisWorks/hypothesis/issues/3016\n            raise InvalidArgument(\n                f\"Got {thing!r} as a type annotation, but the forward-reference \"\n                \"could not be resolved from a string to a type.  Consider using \"\n                \"`from __future__ import annotations` instead of forward-reference \"\n                \"strings.\"\n            )\n        raise InvalidArgument(f\"{thing=} must be a type\")  # pragma: no cover\n\n    if thing in types.NON_RUNTIME_TYPES:\n        # Some code like `st.from_type(TypeAlias)` does not make sense.\n        # Because there are types in python that do not exist in runtime.\n        raise InvalidArgument(\n            f\"Could not resolve {thing!r} to a strategy, \"\n            f\"because there is no such thing as a runtime instance of {thing!r}\"\n        )\n\n    # Now that we know `thing` is a type, the first step is to check for an\n    # explicitly registered strategy. This is the best (and hopefully most\n    # common) way to resolve a type to a strategy.  Note that the value in the\n    # lookup may be a strategy or a function from type -> strategy; and we\n    # convert empty results into an explicit error.\n    try:\n        if thing in types._global_type_lookup:\n            strategy = as_strategy(types._global_type_lookup[thing], thing)\n            if strategy is not NotImplemented:\n                return strategy\n        elif (\n            isinstance(thing, GenericAlias)\n            and (origin := get_origin(thing)) in types._global_type_lookup\n        ):\n            strategy = as_strategy(types._global_type_lookup[origin], thing)\n            if strategy is not NotImplemented:\n                return strategy\n    except TypeError:  # pragma: no cover\n        # This was originally due to a bizarre divergence in behaviour on Python 3.9.0:\n        # typing.Callable[[], foo] has __args__ = (foo,) but collections.abc.Callable\n        # has __args__ = ([], foo); and as a result is non-hashable.\n        # We've kept it because we turn out to have more type errors from... somewhere.\n        # FIXME: investigate that, maybe it should be fixed more precisely?\n        pass\n\n    if (hasattr(typing, \"_TypedDictMeta\") and type(thing) is typing._TypedDictMeta) or (\n        hasattr(types.typing_extensions, \"_TypedDictMeta\")  # type: ignore\n        and type(thing) is types.typing_extensions._TypedDictMeta  # type: ignore\n    ):  # pragma: no cover\n\n        def _get_annotation_arg(key, annotation_type):\n            try:\n                return get_args(annotation_type)[0]\n            except IndexError:\n                raise InvalidArgument(\n                    f\"`{key}: {annotation_type.__name__}` is not a valid type annotation\"\n                ) from None\n\n        # Taken from `Lib/typing.py` and modified:\n        def _get_typeddict_qualifiers(key, annotation_type):\n            qualifiers = []\n            annotations = []\n            while True:\n                annotation_origin = types.extended_get_origin(annotation_type)\n                if annotation_origin is Annotated:\n                    if annotation_args := get_args(annotation_type):\n                        annotation_type = annotation_args[0]\n                        annotations.extend(annotation_args[1:])\n                    else:\n                        break\n                elif annotation_origin in types.RequiredTypes:\n                    qualifiers.append(types.RequiredTypes)\n                    annotation_type = _get_annotation_arg(key, annotation_type)\n                elif annotation_origin in types.NotRequiredTypes:\n                    qualifiers.append(types.NotRequiredTypes)\n                    annotation_type = _get_annotation_arg(key, annotation_type)\n                elif annotation_origin in types.ReadOnlyTypes:\n                    qualifiers.append(types.ReadOnlyTypes)\n                    annotation_type = _get_annotation_arg(key, annotation_type)\n                else:\n                    break\n            if annotations:\n                annotation_type = Annotated[(annotation_type, *annotations)]\n            return set(qualifiers), annotation_type\n\n        # The __optional_keys__ attribute may or may not be present, but if there's no\n        # way to tell and we just have to assume that everything is required.\n        # See https://github.com/python/cpython/pull/17214 for details.\n        optional = set(getattr(thing, \"__optional_keys__\", ()))\n        required = set(\n            getattr(thing, \"__required_keys__\", get_type_hints(thing).keys())\n        )\n        anns = {}\n        for k, v in get_type_hints(thing).items():\n            qualifiers, v = _get_typeddict_qualifiers(k, v)\n            # We ignore `ReadOnly` type for now, only unwrap it.\n            if types.RequiredTypes in qualifiers:\n                optional.discard(k)\n                required.add(k)\n            if types.NotRequiredTypes in qualifiers:\n                optional.add(k)\n                required.discard(k)\n\n            anns[k] = from_type_guarded(v)\n            if anns[k] is ...:\n                anns[k] = _from_type_deferred(v)\n\n        if not required.isdisjoint(optional):  # pragma: no cover\n            # It is impossible to cover, because `typing.py` or `typing-extensions`\n            # won't allow creating incorrect TypedDicts,\n            # this is just a sanity check from our side.\n            raise InvalidArgument(\n                f\"Required keys overlap with optional keys in a TypedDict:\"\n                f\" {required=}, {optional=}\"\n            )\n        if (\n            (not anns)\n            and thing.__annotations__\n            and \".<locals>.\" in getattr(thing, \"__qualname__\", \"\")\n        ):\n            raise InvalidArgument(\"Failed to retrieve type annotations for local type\")\n        return fixed_dictionaries(  # type: ignore\n            mapping={k: v for k, v in anns.items() if k in required},\n            optional={k: v for k, v in anns.items() if k in optional},\n        )\n\n    # If there's no explicitly registered strategy, maybe a subtype of thing\n    # is registered - if so, we can resolve it to the subclass strategy.\n    # We'll start by checking if thing is from the typing module,\n    # because there are several special cases that don't play well with\n    # subclass and instance checks.\n    if (\n        isinstance(thing, types.typing_root_type)\n        or (isinstance(get_origin(thing), type) and get_args(thing))\n        or isinstance(thing, typing.ForwardRef)\n    ):\n        return types.from_typing_type(thing)\n\n    # If it's not from the typing module, we get all registered types that are\n    # a subclass of `thing` and are not themselves a subtype of any other such\n    # type.  For example, `Number -> integers() | floats()`, but bools() is\n    # not included because bool is a subclass of int as well as Number.\n    strategies = [\n        s\n        for s in (\n            as_strategy(v, thing)\n            for k, v in sorted(types._global_type_lookup.items(), key=repr)\n            if isinstance(k, type)\n            and issubclass(k, thing)\n            and sum(types.try_issubclass(k, typ) for typ in types._global_type_lookup)\n            == 1\n        )\n        if s is not NotImplemented\n    ]\n    if any(not s.is_empty for s in strategies):\n        return one_of(strategies)\n\n    # If we don't have a strategy registered for this type or any subtype, we\n    # may be able to fall back on type annotations.\n    if issubclass(thing, enum.Enum):\n        return sampled_from(thing)\n\n    # Finally, try to build an instance by calling the type object.  Unlike builds(),\n    # this block *does* try to infer strategies for arguments with default values.\n    # That's because of the semantic different; builds() -> \"call this with ...\"\n    # so we only infer when *not* doing so would be an error; from_type() -> \"give\n    # me arbitrary instances\" so the greater variety is acceptable.\n    # And if it's *too* varied, express your opinions with register_type_strategy()\n    if not isabstract(thing):\n        # If we know that builds(thing) will fail, give a better error message\n        required = required_args(thing)\n        if required and not (\n            required.issubset(get_type_hints(thing))\n            or ((attr := sys.modules.get(\"attr\")) is not None and attr.has(thing))\n            or is_typed_named_tuple(thing)  # weird enough that we have a specific check\n        ):\n            raise ResolutionFailed(\n                f\"Could not resolve {thing!r} to a strategy; consider \"\n                \"using register_type_strategy\"\n            )\n        try:\n            hints = get_type_hints(thing)\n            params = get_signature(thing).parameters\n        except Exception:\n            params = {}  # type: ignore\n\n        posonly_args = []\n        kwargs = {}\n        for k, p in params.items():\n            if (\n                p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD, p.KEYWORD_ONLY)\n                and k in hints\n                and k != \"return\"\n            ):\n                ps = from_type_guarded(hints[k])\n                if p.default is not Parameter.empty and ps is not ...:\n                    ps = just(p.default) | ps\n                if p.kind is Parameter.POSITIONAL_ONLY:\n                    # builds() doesn't infer strategies for positional args, so:\n                    if ps is ...:  # pragma: no cover  # rather fiddly to test\n                        if p.default is Parameter.empty:\n                            raise ResolutionFailed(\n                                f\"Could not resolve {thing!r} to a strategy; \"\n                                \"consider using register_type_strategy\"\n                            )\n                        ps = just(p.default)\n                    posonly_args.append(ps)\n                else:\n                    kwargs[k] = ps\n        if (\n            params\n            and not (posonly_args or kwargs)\n            and not issubclass(thing, BaseException)\n        ):\n            from_type_repr = repr_call(from_type, (thing,), {})\n            builds_repr = repr_call(builds, (thing,), {})\n            warnings.warn(\n                f\"{from_type_repr} resolved to {builds_repr}, because we could not \"\n                \"find any (non-varargs) arguments. Use st.register_type_strategy() \"\n                \"to resolve to a strategy which can generate more than one value, \"\n                \"or to silence this warning.\",\n                SmallSearchSpaceWarning,\n                stacklevel=2,\n            )\n        return builds(thing, *posonly_args, **kwargs)\n\n    # And if it's an abstract type, we'll resolve to a union of subclasses instead.\n    subclasses = thing.__subclasses__()\n    if not subclasses:\n        raise ResolutionFailed(\n            f\"Could not resolve {thing!r} to a strategy, because it is an abstract \"\n            \"type without any subclasses. Consider using register_type_strategy\"\n        )\n\n    subclass_strategies: SearchStrategy = nothing()\n    for sc in subclasses:\n        try:\n            subclass_strategies |= _from_type(sc)\n        except Exception:\n            pass\n    if subclass_strategies.is_empty:\n        # We're unable to resolve subclasses now, but we might be able to later -\n        # so we'll just go back to the mixed distribution.\n        return sampled_from(subclasses).flatmap(_from_type)\n    return subclass_strategies\n\n\n@cacheable\n@defines_strategy(force_reusable_values=True)\ndef fractions(\n    min_value: Real | str | None = None,\n    max_value: Real | str | None = None,\n    *,\n    max_denominator: int | None = None,\n) -> SearchStrategy[Fraction]:\n    \"\"\"Returns a strategy which generates Fractions.\n\n    If ``min_value`` is not None then all generated values are no less than\n    ``min_value``.  If ``max_value`` is not None then all generated values are no\n    greater than ``max_value``.  ``min_value`` and ``max_value`` may be anything accepted\n    by the :class:`~fractions.Fraction` constructor.\n\n    If ``max_denominator`` is not None then the denominator of any generated\n    values is no greater than ``max_denominator``. Note that ``max_denominator`` must\n    be None or a positive integer.\n\n    Examples from this strategy shrink towards smaller denominators, then\n    closer to zero.\n    \"\"\"\n    min_value = try_convert(Fraction, min_value, \"min_value\")\n    max_value = try_convert(Fraction, max_value, \"max_value\")\n    # These assertions tell Mypy what happened in try_convert\n    assert min_value is None or isinstance(min_value, Fraction)\n    assert max_value is None or isinstance(max_value, Fraction)\n\n    check_valid_interval(min_value, max_value, \"min_value\", \"max_value\")\n    check_valid_integer(max_denominator, \"max_denominator\")\n\n    if max_denominator is not None:\n        if max_denominator < 1:\n            raise InvalidArgument(f\"{max_denominator=} must be >= 1\")\n        if min_value is not None and min_value.denominator > max_denominator:\n            raise InvalidArgument(\n                f\"The {min_value=} has a denominator greater than the \"\n                f\"{max_denominator=}\"\n            )\n        if max_value is not None and max_value.denominator > max_denominator:\n            raise InvalidArgument(\n                f\"The {max_value=} has a denominator greater than the \"\n                f\"{max_denominator=}\"\n            )\n\n    if min_value is not None and min_value == max_value:\n        return just(min_value)\n\n    def dm_func(denom):\n        \"\"\"Take denom, construct numerator strategy, and build fraction.\"\"\"\n        # Four cases of algebra to get integer bounds and scale factor.\n        min_num, max_num = None, None\n        if max_value is None and min_value is None:\n            pass\n        elif min_value is None:\n            max_num = denom * max_value.numerator\n            denom *= max_value.denominator\n        elif max_value is None:\n            min_num = denom * min_value.numerator\n            denom *= min_value.denominator\n        else:\n            low = min_value.numerator * max_value.denominator\n            high = max_value.numerator * min_value.denominator\n            scale = min_value.denominator * max_value.denominator\n            # After calculating our integer bounds and scale factor, we remove\n            # the gcd to avoid drawing more bytes for the example than needed.\n            # Note that `div` can be at most equal to `scale`.\n            div = math.gcd(scale, math.gcd(low, high))\n            min_num = denom * low // div\n            max_num = denom * high // div\n            denom *= scale // div\n\n        return builds(\n            Fraction, integers(min_value=min_num, max_value=max_num), just(denom)\n        )\n\n    if max_denominator is None:\n        return integers(min_value=1).flatmap(dm_func)\n\n    return (\n        integers(1, max_denominator)\n        .flatmap(dm_func)\n        .map(lambda f: f.limit_denominator(max_denominator))\n    )\n\n\ndef _as_finite_decimal(\n    value: Real | str | None, name: str, allow_infinity: bool | None, places: int | None\n) -> Decimal | None:\n    \"\"\"Convert decimal bounds to decimals, carefully.\"\"\"\n    assert name in (\"min_value\", \"max_value\")\n    if value is None:\n        return None\n    old = value\n    if isinstance(value, Fraction):\n        value = Context(prec=places).divide(value.numerator, value.denominator)\n        if old != value:\n            raise InvalidArgument(\n                f\"{old!r} cannot be exactly represented as a decimal with {places=}\"\n            )\n    if not isinstance(value, Decimal):\n        with localcontext(Context()):  # ensure that default traps are enabled\n            value = try_convert(Decimal, value, name)\n    assert isinstance(value, Decimal)\n    if value.is_nan():\n        raise InvalidArgument(f\"Invalid {name}={value!r}\")\n\n    # If you are reading this conditional, I am so sorry.  I did my best.\n    finitude_old = value if isinstance(old, str) else old\n    if math.isfinite(finitude_old) != math.isfinite(value) or (\n        value.is_finite() and Fraction(str(old)) != Fraction(str(value))\n    ):\n        note_deprecation(\n            f\"{old!r} cannot be exactly represented as a decimal with {places=}\",\n            since=\"2025-11-02\",\n            has_codemod=False,\n            stacklevel=1,\n        )\n\n    if value.is_finite():\n        return value\n    assert value.is_infinite()\n    if (value < 0 if \"min\" in name else value > 0) and allow_infinity is not False:\n        return None\n    raise InvalidArgument(f\"{allow_infinity=}, but {name}={value!r}\")\n\n\n@cacheable\n@defines_strategy(force_reusable_values=True)\ndef decimals(\n    min_value: Real | str | None = None,\n    max_value: Real | str | None = None,\n    *,\n    allow_nan: bool | None = None,\n    allow_infinity: bool | None = None,\n    places: int | None = None,\n) -> SearchStrategy[Decimal]:\n    \"\"\"Generates instances of :class:`python:decimal.Decimal`, which may be:\n\n    - A finite rational number, between ``min_value`` and ``max_value``.\n    - Not a Number, if ``allow_nan`` is True.  None means \"allow NaN, unless\n      ``min_value`` and ``max_value`` are not None\".\n    - Positive or negative infinity, if ``max_value`` and ``min_value``\n      respectively are None, and ``allow_infinity`` is not False.  None means\n      \"allow infinity, unless excluded by the min and max values\".\n\n    Note that where floats have one ``NaN`` value, Decimals have four: signed,\n    and either *quiet* or *signalling*.  See `the decimal module docs\n    <https://docs.python.org/3/library/decimal.html#special-values>`_ for\n    more information on special values.\n\n    If ``places`` is not None, all finite values drawn from the strategy will\n    have that number of digits after the decimal place.\n\n    Examples from this strategy do not have a well defined shrink order but\n    try to maximize human readability when shrinking.\n    \"\"\"\n    # Convert min_value and max_value to Decimal values, and validate args\n    check_valid_integer(places, \"places\")\n    if places is not None and places < 0:\n        raise InvalidArgument(f\"{places=} may not be negative\")\n    min_value = _as_finite_decimal(min_value, \"min_value\", allow_infinity, places)\n    max_value = _as_finite_decimal(max_value, \"max_value\", allow_infinity, places)\n    check_valid_interval(min_value, max_value, \"min_value\", \"max_value\")\n    if allow_infinity and (None not in (min_value, max_value)):\n        raise InvalidArgument(\"Cannot allow infinity between finite bounds\")\n    # Set up a strategy for finite decimals.  Note that both floating and\n    # fixed-point decimals require careful handling to remain isolated from\n    # any external precision context - in short, we always work out the\n    # required precision for lossless operation and use context methods.\n    if places is not None:\n        # Fixed-point decimals are basically integers with a scale factor\n        def ctx(val):\n            \"\"\"Return a context in which this value is lossless.\"\"\"\n            precision = ceil(math.log10(abs(val) or 1)) + places + 1\n            return Context(prec=max([precision, 1]))\n\n        def int_to_decimal(val):\n            context = ctx(val)\n            return context.quantize(context.multiply(val, factor), factor)\n\n        factor = Decimal(10) ** -places\n        min_num, max_num = None, None\n        if min_value is not None:\n            min_num = ceil(ctx(min_value).divide(min_value, factor))\n        if max_value is not None:\n            max_num = floor(ctx(max_value).divide(max_value, factor))\n        if min_num is not None and max_num is not None and min_num > max_num:\n            raise InvalidArgument(\n                f\"There are no decimals with {places} places between \"\n                f\"{min_value=} and {max_value=}\"\n            )\n        strat = integers(min_num, max_num).map(int_to_decimal)\n    else:\n        # Otherwise, they're like fractions featuring a power of ten\n        def fraction_to_decimal(val):\n            precision = (\n                ceil(math.log10(abs(val.numerator) or 1) + math.log10(val.denominator))\n                + 1\n            )\n            return Context(prec=precision or 1).divide(\n                Decimal(val.numerator), val.denominator\n            )\n\n        strat = fractions(min_value, max_value).map(fraction_to_decimal)\n    # Compose with sampled_from for infinities and NaNs as appropriate\n    special: list[Decimal] = []\n    if allow_infinity or (allow_infinity is None and max_value is None):\n        special.append(Decimal(\"Infinity\"))\n    if allow_infinity or (allow_infinity is None and min_value is None):\n        special.append(Decimal(\"-Infinity\"))\n    if allow_nan or (allow_nan is None and (None in (min_value, max_value))):\n        special.extend(map(Decimal, (\"NaN\", \"-NaN\", \"sNaN\", \"-sNaN\")))\n    return strat | (sampled_from(special) if special else nothing())\n\n\n@defines_strategy(eager=True)\ndef recursive(\n    base: SearchStrategy[Ex],\n    extend: Callable[[SearchStrategy[Any]], SearchStrategy[T]],\n    *,\n    min_leaves: int | None = None,\n    max_leaves: int = 100,\n) -> SearchStrategy[T | Ex]:\n    \"\"\"base: A strategy to start from.\n\n    extend: A function which takes a strategy and returns a new strategy.\n\n    min_leaves: The minimum number of elements to be drawn from base on a given run.\n\n    max_leaves: The maximum number of elements to be drawn from base on a given run.\n\n    This returns a strategy ``S`` such that ``S = extend(base | S)``. That is,\n    values may be drawn from base, or from any strategy reachable by mixing\n    applications of | and extend.\n\n    An example may clarify: ``recursive(booleans(), lists)`` would return a\n    strategy that may return arbitrarily nested and mixed lists of booleans.\n    So e.g. ``False``, ``[True]``, ``[False, []]``, and ``[[[[True]]]]`` are\n    all valid values to be drawn from that strategy.\n\n    Examples from this strategy shrink by trying to reduce the amount of\n    recursion and by shrinking according to the shrinking behaviour of base\n    and the result of extend.\n    \"\"\"\n    return RecursiveStrategy(base, extend, min_leaves, max_leaves)\n\n\nclass PermutationStrategy(SearchStrategy):\n    def __init__(self, values):\n        super().__init__()\n        self.values = values\n\n    def do_draw(self, data):\n        # Reversed Fisher-Yates shuffle: swap each element with itself or with\n        # a later element.  This shrinks i==j for each element, i.e. to no\n        # change.  We don't consider the last element as it's always a no-op.\n        result = list(self.values)\n        for i in range(len(result) - 1):\n            j = data.draw_integer(i, len(result) - 1)\n            result[i], result[j] = result[j], result[i]\n        return result\n\n\n@defines_strategy()\ndef permutations(values: Sequence[T]) -> SearchStrategy[list[T]]:\n    \"\"\"Return a strategy which returns permutations of the ordered collection\n    ``values``.\n\n    Examples from this strategy shrink by trying to become closer to the\n    original order of values.\n    \"\"\"\n    values = check_sample(values, \"permutations\")\n    if not values:\n        return builds(list)\n\n    return PermutationStrategy(values)\n\n\nclass CompositeStrategy(SearchStrategy):\n    def __init__(self, definition, args, kwargs):\n        super().__init__()\n        self.definition = definition\n        self.args = args\n        self.kwargs = kwargs\n\n    def do_draw(self, data):\n        return self.definition(data.draw, *self.args, **self.kwargs)\n\n    def calc_label(self) -> int:\n        return combine_labels(\n            self.class_label,\n            calc_label_from_callable(self.definition),\n        )\n\n\nclass DrawFn(Protocol):\n    \"\"\"This type only exists so that you can write type hints for functions\n    decorated with :func:`@composite <hypothesis.strategies.composite>`.\n\n    .. code-block:: python\n\n        def draw(strategy: SearchStrategy[Ex], label: object = None) -> Ex: ...\n\n        @composite\n        def list_and_index(draw: DrawFn) -> tuple[int, str]:\n            i = draw(integers())  # type of `i` inferred as 'int'\n            s = draw(text())  # type of `s` inferred as 'str'\n            return i, s\n    \"\"\"\n\n    def __init__(self):\n        raise TypeError(\"Protocols cannot be instantiated\")  # pragma: no cover\n\n    # Protocol overrides our signature for __init__,\n    # so we override it right back to make the docs look nice.\n    __signature__: Signature = Signature(parameters=[])\n\n    # We define this as a callback protocol because a simple typing.Callable is\n    # insufficient to fully represent the interface, due to the optional `label`\n    # parameter.\n    def __call__(self, strategy: SearchStrategy[Ex], label: object = None) -> Ex:\n        raise NotImplementedError\n\n\ndef _composite(f):\n    # Wrapped below, using ParamSpec if available\n    if isinstance(f, (classmethod, staticmethod)):\n        special_method = type(f)\n        f = f.__func__\n    else:\n        special_method = None\n\n    sig = get_signature(f)\n    params = tuple(sig.parameters.values())\n\n    if not (params and \"POSITIONAL\" in params[0].kind.name):\n        raise InvalidArgument(\n            \"Functions wrapped with composite must take at least one \"\n            \"positional argument.\"\n        )\n    if params[0].default is not sig.empty:\n        raise InvalidArgument(\"A default value for initial argument will never be used\")\n    if not (f is typing._overload_dummy or is_first_param_referenced_in_function(f)):\n        note_deprecation(\n            \"There is no reason to use @st.composite on a function which \"\n            \"does not call the provided draw() function internally.\",\n            since=\"2022-07-17\",\n            has_codemod=False,\n        )\n    if get_origin(sig.return_annotation) is SearchStrategy:\n        ret_repr = repr(sig.return_annotation).replace(\"hypothesis.strategies.\", \"st.\")\n        warnings.warn(\n            f\"Return-type annotation is `{ret_repr}`, but the decorated \"\n            \"function should return a value (not a strategy)\",\n            HypothesisWarning,\n            stacklevel=3,\n        )\n    if params[0].kind.name != \"VAR_POSITIONAL\":\n        params = params[1:]\n    newsig = sig.replace(\n        parameters=params,\n        return_annotation=(\n            SearchStrategy\n            if sig.return_annotation is sig.empty\n            else SearchStrategy[sig.return_annotation]\n        ),\n    )\n\n    @defines_strategy()\n    @define_function_signature(f.__name__, f.__doc__, newsig)\n    def accept(*args, **kwargs):\n        return CompositeStrategy(f, args, kwargs)\n\n    accept.__module__ = f.__module__\n    accept.__signature__ = newsig\n    if special_method is not None:\n        return special_method(accept)\n    return accept\n\n\ncomposite_doc = \"\"\"\nDefines a strategy that is built out of potentially arbitrarily many other\nstrategies.\n\n@composite provides a callable ``draw`` as the first parameter to the decorated\nfunction, which can be used to dynamically draw a value from any strategy. For\nexample:\n\n.. code-block:: python\n\n    from hypothesis import strategies as st, given\n\n    @st.composite\n    def values(draw):\n        n1 = draw(st.integers())\n        n2 = draw(st.integers(min_value=n1))\n        return (n1, n2)\n\n    @given(values())\n    def f(value):\n        (n1, n2) = value\n        assert n1 <= n2\n\n@composite cannot mix test code and generation code. If you need that, use\n|st.data|.\n\nIf :func:`@composite <hypothesis.strategies.composite>` is used to decorate a\nmethod or classmethod, the ``draw`` argument must come before ``self`` or\n``cls``. While we therefore recommend writing strategies as standalone functions\nand using |st.register_type_strategy| to associate them with a class, methods\nare supported and the ``@composite`` decorator may be applied either before or\nafter ``@classmethod`` or ``@staticmethod``. See :issue:`2578` and :pull:`2634`\nfor more details.\n\nExamples from this strategy shrink by shrinking the output of each draw call.\n\"\"\"\nif typing.TYPE_CHECKING or ParamSpec is not None:\n    P = ParamSpec(\"P\")\n\n    def composite(\n        f: Callable[Concatenate[DrawFn, P], Ex],\n    ) -> Callable[P, SearchStrategy[Ex]]:\n        return _composite(f)\n\nelse:  # pragma: no cover\n\n    @cacheable\n    def composite(f: Callable[..., Ex]) -> Callable[..., SearchStrategy[Ex]]:\n        return _composite(f)\n\n\ncomposite.__doc__ = composite_doc\n\n\n@defines_strategy(force_reusable_values=True)\n@cacheable\ndef complex_numbers(\n    *,\n    min_magnitude: Real = 0,\n    max_magnitude: Real | None = None,\n    allow_infinity: bool | None = None,\n    allow_nan: bool | None = None,\n    allow_subnormal: bool = True,\n    width: Literal[32, 64, 128] = 128,\n) -> SearchStrategy[complex]:\n    \"\"\"Returns a strategy that generates :class:`~python:complex`\n    numbers.\n\n    This strategy draws complex numbers with constrained magnitudes.\n    The ``min_magnitude`` and ``max_magnitude`` parameters should be\n    non-negative :class:`~python:numbers.Real` numbers; a value\n    of ``None`` corresponds an infinite upper bound.\n\n    If ``min_magnitude`` is nonzero or ``max_magnitude`` is finite, it\n    is an error to enable ``allow_nan``.  If ``max_magnitude`` is finite,\n    it is an error to enable ``allow_infinity``.\n\n    ``allow_infinity``, ``allow_nan``, and ``allow_subnormal`` are\n    applied to each part of the complex number separately, as for\n    :func:`~hypothesis.strategies.floats`.\n\n    The magnitude constraints are respected up to a relative error\n    of (around) floating-point epsilon, due to implementation via\n    the system ``sqrt`` function.\n\n    The ``width`` argument specifies the maximum number of bits of precision\n    required to represent the entire generated complex number.\n    Valid values are 32, 64 or 128, which correspond to the real and imaginary\n    components each having width 16, 32 or 64, respectively.\n    Passing ``width=64`` will still use the builtin 128-bit\n    :class:`~python:complex` class, but always for values which can be\n    exactly represented as two 32-bit floats.\n\n    Examples from this strategy shrink by shrinking their real and\n    imaginary parts, as :func:`~hypothesis.strategies.floats`.\n\n    If you need to generate complex numbers with particular real and\n    imaginary parts or relationships between parts, consider using\n    :func:`builds(complex, ...) <hypothesis.strategies.builds>` or\n    :func:`@composite <hypothesis.strategies.composite>` respectively.\n    \"\"\"\n    check_valid_magnitude(min_magnitude, \"min_magnitude\")\n    check_valid_magnitude(max_magnitude, \"max_magnitude\")\n    check_valid_interval(min_magnitude, max_magnitude, \"min_magnitude\", \"max_magnitude\")\n    if max_magnitude == math.inf:\n        max_magnitude = None\n\n    if allow_infinity is None:\n        allow_infinity = bool(max_magnitude is None)\n    elif allow_infinity and max_magnitude is not None:\n        raise InvalidArgument(f\"Cannot have {allow_infinity=} with {max_magnitude=}\")\n    if allow_nan is None:\n        allow_nan = bool(min_magnitude == 0 and max_magnitude is None)\n    elif allow_nan and not (min_magnitude == 0 and max_magnitude is None):\n        raise InvalidArgument(\n            f\"Cannot have {allow_nan=}, {min_magnitude=}, {max_magnitude=}\"\n        )\n    check_type(bool, allow_subnormal, \"allow_subnormal\")\n    if width not in (32, 64, 128):\n        raise InvalidArgument(\n            f\"{width=}, but must be 32, 64 or 128 (other complex dtypes \"\n            \"such as complex192 or complex256 are not supported)\"\n            # For numpy, these types would be supported (but not by CPython):\n            # https://numpy.org/doc/stable/reference/arrays.scalars.html#complex-floating-point-types\n        )\n    component_width = width // 2\n    allow_kw = {\n        \"allow_nan\": allow_nan,\n        \"allow_infinity\": allow_infinity,\n        # If we have a nonzero normal min_magnitude and draw a zero imaginary part,\n        # then allow_subnormal=True would be an error with the min_value to the floats()\n        # strategy for the real part.  We therefore replace True with None.\n        \"allow_subnormal\": None if allow_subnormal else allow_subnormal,\n        \"width\": component_width,\n    }\n\n    if min_magnitude == 0 and max_magnitude is None:\n        # In this simple but common case, there are no constraints on the\n        # magnitude and therefore no relationship between the real and\n        # imaginary parts.\n        return builds(complex, floats(**allow_kw), floats(**allow_kw))  # type: ignore\n\n    @composite\n    def constrained_complex(draw):\n        # We downcast drawn floats to the desired (component) width so we\n        # guarantee the resulting complex values are representable. Note\n        # truncating the mantissa bits with float_of() cannot increase the\n        # magnitude of a float, so we are guaranteed to stay within the allowed\n        # range. See https://github.com/HypothesisWorks/hypothesis/issues/3573\n\n        # Draw the imaginary part, and determine the maximum real part given\n        # this and the max_magnitude\n        if max_magnitude is None:\n            zi = draw(floats(**allow_kw))\n            rmax = None\n        else:\n            zi = draw(\n                floats(\n                    -float_of(max_magnitude, component_width),\n                    float_of(max_magnitude, component_width),\n                    **allow_kw,\n                )\n            )\n            rmax = float_of(cathetus(max_magnitude, zi), component_width)\n        # Draw the real part from the allowed range given the imaginary part\n        if min_magnitude == 0 or math.fabs(zi) >= min_magnitude:\n            zr = draw(floats(None if rmax is None else -rmax, rmax, **allow_kw))\n        else:\n            rmin = float_of(cathetus(min_magnitude, zi), component_width)\n            zr = draw(floats(rmin, rmax, **allow_kw))\n        # Order of conditions carefully tuned so that for a given pair of\n        # magnitude arguments, we always either draw or do not draw the bool\n        # (crucial for good shrinking behaviour) but only invert when needed.\n        if min_magnitude > 0 and draw(booleans()) and math.fabs(zi) <= min_magnitude:\n            zr = -zr\n        return complex(zr, zi)\n\n    return constrained_complex()\n\n\n@defines_strategy(eager=True)\ndef shared(\n    base: SearchStrategy[Ex],\n    *,\n    key: Hashable | None = None,\n) -> SearchStrategy[Ex]:\n    \"\"\"Returns a strategy that draws a single shared value per run, drawn from\n    base. Any two shared instances with the same key will share the same value,\n    otherwise the identity of this strategy will be used. That is:\n\n    >>> s = integers()  # or any other strategy\n    >>> x = shared(s)\n    >>> y = shared(s)\n\n    In the above x and y may draw different (or potentially the same) values.\n    In the following they will always draw the same:\n\n    >>> x = shared(s, key=\"hi\")\n    >>> y = shared(s, key=\"hi\")\n\n    Examples from this strategy shrink as per their base strategy.\n    \"\"\"\n    return SharedStrategy(base, key)\n\n\n@composite\ndef _maybe_nil_uuids(draw, uuid):\n    # Equivalent to `random_uuids | just(...)`, with a stronger bias to the former.\n    if draw(data()).conjecture_data.draw_boolean(1 / 64):\n        return UUID(\"00000000-0000-0000-0000-000000000000\")\n    return uuid\n\n\n@cacheable\n@defines_strategy(force_reusable_values=True)\ndef uuids(\n    *, version: Literal[1, 2, 3, 4, 5] | None = None, allow_nil: bool = False\n) -> SearchStrategy[UUID]:\n    \"\"\"Returns a strategy that generates :class:`UUIDs <uuid.UUID>`.\n\n    If the optional version argument is given, value is passed through\n    to :class:`~python:uuid.UUID` and only UUIDs of that version will\n    be generated.\n\n    If ``allow_nil`` is True, generate the nil UUID much more often.\n    Otherwise, all returned values from this will be unique, so e.g. if you do\n    ``lists(uuids())`` the resulting list will never contain duplicates.\n\n    Examples from this strategy don't have any meaningful shrink order.\n    \"\"\"\n    check_type(bool, allow_nil, \"allow_nil\")\n    if version not in (None, 1, 2, 3, 4, 5):\n        raise InvalidArgument(\n            f\"{version=}, but version must be in \"\n            \"(None, 1, 2, 3, 4, 5) to pass to the uuid.UUID constructor.\"\n        )\n    random_uuids = shared(\n        randoms(use_true_random=True), key=\"hypothesis.strategies.uuids.generator\"\n    ).map(lambda r: UUID(version=version, int=r.getrandbits(128)))\n\n    if allow_nil:\n        if version is not None:\n            raise InvalidArgument(\"The nil UUID is not of any version\")\n        return random_uuids.flatmap(_maybe_nil_uuids)\n    return random_uuids\n\n\nclass RunnerStrategy(SearchStrategy):\n    def __init__(self, default):\n        super().__init__()\n        self.default = default\n\n    def do_draw(self, data):\n        if data.hypothesis_runner is not_set:\n            if self.default is not_set:\n                raise InvalidArgument(\n                    \"Cannot use runner() strategy with no \"\n                    \"associated runner or explicit default.\"\n                )\n            return self.default\n        return data.hypothesis_runner\n\n\n@defines_strategy(force_reusable_values=True)\ndef runner(*, default: Any = not_set) -> SearchStrategy[Any]:\n    \"\"\"A strategy for getting \"the current test runner\", whatever that may be.\n    The exact meaning depends on the entry point, but it will usually be the\n    associated 'self' value for it.\n\n    If you are using this in a rule for stateful testing, this strategy\n    will return the instance of the :class:`~hypothesis.stateful.RuleBasedStateMachine`\n    that the rule is running for.\n\n    If there is no current test runner and a default is provided, return\n    that default. If no default is provided, raises InvalidArgument.\n\n    Examples from this strategy do not shrink (because there is only one).\n    \"\"\"\n    return RunnerStrategy(default)\n\n\nclass DataObject:\n    \"\"\"This type only exists so that you can write type hints for tests using\n    the :func:`~hypothesis.strategies.data` strategy.  Do not use it directly!\n    \"\"\"\n\n    # Note that \"only exists\" here really means \"is only exported to users\",\n    # but we want to treat it as \"semi-stable\", not document it as \"public API\".\n\n    def __init__(self, data: ConjectureData) -> None:\n        self.count = 0\n        self.conjecture_data = data\n\n    __signature__ = Signature()  # hide internals from Sphinx introspection\n\n    def __repr__(self) -> str:\n        return \"data(...)\"\n\n    def draw(self, strategy: SearchStrategy[Ex], label: Any = None) -> Ex:\n        \"\"\"Like :obj:`~hypothesis.strategies.DrawFn`.\"\"\"\n        check_strategy(strategy, \"strategy\")\n        self.count += 1\n        desc = f\"Draw {self.count}{'' if label is None else f' ({label})'}\"\n        with deprecate_random_in_strategy(\"{}from {!r}\", desc, strategy):\n            result = self.conjecture_data.draw(strategy, observe_as=f\"generate:{desc}\")\n\n        # optimization to avoid needless printer.pretty\n        if should_note():\n            printer = RepresentationPrinter(context=current_build_context())\n            printer.text(f\"{desc}: \")\n            if self.conjecture_data.provider.avoid_realization:\n                printer.text(\"<symbolic>\")\n            else:\n                printer.pretty(result)\n            note(printer.getvalue())\n        return result\n\n\nclass DataStrategy(SearchStrategy):\n    def do_draw(self, data):\n        if data._shared_data_strategy is None:\n            data._shared_data_strategy = DataObject(data)\n        return data._shared_data_strategy\n\n    def __repr__(self) -> str:\n        return \"data()\"\n\n    def map(self, f):\n        self.__not_a_first_class_strategy(\"map\")\n\n    def filter(self, condition: Callable[[Ex], Any]) -> NoReturn:\n        self.__not_a_first_class_strategy(\"filter\")\n\n    def flatmap(self, f):\n        self.__not_a_first_class_strategy(\"flatmap\")\n\n    def example(self) -> NoReturn:\n        self.__not_a_first_class_strategy(\"example\")\n\n    def __not_a_first_class_strategy(self, name: str) -> NoReturn:\n        raise InvalidArgument(\n            f\"Cannot call {name} on a DataStrategy. You should probably \"\n            \"be using @composite for whatever it is you're trying to do.\"\n        )\n\n\n@cacheable\n@defines_strategy(eager=True)\ndef data() -> SearchStrategy[DataObject]:\n    \"\"\"\n    Provides an object ``data`` with a ``data.draw`` function which acts like\n    the ``draw`` callable provided by |st.composite|, in that it can be used\n    to dynamically draw values from strategies. |st.data| is more powerful\n    than |st.composite|, because it allows you to mix generation and test code.\n\n    Here's an example of dynamically generating values using |st.data|:\n\n    .. code-block:: python\n\n        from hypothesis import strategies as st, given\n\n        @given(st.data())\n        def test_values(data):\n            n1 = data.draw(st.integers())\n            n2 = data.draw(st.integers(min_value=n1))\n            assert n1 + 1 <= n2\n\n    If the test fails, each draw will be printed with the falsifying example.\n    e.g. the above is wrong (it has a boundary condition error), so will print:\n\n    .. code-block:: pycon\n\n        Falsifying example: test_values(data=data(...))\n        Draw 1: 0\n        Draw 2: 0\n\n    Optionally, you can provide a label to identify values generated by each call\n    to ``data.draw()``.  These labels can be used to identify values in the\n    output of a falsifying example.\n\n    For instance:\n\n    .. code-block:: python\n\n        @given(st.data())\n        def test_draw_sequentially(data):\n            x = data.draw(st.integers(), label=\"First number\")\n            y = data.draw(st.integers(min_value=x), label=\"Second number\")\n            assert x < y\n\n    will produce:\n\n    .. code-block:: pycon\n\n        Falsifying example: test_draw_sequentially(data=data(...))\n        Draw 1 (First number): 0\n        Draw 2 (Second number): 0\n\n    Examples from this strategy shrink by shrinking the output of each draw call.\n    \"\"\"\n    return DataStrategy()\n\n\nif sys.version_info < (3, 12):\n    # TypeAliasType is new in 3.12\n    RegisterTypeT: TypeAlias = type[Ex]\nelse:  # pragma: no cover  # covered by test_mypy.py\n    from typing import TypeAliasType\n\n    # see https://github.com/HypothesisWorks/hypothesis/issues/4410\n    RegisterTypeT: TypeAlias = type[Ex] | TypeAliasType\n\n\ndef register_type_strategy(\n    custom_type: RegisterTypeT,\n    strategy: SearchStrategy[Ex] | Callable[[type[Ex]], SearchStrategy[Ex]],\n) -> None:\n    \"\"\"Add an entry to the global type-to-strategy lookup.\n\n    This lookup is used in :func:`~hypothesis.strategies.builds` and\n    |@given|.\n\n    :func:`~hypothesis.strategies.builds` will be used automatically for\n    classes with type annotations on ``__init__`` , so you only need to\n    register a strategy if one or more arguments need to be more tightly\n    defined than their type-based default, or if you want to supply a strategy\n    for an argument with a default value.\n\n    ``strategy`` may be a search strategy, or a function that takes a type and\n    returns a strategy (useful for generic types). The function may return\n    :data:`NotImplemented` to conditionally not provide a strategy for the type\n    (the type will still be resolved by other methods, if possible, as if the\n    function was not registered).\n\n    Note that you may not register a parametrised generic type (such as\n    ``MyCollection[int]``) directly, because the resolution logic does not\n    handle this case correctly.  Instead, you may register a *function* for\n    ``MyCollection`` and `inspect the type parameters within that function\n    <https://stackoverflow.com/q/48572831>`__.\n    \"\"\"\n    # TODO: We would like to move this to the top level, but pending some major\n    # refactoring it's hard to do without creating circular imports.\n    from hypothesis.strategies._internal import types\n\n    if not types.is_a_type(custom_type):\n        raise InvalidArgument(f\"{custom_type=} must be a type\")\n    if custom_type in types.NON_RUNTIME_TYPES:\n        raise InvalidArgument(\n            f\"{custom_type=} is not allowed to be registered, \"\n            f\"because there is no such thing as a runtime instance of {custom_type!r}\"\n        )\n    if not (isinstance(strategy, SearchStrategy) or callable(strategy)):\n        raise InvalidArgument(\n            f\"{strategy=} must be a SearchStrategy, or a function that takes \"\n            \"a generic type and returns a specific SearchStrategy\"\n        )\n    if isinstance(strategy, SearchStrategy):\n        with warnings.catch_warnings():\n            warnings.simplefilter(\"error\", HypothesisSideeffectWarning)\n\n            # Calling is_empty forces materialization of lazy strategies. If this is done at import\n            # time, lazy strategies will warn about it; here, we force that warning to raise to\n            # avoid the materialization. Ideally, we'd just check if the strategy is lazy, but the\n            # lazy strategy may be wrapped underneath another strategy so that's complicated.\n            try:\n                if strategy.is_empty:\n                    raise InvalidArgument(f\"{strategy=} must not be empty\")\n            except HypothesisSideeffectWarning:  # pragma: no cover\n                pass\n    if types.has_type_arguments(custom_type):\n        raise InvalidArgument(\n            f\"Cannot register generic type {custom_type!r}, because it has type \"\n            \"arguments which would not be handled.  Instead, register a function \"\n            f\"for {get_origin(custom_type)!r} which can inspect specific type \"\n            \"objects and return a strategy.\"\n        )\n    if (\n        \"pydantic.generics\" in sys.modules\n        and isinstance(custom_type, type)\n        and issubclass(custom_type, sys.modules[\"pydantic.generics\"].GenericModel)\n        and not re.search(r\"[A-Za-z_]+\\[.+\\]\", repr(custom_type))\n        and callable(strategy)\n    ):  # pragma: no cover\n        # See https://github.com/HypothesisWorks/hypothesis/issues/2940\n        raise InvalidArgument(\n            f\"Cannot register a function for {custom_type!r}, because parametrized \"\n            \"`pydantic.generics.GenericModel` subclasses aren't actually generic \"\n            \"types at runtime.  In this case, you should register a strategy \"\n            \"directly for each parametrized form that you anticipate using.\"\n        )\n\n    types._global_type_lookup[custom_type] = strategy\n    from_type.__clear_cache()  # type: ignore\n\n\n@cacheable\n@defines_strategy(eager=True)\ndef deferred(definition: Callable[[], SearchStrategy[Ex]]) -> SearchStrategy[Ex]:\n    \"\"\"A deferred strategy allows you to write a strategy that references other\n    strategies that have not yet been defined. This allows for the easy\n    definition of recursive and mutually recursive strategies.\n\n    The definition argument should be a zero-argument function that returns a\n    strategy. It will be evaluated the first time the strategy is used to\n    produce an example.\n\n    Example usage:\n\n    >>> import hypothesis.strategies as st\n    >>> x = st.deferred(lambda: st.booleans() | st.tuples(x, x))\n    >>> x.example()\n    (((False, (True, True)), (False, True)), (True, True))\n    >>> x.example()\n    True\n\n    Mutual recursion also works fine:\n\n    >>> a = st.deferred(lambda: st.booleans() | b)\n    >>> b = st.deferred(lambda: st.tuples(a, a))\n    >>> a.example()\n    True\n    >>> b.example()\n    (False, (False, ((False, True), False)))\n\n    Examples from this strategy shrink as they normally would from the strategy\n    returned by the definition.\n    \"\"\"\n    return DeferredStrategy(definition)\n\n\ndef domains() -> SearchStrategy[str]:\n    import hypothesis.provisional\n\n    return hypothesis.provisional.domains()\n\n\n@defines_strategy(force_reusable_values=True)\ndef emails(\n    *, domains: SearchStrategy[str] = LazyStrategy(domains, (), {})\n) -> SearchStrategy[str]:\n    \"\"\"A strategy for generating email addresses as unicode strings. The\n    address format is specified in :rfc:`5322#section-3.4.1`. Values shrink\n    towards shorter local-parts and host domains.\n\n    If ``domains`` is given then it must be a strategy that generates domain\n    names for the emails, defaulting to :func:`~hypothesis.provisional.domains`.\n\n    This strategy is useful for generating \"user data\" for tests, as\n    mishandling of email addresses is a common source of bugs.\n    \"\"\"\n    local_chars = string.ascii_letters + string.digits + \"!#$%&'*+-/=^_`{|}~\"\n    local_part = text(local_chars, min_size=1, max_size=64)\n    # TODO: include dot-atoms, quoted strings, escaped chars, etc in local part\n    return builds(\"{}@{}\".format, local_part, domains).filter(\n        lambda addr: len(addr) <= 254\n    )\n\n\ndef _functions(*, like, returns, pure):\n    # Wrapped up to use ParamSpec below\n    check_type(bool, pure, \"pure\")\n    if not callable(like):\n        raise InvalidArgument(\n            \"The first argument to functions() must be a callable to imitate, \"\n            f\"but got non-callable like={nicerepr(like)!r}\"\n        )\n    if returns in (None, ...):\n        # Passing `None` has never been *documented* as working, but it still\n        # did from May 2020 to Jan 2022 so we'll avoid breaking it without cause.\n        hints = get_type_hints(like)\n        returns = from_type(hints.get(\"return\", type(None)))\n    check_strategy(returns, \"returns\")\n    return FunctionStrategy(like, returns, pure)\n\n\nif typing.TYPE_CHECKING or ParamSpec is not None:\n\n    @overload\n    def functions(\n        *, pure: bool = ...\n    ) -> SearchStrategy[Callable[[], None]]:  # pragma: no cover\n        ...\n\n    @overload\n    def functions(\n        *,\n        like: Callable[P, T],\n        pure: bool = ...,\n    ) -> SearchStrategy[Callable[P, T]]:  # pragma: no cover\n        ...\n\n    @overload\n    def functions(\n        *,\n        returns: SearchStrategy[T],\n        pure: bool = ...,\n    ) -> SearchStrategy[Callable[[], T]]:  # pragma: no cover\n        ...\n\n    @overload\n    def functions(\n        *,\n        like: Callable[P, Any],\n        returns: SearchStrategy[T],\n        pure: bool = ...,\n    ) -> SearchStrategy[Callable[P, T]]:  # pragma: no cover\n        ...\n\n    @defines_strategy()\n    def functions(*, like=lambda: None, returns=..., pure=False):\n        # We shouldn't need overloads here, but mypy disallows default args for\n        # generics: https://github.com/python/mypy/issues/3737\n        \"\"\"functions(*, like=lambda: None, returns=..., pure=False)\n\n        A strategy for functions, which can be used in callbacks.\n\n        The generated functions will mimic the interface of ``like``, which must\n        be a callable (including a class, method, or function).  The return value\n        for the function is drawn from the ``returns`` argument, which must be a\n        strategy.  If ``returns`` is not passed, we attempt to infer a strategy\n        from the return-type annotation if present, falling back to :func:`~none`.\n\n        If ``pure=True``, all arguments passed to the generated function must be\n        hashable, and if passed identical arguments the original return value will\n        be returned again - *not* regenerated, so beware mutable values.\n\n        If ``pure=False``, generated functions do not validate their arguments, and\n        may return a different value if called again with the same arguments.\n\n        Generated functions can only be called within the scope of the ``@given``\n        which created them.\n        \"\"\"\n        return _functions(like=like, returns=returns, pure=pure)\n\nelse:  # pragma: no cover\n\n    @defines_strategy()\n    def functions(\n        *,\n        like: Callable[..., Any] = lambda: None,\n        returns: SearchStrategy[Any] | EllipsisType = ...,\n        pure: bool = False,\n    ) -> SearchStrategy[Callable[..., Any]]:\n        \"\"\"functions(*, like=lambda: None, returns=..., pure=False)\n\n        A strategy for functions, which can be used in callbacks.\n\n        The generated functions will mimic the interface of ``like``, which must\n        be a callable (including a class, method, or function).  The return value\n        for the function is drawn from the ``returns`` argument, which must be a\n        strategy.  If ``returns`` is not passed, we attempt to infer a strategy\n        from the return-type annotation if present, falling back to :func:`~none`.\n\n        If ``pure=True``, all arguments passed to the generated function must be\n        hashable, and if passed identical arguments the original return value will\n        be returned again - *not* regenerated, so beware mutable values.\n\n        If ``pure=False``, generated functions do not validate their arguments, and\n        may return a different value if called again with the same arguments.\n\n        Generated functions can only be called within the scope of the ``@given``\n        which created them.\n        \"\"\"\n        return _functions(like=like, returns=returns, pure=pure)\n\n\n@composite\ndef slices(draw: Any, size: int) -> slice:\n    \"\"\"Generates slices that will select indices up to the supplied size\n\n    Generated slices will have start and stop indices that range from -size to size - 1\n    and will step in the appropriate direction. Slices should only produce an empty selection\n    if the start and end are the same.\n\n    Examples from this strategy shrink toward 0 and smaller values\n    \"\"\"\n    check_valid_size(size, \"size\")\n    if size == 0:\n        step = draw(none() | integers().filter(bool))\n        return slice(None, None, step)\n    # For slices start is inclusive and stop is exclusive\n    start = draw(integers(0, size - 1) | none())\n    stop = draw(integers(0, size) | none())\n\n    # Limit step size to be reasonable\n    if start is None and stop is None:\n        max_step = size\n    elif start is None:\n        max_step = stop\n    elif stop is None:\n        max_step = start\n    else:\n        max_step = abs(start - stop)\n\n    step = draw(integers(1, max_step or 1))\n\n    if (draw(booleans()) and start == stop) or (stop or 0) < (start or 0):\n        step *= -1\n\n    if draw(booleans()) and start is not None:\n        start -= size\n    if draw(booleans()) and stop is not None:\n        stop -= size\n    if (not draw(booleans())) and step == 1:\n        step = None\n\n    return slice(start, stop, step)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/datetime.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport datetime as dt\nimport operator as op\nimport warnings\nimport zoneinfo\nfrom calendar import monthrange\nfrom functools import cache, partial\nfrom importlib import resources\nfrom pathlib import Path\n\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.validation import check_type, check_valid_interval\nfrom hypothesis.strategies._internal.core import sampled_from\nfrom hypothesis.strategies._internal.misc import just, none, nothing\nfrom hypothesis.strategies._internal.strategies import SearchStrategy\nfrom hypothesis.strategies._internal.utils import defines_strategy\n\nDATENAMES = (\"year\", \"month\", \"day\")\nTIMENAMES = (\"hour\", \"minute\", \"second\", \"microsecond\")\n\n\ndef is_pytz_timezone(tz):\n    if not isinstance(tz, dt.tzinfo):\n        return False\n    module = type(tz).__module__\n    return module == \"pytz\" or module.startswith(\"pytz.\")\n\n\ndef replace_tzinfo(value, timezone):\n    if is_pytz_timezone(timezone):\n        # Pytz timezones are a little complicated, and using the .replace method\n        # can cause some weird issues, so we use their special \"localize\" instead.\n        #\n        # We use the fold attribute as a convenient boolean for is_dst, even though\n        # they're semantically distinct.  For ambiguous or imaginary hours, fold says\n        # whether you should use the offset that applies before the gap (fold=0) or\n        # the offset that applies after the gap (fold=1). is_dst says whether you\n        # should choose the side that is \"DST\" or \"STD\" (STD->STD or DST->DST\n        # transitions are unclear as you might expect).\n        #\n        # WARNING: this is INCORRECT for timezones with negative DST offsets such as\n        #       \"Europe/Dublin\", but it's unclear what we could do instead beyond\n        #       documenting the problem and recommending use of `dateutil` instead.\n        return timezone.localize(value, is_dst=not value.fold)\n    return value.replace(tzinfo=timezone)\n\n\ndef datetime_does_not_exist(value):\n    \"\"\"This function tests whether the given datetime can be round-tripped to and\n    from UTC.  It is an exact inverse of (and very similar to) the dateutil method\n    https://dateutil.readthedocs.io/en/stable/tz.html#dateutil.tz.datetime_exists\n    \"\"\"\n    # Naive datetimes cannot be imaginary, but we need this special case because\n    # chaining .astimezone() ends with *the system local timezone*, not None.\n    # See bug report in https://github.com/HypothesisWorks/hypothesis/issues/2662\n    if value.tzinfo is None:\n        return False\n    try:\n        # Does the naive portion of the datetime change when round-tripped to\n        # UTC?  If so, or if this overflows, we say that it does not exist.\n        roundtrip = value.astimezone(dt.timezone.utc).astimezone(value.tzinfo)\n    except OverflowError:\n        # Overflows at datetime.min or datetime.max boundary condition.\n        # Rejecting these is acceptable, because timezones are close to\n        # meaningless before ~1900 and subject to a lot of change by\n        # 9999, so it should be a very small fraction of possible values.\n        return True\n\n    if (\n        value.tzinfo is not roundtrip.tzinfo\n        and value.utcoffset() != roundtrip.utcoffset()\n    ):\n        # This only ever occurs during imaginary (i.e. nonexistent) datetimes,\n        # and only for pytz timezones which do not follow PEP-495 semantics.\n        # (may exclude a few other edge cases, but you should use zoneinfo anyway)\n        return True\n\n    assert value.tzinfo is roundtrip.tzinfo, \"so only the naive portions are compared\"\n    return value != roundtrip\n\n\ndef draw_capped_multipart(\n    data, min_value, max_value, duration_names=DATENAMES + TIMENAMES\n):\n    assert isinstance(min_value, (dt.date, dt.time, dt.datetime))\n    assert type(min_value) == type(max_value)\n    assert min_value <= max_value\n    result = {}\n    cap_low, cap_high = True, True\n    for name in duration_names:\n        low = getattr(min_value if cap_low else dt.datetime.min, name)\n        high = getattr(max_value if cap_high else dt.datetime.max, name)\n        if name == \"day\" and not cap_high:\n            _, high = monthrange(**result)\n        if name == \"year\":\n            val = data.draw_integer(low, high, shrink_towards=2000)\n        else:\n            val = data.draw_integer(low, high)\n        result[name] = val\n        cap_low = cap_low and val == low\n        cap_high = cap_high and val == high\n    if hasattr(min_value, \"fold\"):\n        # The `fold` attribute is ignored in comparison of naive datetimes.\n        # In tz-aware datetimes it would require *very* invasive changes to\n        # the logic above, and be very sensitive to the specific timezone\n        # (at the cost of efficient shrinking and mutation), so at least for\n        # now we stick with the status quo and generate it independently.\n        result[\"fold\"] = data.draw_integer(0, 1)\n    return result\n\n\nclass DatetimeStrategy(SearchStrategy):\n    def __init__(self, min_value, max_value, timezones_strat, allow_imaginary):\n        super().__init__()\n        assert isinstance(min_value, dt.datetime)\n        assert isinstance(max_value, dt.datetime)\n        assert min_value.tzinfo is None\n        assert max_value.tzinfo is None\n        assert min_value <= max_value\n        assert isinstance(timezones_strat, SearchStrategy)\n        assert isinstance(allow_imaginary, bool)\n        self.min_value = min_value\n        self.max_value = max_value\n        self.tz_strat = timezones_strat\n        self.allow_imaginary = allow_imaginary\n\n    def do_draw(self, data):\n        # We start by drawing a timezone, and an initial datetime.\n        tz = data.draw(self.tz_strat)\n        result = self.draw_naive_datetime_and_combine(data, tz)\n\n        # TODO: with some probability, systematically search for one of\n        #   - an imaginary time (if allowed),\n        #   - a time within 24hrs of a leap second (if there any are within bounds),\n        #   - other subtle, little-known, or nasty issues as described in\n        #     https://github.com/HypothesisWorks/hypothesis/issues/69\n\n        # If we happened to end up with a disallowed imaginary time, reject it.\n        if (not self.allow_imaginary) and datetime_does_not_exist(result):\n            data.mark_invalid(f\"{result} does not exist (usually a DST transition)\")\n        return result\n\n    def draw_naive_datetime_and_combine(self, data, tz):\n        result = draw_capped_multipart(data, self.min_value, self.max_value)\n        try:\n            return replace_tzinfo(dt.datetime(**result), timezone=tz)\n        except (ValueError, OverflowError):\n            data.mark_invalid(\n                f\"Failed to draw a datetime between {self.min_value!r} and \"\n                f\"{self.max_value!r} with timezone from {self.tz_strat!r}.\"\n            )\n\n\n@defines_strategy(force_reusable_values=True)\ndef datetimes(\n    min_value: dt.datetime = dt.datetime.min,\n    max_value: dt.datetime = dt.datetime.max,\n    *,\n    timezones: SearchStrategy[dt.tzinfo | None] = none(),\n    allow_imaginary: bool = True,\n) -> SearchStrategy[dt.datetime]:\n    \"\"\"datetimes(min_value=datetime.datetime.min, max_value=datetime.datetime.max, *, timezones=none(), allow_imaginary=True)\n\n    A strategy for generating datetimes, which may be timezone-aware.\n\n    This strategy works by drawing a naive datetime between ``min_value``\n    and ``max_value``, which must both be naive (have no timezone).\n\n    ``timezones`` must be a strategy that generates either ``None``, for naive\n    datetimes, or :class:`~python:datetime.tzinfo` objects for 'aware' datetimes.\n    You can construct your own, though we recommend using one of these built-in\n    strategies:\n\n    * with the standard library: :func:`hypothesis.strategies.timezones`;\n    * with :pypi:`dateutil <python-dateutil>`:\n      :func:`hypothesis.extra.dateutil.timezones`; or\n    * with :pypi:`pytz`: :func:`hypothesis.extra.pytz.timezones`.\n\n    You may pass ``allow_imaginary=False`` to filter out \"imaginary\" datetimes\n    which did not (or will not) occur due to daylight savings, leap seconds,\n    timezone and calendar adjustments, etc.  Imaginary datetimes are allowed\n    by default, because malformed timestamps are a common source of bugs.\n\n    Examples from this strategy shrink towards midnight on January 1st 2000,\n    local time.\n    \"\"\"\n    # Why must bounds be naive?  In principle, we could also write a strategy\n    # that took aware bounds, but the API and validation is much harder.\n    # If you want to generate datetimes between two particular moments in\n    # time I suggest (a) just filtering out-of-bounds values; (b) if bounds\n    # are very close, draw a value and subtract its UTC offset, handling\n    # overflows and nonexistent times; or (c) do something customised to\n    # handle datetimes in e.g. a four-microsecond span which is not\n    # representable in UTC.  Handling (d), all of the above, leads to a much\n    # more complex API for all users and a useful feature for very few.\n    check_type(bool, allow_imaginary, \"allow_imaginary\")\n    check_type(dt.datetime, min_value, \"min_value\")\n    check_type(dt.datetime, max_value, \"max_value\")\n    if min_value.tzinfo is not None:\n        raise InvalidArgument(f\"{min_value=} must not have tzinfo\")\n    if max_value.tzinfo is not None:\n        raise InvalidArgument(f\"{max_value=} must not have tzinfo\")\n    check_valid_interval(min_value, max_value, \"min_value\", \"max_value\")\n    if not isinstance(timezones, SearchStrategy):\n        raise InvalidArgument(\n            f\"{timezones=} must be a SearchStrategy that can \"\n            \"provide tzinfo for datetimes (either None or dt.tzinfo objects)\"\n        )\n    return DatetimeStrategy(min_value, max_value, timezones, allow_imaginary)\n\n\nclass TimeStrategy(SearchStrategy):\n    def __init__(self, min_value, max_value, timezones_strat):\n        super().__init__()\n        self.min_value = min_value\n        self.max_value = max_value\n        self.tz_strat = timezones_strat\n\n    def do_draw(self, data):\n        result = draw_capped_multipart(data, self.min_value, self.max_value, TIMENAMES)\n        tz = data.draw(self.tz_strat)\n        return dt.time(**result, tzinfo=tz)\n\n\n@defines_strategy(force_reusable_values=True)\ndef times(\n    min_value: dt.time = dt.time.min,\n    max_value: dt.time = dt.time.max,\n    *,\n    timezones: SearchStrategy[dt.tzinfo | None] = none(),\n) -> SearchStrategy[dt.time]:\n    \"\"\"times(min_value=datetime.time.min, max_value=datetime.time.max, *, timezones=none())\n\n    A strategy for times between ``min_value`` and ``max_value``.\n\n    The ``timezones`` argument is handled as for :py:func:`datetimes`.\n\n    Examples from this strategy shrink towards midnight, with the timezone\n    component shrinking as for the strategy that provided it.\n    \"\"\"\n    check_type(dt.time, min_value, \"min_value\")\n    check_type(dt.time, max_value, \"max_value\")\n    if min_value.tzinfo is not None:\n        raise InvalidArgument(f\"{min_value=} must not have tzinfo\")\n    if max_value.tzinfo is not None:\n        raise InvalidArgument(f\"{max_value=} must not have tzinfo\")\n    check_valid_interval(min_value, max_value, \"min_value\", \"max_value\")\n    return TimeStrategy(min_value, max_value, timezones)\n\n\nclass DateStrategy(SearchStrategy):\n    def __init__(self, min_value, max_value):\n        super().__init__()\n        assert isinstance(min_value, dt.date)\n        assert isinstance(max_value, dt.date)\n        assert min_value < max_value\n        self.min_value = min_value\n        self.max_value = max_value\n\n    def do_draw(self, data):\n        return dt.date(\n            **draw_capped_multipart(data, self.min_value, self.max_value, DATENAMES)\n        )\n\n    def filter(self, condition):\n        if (\n            isinstance(condition, partial)\n            and len(args := condition.args) == 1\n            and not condition.keywords\n            and isinstance(arg := args[0], dt.date)\n            and condition.func in (op.lt, op.le, op.eq, op.ge, op.gt)\n        ):\n            try:\n                arg += dt.timedelta(days={op.lt: 1, op.gt: -1}.get(condition.func, 0))\n            except OverflowError:  # gt date.max, or lt date.min\n                return nothing()\n            lo, hi = {\n                # We're talking about op(arg, x) - the reverse of our usual intuition!\n                op.lt: (arg, self.max_value),  # lambda x: arg < x\n                op.le: (arg, self.max_value),  # lambda x: arg <= x\n                op.eq: (arg, arg),  #            lambda x: arg == x\n                op.ge: (self.min_value, arg),  # lambda x: arg >= x\n                op.gt: (self.min_value, arg),  # lambda x: arg > x\n            }[condition.func]\n            lo = max(lo, self.min_value)\n            hi = min(hi, self.max_value)\n            print(lo, hi)\n            if hi < lo:\n                return nothing()\n            if lo <= self.min_value and self.max_value <= hi:\n                return self\n            return dates(lo, hi)\n\n        return super().filter(condition)\n\n\n@defines_strategy(force_reusable_values=True)\ndef dates(\n    min_value: dt.date = dt.date.min, max_value: dt.date = dt.date.max\n) -> SearchStrategy[dt.date]:\n    \"\"\"dates(min_value=datetime.date.min, max_value=datetime.date.max)\n\n    A strategy for dates between ``min_value`` and ``max_value``.\n\n    Examples from this strategy shrink towards January 1st 2000.\n    \"\"\"\n    check_type(dt.date, min_value, \"min_value\")\n    check_type(dt.date, max_value, \"max_value\")\n    check_valid_interval(min_value, max_value, \"min_value\", \"max_value\")\n    if min_value == max_value:\n        return just(min_value)\n    return DateStrategy(min_value, max_value)\n\n\nclass TimedeltaStrategy(SearchStrategy):\n    def __init__(self, min_value, max_value):\n        super().__init__()\n        assert isinstance(min_value, dt.timedelta)\n        assert isinstance(max_value, dt.timedelta)\n        assert min_value < max_value\n        self.min_value = min_value\n        self.max_value = max_value\n\n    def do_draw(self, data):\n        result = {}\n        low_bound = True\n        high_bound = True\n        for name in (\"days\", \"seconds\", \"microseconds\"):\n            low = getattr(self.min_value if low_bound else dt.timedelta.min, name)\n            high = getattr(self.max_value if high_bound else dt.timedelta.max, name)\n            val = data.draw_integer(low, high)\n            result[name] = val\n            low_bound = low_bound and val == low\n            high_bound = high_bound and val == high\n        return dt.timedelta(**result)\n\n\n@defines_strategy(force_reusable_values=True)\ndef timedeltas(\n    min_value: dt.timedelta = dt.timedelta.min,\n    max_value: dt.timedelta = dt.timedelta.max,\n) -> SearchStrategy[dt.timedelta]:\n    \"\"\"timedeltas(min_value=datetime.timedelta.min, max_value=datetime.timedelta.max)\n\n    A strategy for timedeltas between ``min_value`` and ``max_value``.\n\n    Examples from this strategy shrink towards zero.\n    \"\"\"\n    check_type(dt.timedelta, min_value, \"min_value\")\n    check_type(dt.timedelta, max_value, \"max_value\")\n    check_valid_interval(min_value, max_value, \"min_value\", \"max_value\")\n    if min_value == max_value:\n        return just(min_value)\n    return TimedeltaStrategy(min_value=min_value, max_value=max_value)\n\n\n@cache\ndef _valid_key_cacheable(tzpath, key):\n    assert isinstance(tzpath, tuple)  # zoneinfo changed, better update this function!\n    for root in tzpath:\n        if Path(root).joinpath(key).exists():  # pragma: no branch\n            # No branch because most systems only have one TZPATH component.\n            return True\n    else:  # pragma: no cover\n        # This branch is only taken for names which are known to zoneinfo\n        # but not present on the filesystem, i.e. on Windows with tzdata,\n        # and so is never executed by our coverage tests.\n        *package_loc, resource_name = key.split(\"/\")\n        package = \"tzdata.zoneinfo.\" + \".\".join(package_loc)\n        try:\n            return (resources.files(package) / resource_name).exists()\n        except ModuleNotFoundError:\n            return False\n\n\n@defines_strategy(force_reusable_values=True)\ndef timezone_keys(\n    *,\n    # allow_alias: bool = True,\n    # allow_deprecated: bool = True,\n    allow_prefix: bool = True,\n) -> SearchStrategy[str]:\n    \"\"\"A strategy for :wikipedia:`IANA timezone names <List_of_tz_database_time_zones>`.\n\n    As well as timezone names like ``\"UTC\"``, ``\"Australia/Sydney\"``, or\n    ``\"America/New_York\"``, this strategy can generate:\n\n    - Aliases such as ``\"Antarctica/McMurdo\"``, which links to ``\"Pacific/Auckland\"``.\n    - Deprecated names such as ``\"Antarctica/South_Pole\"``, which *also* links to\n      ``\"Pacific/Auckland\"``.  Note that most but\n      not all deprecated timezone names are also aliases.\n    - Timezone names with the ``\"posix/\"`` or ``\"right/\"`` prefixes, unless\n      ``allow_prefix=False``.\n\n    These strings are provided separately from Tzinfo objects - such as ZoneInfo\n    instances from the timezones() strategy - to facilitate testing of timezone\n    logic without needing workarounds to access non-canonical names.\n\n    .. note::\n\n        `The tzdata package is required on Windows\n        <https://docs.python.org/3/library/zoneinfo.html#data-sources>`__.\n        ``pip install hypothesis[zoneinfo]`` installs it, if and only if needed.\n\n    On Windows, you may need to access IANA timezone data via the :pypi:`tzdata`\n    package.  For non-IANA timezones, such as Windows-native names or GNU TZ\n    strings, we recommend using :func:`~hypothesis.strategies.sampled_from` with\n    the :pypi:`dateutil <python-dateutil>` package, e.g.\n    :meth:`dateutil:dateutil.tz.tzwin.list`.\n    \"\"\"\n    # check_type(bool, allow_alias, \"allow_alias\")\n    # check_type(bool, allow_deprecated, \"allow_deprecated\")\n    check_type(bool, allow_prefix, \"allow_prefix\")\n\n    with warnings.catch_warnings():\n        try:\n            warnings.simplefilter(\"ignore\", EncodingWarning)\n        except NameError:  # pragma: no cover\n            pass\n        # On Python 3.12 (and others?), `available_timezones()` opens files\n        # without specifying an encoding - which our selftests make an error.\n        available_timezones = (\"UTC\", *sorted(zoneinfo.available_timezones()))\n\n    # TODO: filter out alias and deprecated names if disallowed\n\n    # When prefixes are allowed, we first choose a key and then flatmap to get our\n    # choice with one of the available prefixes.  That in turn means that we need\n    # some logic to determine which prefixes are available for a given key:\n\n    def valid_key(key):\n        return key == \"UTC\" or _valid_key_cacheable(zoneinfo.TZPATH, key)\n\n    # TODO: work out how to place a higher priority on \"weird\" timezones\n    # For details see https://github.com/HypothesisWorks/hypothesis/issues/2414\n    strategy = sampled_from([key for key in available_timezones if valid_key(key)])\n\n    if not allow_prefix:\n        return strategy\n\n    def sample_with_prefixes(zone):\n        keys_with_prefixes = (zone, f\"posix/{zone}\", f\"right/{zone}\")\n        return sampled_from([key for key in keys_with_prefixes if valid_key(key)])\n\n    return strategy.flatmap(sample_with_prefixes)\n\n\n@defines_strategy(force_reusable_values=True)\ndef timezones(*, no_cache: bool = False) -> SearchStrategy[\"zoneinfo.ZoneInfo\"]:\n    \"\"\"A strategy for :class:`python:zoneinfo.ZoneInfo` objects.\n\n    If ``no_cache=True``, the generated instances are constructed using\n    :meth:`ZoneInfo.no_cache <python:zoneinfo.ZoneInfo.no_cache>` instead\n    of the usual constructor.  This may change the semantics of your datetimes\n    in surprising ways, so only use it if you know that you need to!\n\n    .. note::\n\n        `The tzdata package is required on Windows\n        <https://docs.python.org/3/library/zoneinfo.html#data-sources>`__.\n        ``pip install hypothesis[zoneinfo]`` installs it, if and only if needed.\n    \"\"\"\n    check_type(bool, no_cache, \"no_cache\")\n    return timezone_keys().map(\n        zoneinfo.ZoneInfo.no_cache if no_cache else zoneinfo.ZoneInfo\n    )\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/deferred.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport inspect\nfrom collections.abc import Callable, Sequence\n\nfrom hypothesis.configuration import check_sideeffect_during_initialization\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.reflection import get_pretty_function_description\nfrom hypothesis.strategies._internal.strategies import (\n    Ex,\n    RecurT,\n    SearchStrategy,\n    check_strategy,\n)\n\n\nclass DeferredStrategy(SearchStrategy[Ex]):\n    \"\"\"A strategy which may be used before it is fully defined.\"\"\"\n\n    def __init__(self, definition: Callable[[], SearchStrategy[Ex]]):\n        super().__init__()\n        self.__wrapped_strategy: SearchStrategy[Ex] | None = None\n        self.__in_repr: bool = False\n        self.__definition: Callable[[], SearchStrategy[Ex]] | None = definition\n\n    @property\n    def wrapped_strategy(self) -> SearchStrategy[Ex]:\n        # we assign this before entering the condition to avoid a race condition\n        # under threading. See issue #4523.\n        definition = self.__definition\n        if self.__wrapped_strategy is None:\n            check_sideeffect_during_initialization(\"deferred evaluation of {!r}\", self)\n\n            if not inspect.isfunction(definition):\n                raise InvalidArgument(\n                    f\"Expected definition to be a function but got {definition!r} \"\n                    f\"of type {type(definition).__name__} instead.\"\n                )\n            result = definition()\n            if result is self:\n                raise InvalidArgument(\"Cannot define a deferred strategy to be itself\")\n            check_strategy(result, \"definition()\")\n            self.__wrapped_strategy = result\n            self.__definition = None\n        return self.__wrapped_strategy\n\n    @property\n    def branches(self) -> Sequence[SearchStrategy[Ex]]:\n        return self.wrapped_strategy.branches\n\n    def calc_label(self) -> int:\n        \"\"\"Deferred strategies don't have a calculated label, because we would\n        end up having to calculate the fixed point of some hash function in\n        order to calculate it when they recursively refer to themself!\n\n        The label for the wrapped strategy will still appear because it\n        will be passed to draw.\n        \"\"\"\n        # This is actually the same as the parent class implementation, but we\n        # include it explicitly here in order to document that this is a\n        # deliberate decision.\n        return self.class_label\n\n    def calc_is_empty(self, recur: RecurT) -> bool:\n        return recur(self.wrapped_strategy)\n\n    def calc_has_reusable_values(self, recur: RecurT) -> bool:\n        return recur(self.wrapped_strategy)\n\n    def __repr__(self) -> str:\n        if self.__wrapped_strategy is not None:\n            if self.__in_repr:\n                return f\"(deferred@{id(self)!r})\"\n            try:\n                self.__in_repr = True\n                return repr(self.__wrapped_strategy)\n            finally:\n                self.__in_repr = False\n        else:\n            description = get_pretty_function_description(self.__definition)\n            return f\"deferred({description})\"\n\n    def do_draw(self, data: ConjectureData) -> Ex:\n        return data.draw(self.wrapped_strategy)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/featureflags.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections.abc import Hashable, Iterable, Sequence\nfrom typing import Any\n\nfrom hypothesis.internal.conjecture import utils as cu\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.strategies._internal.strategies import SearchStrategy\n\nFEATURE_LABEL = cu.calc_label_from_name(\"feature flag\")\n\n\nclass FeatureFlags:\n    \"\"\"Object that can be used to control a number of feature flags for a\n    given test run.\n\n    This enables an approach to data generation called swarm testing (\n    see Groce, Alex, et al. \"Swarm testing.\" Proceedings of the 2012\n    International Symposium on Software Testing and Analysis. ACM, 2012), in\n    which generation is biased by selectively turning some features off for\n    each test case generated. When there are many interacting features this can\n    find bugs that a pure generation strategy would otherwise have missed.\n\n    FeatureFlags are designed to \"shrink open\", so that during shrinking they\n    become less restrictive. This allows us to potentially shrink to smaller\n    test cases that were forbidden during the generation phase because they\n    required disabled features.\n    \"\"\"\n\n    def __init__(\n        self,\n        data: ConjectureData | None = None,\n        enabled: Sequence[Any] = (),\n        disabled: Sequence[Any] = (),\n        at_least_one_of: Iterable[Hashable] = (),\n    ):\n        self.__data = data\n        self.__is_disabled = {}\n\n        for f in enabled:\n            self.__is_disabled[f] = False\n\n        for f in disabled:\n            self.__is_disabled[f] = True\n\n        # In the original swarm testing paper they turn features on or off\n        # uniformly at random. Instead we decide the probability with which to\n        # enable features up front. This can allow for scenarios where all or\n        # no features are enabled, which are vanishingly unlikely in the\n        # original model.\n        #\n        # We implement this as a single 8-bit integer and enable features which\n        # score >= that value. In particular when self.__baseline is 0, all\n        # features will be enabled. This is so that we shrink in the direction\n        # of more features being enabled.\n        if self.__data is not None:\n            self.__p_disabled = self.__data.draw_integer(0, 254) / 255\n        else:\n            # If data is None we're in example mode so all that matters is the\n            # enabled/disabled lists above. We set this up so that everything\n            # else is enabled by default.\n            self.__p_disabled = 0.0\n\n        # The naive approach can lead to disabling e.g. every single rule on a\n        # RuleBasedStateMachine, which aborts the test as unable to make progress.\n        # Track the set of possible names, and ensure that at least one is enabled.\n        self.__at_least_one_of = set(at_least_one_of)\n\n    def is_enabled(self, name: Any) -> bool:\n        \"\"\"Tests whether the feature named ``name`` should be enabled on this\n        test run.\"\"\"\n        if self.__data is None or self.__data.frozen:\n            # Feature set objects might hang around after data generation has\n            # finished. If this happens then we just report all new features as\n            # enabled, because that's our shrinking direction and they have no\n            # impact on data generation if they weren't used while it was\n            # running.\n            return not self.__is_disabled.get(name, False)\n\n        data = self.__data\n\n        data.start_span(label=FEATURE_LABEL)\n\n        # If we've already decided on this feature then we don't actually\n        # need to draw anything, but we do write the same decision to the\n        # input stream. This allows us to lazily decide whether a feature\n        # is enabled, because it means that if we happen to delete the part\n        # of the test case where we originally decided, the next point at\n        # which we make this decision just makes the decision it previously\n        # made.\n        oneof = self.__at_least_one_of\n        is_disabled = self.__data.draw_boolean(\n            self.__p_disabled,\n            forced=(\n                False\n                if len(oneof) == 1 and name in oneof\n                else self.__is_disabled.get(name)\n            ),\n        )\n        self.__is_disabled[name] = is_disabled\n        if name in oneof and not is_disabled:\n            oneof.clear()\n        oneof.discard(name)\n        data.stop_span()\n        return not is_disabled\n\n    def __repr__(self) -> str:\n        enabled = []\n        disabled = []\n        for name, is_disabled in self.__is_disabled.items():\n            if is_disabled:\n                disabled.append(name)\n            else:\n                enabled.append(name)\n        return f\"FeatureFlags({enabled=}, {disabled=})\"\n\n\nclass FeatureStrategy(SearchStrategy[FeatureFlags]):\n    def __init__(self, at_least_one_of: Iterable[Hashable] = ()):\n        super().__init__()\n        self._at_least_one_of = frozenset(at_least_one_of)\n\n    def do_draw(self, data: ConjectureData) -> FeatureFlags:\n        return FeatureFlags(data, at_least_one_of=self._at_least_one_of)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/flatmapped.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections.abc import Callable\nfrom typing import Generic, TypeVar\n\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.conjecture.utils import (\n    calc_label_from_callable,\n    combine_labels,\n)\nfrom hypothesis.internal.reflection import get_pretty_function_description\nfrom hypothesis.strategies._internal.strategies import (\n    RecurT,\n    SearchStrategy,\n    check_strategy,\n)\n\nMappedFrom = TypeVar(\"MappedFrom\")\nMappedTo = TypeVar(\"MappedTo\")\n\n\nclass FlatMapStrategy(SearchStrategy[MappedTo], Generic[MappedFrom, MappedTo]):\n    def __init__(\n        self,\n        base: SearchStrategy[MappedFrom],\n        expand: Callable[[MappedFrom], SearchStrategy[MappedTo]],\n    ):\n        super().__init__()\n        self.base = base\n        self.expand = expand\n\n    def calc_is_empty(self, recur: RecurT) -> bool:\n        return recur(self.base)\n\n    def calc_label(self) -> int:\n        return combine_labels(\n            self.class_label,\n            self.base.label,\n            calc_label_from_callable(self.expand),\n        )\n\n    def __repr__(self) -> str:\n        if not hasattr(self, \"_cached_repr\"):\n            self._cached_repr = (\n                f\"{self.base!r}.flatmap({get_pretty_function_description(self.expand)})\"\n            )\n        return self._cached_repr\n\n    def do_draw(self, data: ConjectureData) -> MappedTo:\n        base = data.draw(self.base)\n        expanded = self.expand(base)\n        check_strategy(expanded)\n        return data.draw(expanded)\n\n    @property\n    def branches(self) -> list[SearchStrategy[MappedTo]]:\n        return [\n            FlatMapStrategy(strategy, expand=self.expand)\n            for strategy in self.base.branches\n        ]\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/functions.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom weakref import WeakKeyDictionary\n\nfrom hypothesis.control import note, should_note\nfrom hypothesis.errors import InvalidState\nfrom hypothesis.internal.reflection import (\n    convert_positional_arguments,\n    nicerepr,\n    proxies,\n    repr_call,\n)\nfrom hypothesis.strategies._internal.strategies import RecurT, SearchStrategy\n\n\nclass FunctionStrategy(SearchStrategy):\n    def __init__(self, like, returns, pure):\n        super().__init__()\n        self.like = like\n        self.returns = returns\n        self.pure = pure\n        # Using wekrefs-to-generated-functions means that the cache can be\n        # garbage-collected at the end of each example, reducing memory use.\n        self._cache = WeakKeyDictionary()\n\n    def calc_is_empty(self, recur: RecurT) -> bool:\n        return recur(self.returns)\n\n    def do_draw(self, data):\n        @proxies(self.like)\n        def inner(*args, **kwargs):\n            if data.frozen:\n                raise InvalidState(\n                    f\"This generated {nicerepr(self.like)} function can only \"\n                    \"be called within the scope of the @given that created it.\"\n                )\n            if self.pure:\n                args, kwargs = convert_positional_arguments(self.like, args, kwargs)\n                key = (args, frozenset(kwargs.items()))\n                cache = self._cache.setdefault(inner, {})\n                if key not in cache:\n                    cache[key] = data.draw(self.returns)\n                    if should_note():  # optimization to avoid needless repr_call\n                        rep = repr_call(self.like, args, kwargs, reorder=False)\n                        note(f\"Called function: {rep} -> {cache[key]!r}\")\n                return cache[key]\n            else:\n                val = data.draw(self.returns)\n                if should_note():\n                    rep = repr_call(self.like, args, kwargs, reorder=False)\n                    note(f\"Called function: {rep} -> {val!r}\")\n                return val\n\n        return inner\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/ipaddress.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom ipaddress import IPv4Address, IPv4Network, IPv6Address, IPv6Network, ip_network\nfrom typing import Literal\n\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.validation import check_type\nfrom hypothesis.strategies._internal.core import binary, sampled_from\nfrom hypothesis.strategies._internal.numbers import integers\nfrom hypothesis.strategies._internal.strategies import SearchStrategy\nfrom hypothesis.strategies._internal.utils import defines_strategy\n\n# See https://www.iana.org/assignments/iana-ipv4-special-registry/\nSPECIAL_IPv4_RANGES = (\n    \"0.0.0.0/8\",\n    \"10.0.0.0/8\",\n    \"100.64.0.0/10\",\n    \"127.0.0.0/8\",\n    \"169.254.0.0/16\",\n    \"172.16.0.0/12\",\n    \"192.0.0.0/24\",\n    \"192.0.0.0/29\",\n    \"192.0.0.8/32\",\n    \"192.0.0.9/32\",\n    \"192.0.0.10/32\",\n    \"192.0.0.170/32\",\n    \"192.0.0.171/32\",\n    \"192.0.2.0/24\",\n    \"192.31.196.0/24\",\n    \"192.52.193.0/24\",\n    \"192.88.99.0/24\",\n    \"192.168.0.0/16\",\n    \"192.175.48.0/24\",\n    \"198.18.0.0/15\",\n    \"198.51.100.0/24\",\n    \"203.0.113.0/24\",\n    \"240.0.0.0/4\",\n    \"255.255.255.255/32\",\n)\n# and https://www.iana.org/assignments/iana-ipv6-special-registry/\nSPECIAL_IPv6_RANGES = (\n    \"::1/128\",\n    \"::/128\",\n    \"::ffff:0:0/96\",\n    \"64:ff9b::/96\",\n    \"64:ff9b:1::/48\",\n    \"100::/64\",\n    \"2001::/23\",\n    \"2001::/32\",\n    \"2001:1::1/128\",\n    \"2001:1::2/128\",\n    \"2001:2::/48\",\n    \"2001:3::/32\",\n    \"2001:4:112::/48\",\n    \"2001:10::/28\",\n    \"2001:20::/28\",\n    \"2001:db8::/32\",\n    \"2002::/16\",\n    \"2620:4f:8000::/48\",\n    \"fc00::/7\",\n    \"fe80::/10\",\n)\n\n\n@defines_strategy(force_reusable_values=True)\ndef ip_addresses(\n    *,\n    v: Literal[4, 6] | None = None,\n    network: str | IPv4Network | IPv6Network | None = None,\n) -> SearchStrategy[IPv4Address | IPv6Address]:\n    r\"\"\"Generate IP addresses - ``v=4`` for :class:`~python:ipaddress.IPv4Address`\\ es,\n    ``v=6`` for :class:`~python:ipaddress.IPv6Address`\\ es, or leave unspecified\n    to allow both versions.\n\n    ``network`` may be an :class:`~python:ipaddress.IPv4Network` or\n    :class:`~python:ipaddress.IPv6Network`, or a string representing a network such as\n    ``\"127.0.0.0/24\"`` or ``\"2001:db8::/32\"``.  As well as generating addresses within\n    a particular routable network, this can be used to generate addresses from a\n    reserved range listed in the\n    `IANA <https://www.iana.org/assignments/iana-ipv4-special-registry/>`__\n    `registries <https://www.iana.org/assignments/iana-ipv6-special-registry/>`__.\n\n    If you pass both ``v`` and ``network``, they must be for the same version.\n    \"\"\"\n    if v is not None:\n        check_type(int, v, \"v\")\n        if v not in (4, 6):\n            raise InvalidArgument(f\"{v=}, but only v=4 or v=6 are valid\")\n    if network is None:\n        # We use the reserved-address registries to boost the chance\n        # of generating one of the various special types of address.\n        four = binary(min_size=4, max_size=4).map(IPv4Address) | sampled_from(\n            SPECIAL_IPv4_RANGES\n        ).flatmap(lambda network: ip_addresses(network=network))\n        six = binary(min_size=16, max_size=16).map(IPv6Address) | sampled_from(\n            SPECIAL_IPv6_RANGES\n        ).flatmap(lambda network: ip_addresses(network=network))\n        if v == 4:\n            return four\n        if v == 6:\n            return six\n        return four | six\n    if isinstance(network, str):\n        network = ip_network(network)\n    check_type((IPv4Network, IPv6Network), network, \"network\")\n    assert isinstance(network, (IPv4Network, IPv6Network))  # for Mypy\n    if v not in (None, network.version):\n        raise InvalidArgument(f\"{v=} is incompatible with {network=}\")\n    addr_type = IPv4Address if network.version == 4 else IPv6Address\n    return integers(int(network[0]), int(network[-1])).map(addr_type)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/lazy.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections.abc import Callable, Sequence\nfrom inspect import signature\nfrom typing import Any\nfrom weakref import WeakKeyDictionary\n\nfrom hypothesis.configuration import check_sideeffect_during_initialization\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.reflection import (\n    convert_keyword_arguments,\n    convert_positional_arguments,\n    get_pretty_function_description,\n    repr_call,\n)\nfrom hypothesis.strategies._internal.deferred import DeferredStrategy\nfrom hypothesis.strategies._internal.strategies import Ex, RecurT, SearchStrategy\nfrom hypothesis.utils.threading import ThreadLocal\n\nthreadlocal = ThreadLocal(unwrap_depth=int, unwrap_cache=WeakKeyDictionary)\n\n\ndef unwrap_strategies(s):\n    # optimization\n    if not isinstance(s, (LazyStrategy, DeferredStrategy)):\n        return s\n\n    try:\n        return threadlocal.unwrap_cache[s]\n    except KeyError:\n        pass\n\n    threadlocal.unwrap_cache[s] = s\n    threadlocal.unwrap_depth += 1\n\n    try:\n        result = unwrap_strategies(s.wrapped_strategy)\n        threadlocal.unwrap_cache[s] = result\n\n        try:\n            assert result.force_has_reusable_values == s.force_has_reusable_values\n        except AttributeError:\n            pass\n\n        try:\n            result.force_has_reusable_values = s.force_has_reusable_values\n        except AttributeError:\n            pass\n\n        return result\n    finally:\n        threadlocal.unwrap_depth -= 1\n        if threadlocal.unwrap_depth <= 0:\n            threadlocal.unwrap_cache.clear()\n        assert threadlocal.unwrap_depth >= 0\n\n\nclass LazyStrategy(SearchStrategy[Ex]):\n    \"\"\"A strategy which is defined purely by conversion to and from another\n    strategy.\n\n    Its parameter and distribution come from that other strategy.\n    \"\"\"\n\n    def __init__(\n        self,\n        function: Callable[..., SearchStrategy[Ex]],\n        args: Sequence[object],\n        kwargs: dict[str, object],\n        *,\n        transforms: tuple[tuple[str, Callable[..., Any]], ...] = (),\n        force_repr: str | None = None,\n    ):\n        super().__init__()\n        self.__wrapped_strategy: SearchStrategy[Ex] | None = None\n        self.__representation: str | None = force_repr\n        self.function = function\n        self.__args = args\n        self.__kwargs = kwargs\n        self._transformations = transforms\n\n    def calc_is_empty(self, recur: RecurT) -> bool:\n        return recur(self.wrapped_strategy)\n\n    def calc_has_reusable_values(self, recur: RecurT) -> bool:\n        return recur(self.wrapped_strategy)\n\n    def calc_is_cacheable(self, recur: RecurT) -> bool:\n        for source in (self.__args, self.__kwargs.values()):\n            for v in source:\n                if isinstance(v, SearchStrategy) and not v.is_cacheable:\n                    return False\n        return True\n\n    def calc_label(self) -> int:\n        return self.wrapped_strategy.label\n\n    @property\n    def wrapped_strategy(self) -> SearchStrategy[Ex]:\n        if self.__wrapped_strategy is None:\n            check_sideeffect_during_initialization(\"lazy evaluation of {!r}\", self)\n\n            unwrapped_args = tuple(unwrap_strategies(s) for s in self.__args)\n            unwrapped_kwargs = {\n                k: unwrap_strategies(v) for k, v in self.__kwargs.items()\n            }\n\n            base = self.function(*self.__args, **self.__kwargs)\n            if unwrapped_args == self.__args and unwrapped_kwargs == self.__kwargs:\n                _wrapped_strategy = base\n            else:\n                _wrapped_strategy = self.function(*unwrapped_args, **unwrapped_kwargs)\n            for method, fn in self._transformations:\n                _wrapped_strategy = getattr(_wrapped_strategy, method)(fn)\n            self.__wrapped_strategy = _wrapped_strategy\n        assert self.__wrapped_strategy is not None\n        return self.__wrapped_strategy\n\n    def __with_transform(self, method, fn):\n        repr_ = self.__representation\n        if repr_:\n            repr_ = f\"{repr_}.{method}({get_pretty_function_description(fn)})\"\n        return LazyStrategy(\n            self.function,\n            self.__args,\n            self.__kwargs,\n            transforms=(*self._transformations, (method, fn)),\n            force_repr=repr_,\n        )\n\n    def map(self, pack):\n        return self.__with_transform(\"map\", pack)\n\n    def filter(self, condition):\n        return self.__with_transform(\"filter\", condition)\n\n    def do_validate(self) -> None:\n        w = self.wrapped_strategy\n        assert isinstance(w, SearchStrategy), f\"{self!r} returned non-strategy {w!r}\"\n        w.validate()\n\n    def __repr__(self) -> str:\n        if self.__representation is None:\n            sig = signature(self.function)\n            pos = [p for p in sig.parameters.values() if \"POSITIONAL\" in p.kind.name]\n            if len(pos) > 1 or any(p.default is not sig.empty for p in pos):\n                _args, _kwargs = convert_positional_arguments(\n                    self.function, self.__args, self.__kwargs\n                )\n            else:\n                _args, _kwargs = convert_keyword_arguments(\n                    self.function, self.__args, self.__kwargs\n                )\n            kwargs_for_repr = {\n                k: v\n                for k, v in _kwargs.items()\n                if k not in sig.parameters or v is not sig.parameters[k].default\n            }\n            self.__representation = repr_call(\n                self.function, _args, kwargs_for_repr, reorder=False\n            ) + \"\".join(\n                f\".{method}({get_pretty_function_description(fn)})\"\n                for method, fn in self._transformations\n            )\n        return self.__representation\n\n    def do_draw(self, data: ConjectureData) -> Ex:\n        return data.draw(self.wrapped_strategy)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/misc.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections.abc import Callable\nfrom typing import TYPE_CHECKING, Any, NoReturn\n\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.reflection import get_pretty_function_description\nfrom hypothesis.strategies._internal.strategies import (\n    Ex,\n    RecurT,\n    SampledFromStrategy,\n    SearchStrategy,\n    T,\n    is_hashable,\n)\nfrom hypothesis.strategies._internal.utils import cacheable, defines_strategy\nfrom hypothesis.utils.conventions import UniqueIdentifier\n\nif TYPE_CHECKING:\n    from typing_extensions import Never\n\n\nclass JustStrategy(SampledFromStrategy[Ex]):\n    \"\"\"A strategy which always returns a single fixed value.\n\n    It's implemented as a length-one SampledFromStrategy so that all our\n    special-case logic for filtering and sets applies also to just(x).\n\n    The important difference from a SampledFromStrategy with only one\n    element to choose is that JustStrategy *never* touches the underlying\n    choice sequence, i.e. drawing neither reads from nor writes to `data`.\n    This is a reasonably important optimisation (or semantic distinction!)\n    for both JustStrategy and SampledFromStrategy.\n    \"\"\"\n\n    @property\n    def value(self) -> Ex:\n        return self.elements[0]\n\n    def __repr__(self) -> str:\n        suffix = \"\".join(\n            f\".{name}({get_pretty_function_description(f)})\"\n            for name, f in self._transformations\n        )\n        if self.value is None:\n            return \"none()\" + suffix\n        return f\"just({get_pretty_function_description(self.value)}){suffix}\"\n\n    def calc_is_cacheable(self, recur: RecurT) -> bool:\n        return is_hashable(self.value)\n\n    def do_filtered_draw(self, data: ConjectureData) -> Ex | UniqueIdentifier:\n        # The parent class's `do_draw` implementation delegates directly to\n        # `do_filtered_draw`, which we can greatly simplify in this case since\n        # we have exactly one value. (This also avoids drawing any data.)\n        return self._transform(self.value)\n\n\n@defines_strategy(eager=True)\ndef just(value: T) -> SearchStrategy[T]:\n    \"\"\"Return a strategy which only generates ``value``.\n\n    Note: ``value`` is not copied. Be wary of using mutable values.\n\n    If ``value`` is the result of a callable, you can use\n    :func:`builds(callable) <hypothesis.strategies.builds>` instead\n    of ``just(callable())`` to get a fresh value each time.\n\n    Examples from this strategy do not shrink (because there is only one).\n    \"\"\"\n    return JustStrategy([value])\n\n\n@defines_strategy(force_reusable_values=True)\ndef none() -> SearchStrategy[None]:\n    \"\"\"Return a strategy which only generates None.\n\n    Examples from this strategy do not shrink (because there is only\n    one).\n    \"\"\"\n    return just(None)\n\n\nclass Nothing(SearchStrategy[\"Never\"]):\n    def calc_is_empty(self, recur: RecurT) -> bool:\n        return True\n\n    def do_draw(self, data: ConjectureData) -> NoReturn:\n        # This method should never be called because draw() will mark the\n        # data as invalid immediately because is_empty is True.\n        raise NotImplementedError(\"This should never happen\")\n\n    def calc_has_reusable_values(self, recur: RecurT) -> bool:\n        return True\n\n    def __repr__(self) -> str:\n        return \"nothing()\"\n\n    def map(self, pack: Callable[[Any], Any]) -> SearchStrategy[\"Never\"]:\n        return self\n\n    def filter(self, condition: Callable[[Any], Any]) -> \"SearchStrategy[Never]\":\n        return self\n\n    def flatmap(\n        self, expand: Callable[[Any], \"SearchStrategy[Any]\"]\n    ) -> \"SearchStrategy[Never]\":\n        return self\n\n\nNOTHING = Nothing()\n\n\n@cacheable\n@defines_strategy(eager=True)\ndef nothing() -> SearchStrategy[\"Never\"]:\n    \"\"\"This strategy never successfully draws a value and will always reject on\n    an attempt to draw.\n\n    Examples from this strategy do not shrink (because there are none).\n    \"\"\"\n    return NOTHING\n\n\nclass BooleansStrategy(SearchStrategy[bool]):\n    def do_draw(self, data: ConjectureData) -> bool:\n        return data.draw_boolean()\n\n    def __repr__(self) -> str:\n        return \"booleans()\"\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/numbers.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nfrom decimal import Decimal\nfrom fractions import Fraction\nfrom typing import Literal, cast\n\nfrom hypothesis.control import reject\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.filtering import (\n    get_float_predicate_bounds,\n    get_integer_predicate_bounds,\n)\nfrom hypothesis.internal.floats import (\n    SMALLEST_SUBNORMAL,\n    float_of,\n    float_to_int,\n    int_to_float,\n    is_negative,\n    next_down,\n    next_down_normal,\n    next_up,\n    next_up_normal,\n    width_smallest_normals,\n)\nfrom hypothesis.internal.validation import (\n    check_type,\n    check_valid_bound,\n    check_valid_interval,\n)\nfrom hypothesis.strategies._internal.misc import nothing\nfrom hypothesis.strategies._internal.strategies import (\n    SampledFromStrategy,\n    SearchStrategy,\n)\nfrom hypothesis.strategies._internal.utils import cacheable, defines_strategy\n\n# See https://github.com/python/mypy/issues/3186 - numbers.Real is wrong!\nReal = int | float | Fraction | Decimal\n\n\nclass IntegersStrategy(SearchStrategy[int]):\n    def __init__(self, start: int | None, end: int | None) -> None:\n        super().__init__()\n        assert isinstance(start, int) or start is None\n        assert isinstance(end, int) or end is None\n        assert start is None or end is None or start <= end\n        self.start = start\n        self.end = end\n\n    def __repr__(self) -> str:\n        if self.start is None and self.end is None:\n            return \"integers()\"\n        if self.end is None:\n            return f\"integers(min_value={self.start})\"\n        if self.start is None:\n            return f\"integers(max_value={self.end})\"\n        return f\"integers({self.start}, {self.end})\"\n\n    def do_draw(self, data: ConjectureData) -> int:\n        # For bounded integers, make the bounds and near-bounds more likely.\n        weights = None\n        if (\n            self.end is not None\n            and self.start is not None\n            and self.end - self.start > 127\n        ):\n            weights = {\n                self.start: (2 / 128),\n                self.start + 1: (1 / 128),\n                self.end - 1: (1 / 128),\n                self.end: (2 / 128),\n            }\n\n        return data.draw_integer(\n            min_value=self.start, max_value=self.end, weights=weights\n        )\n\n    def filter(self, condition):\n        if condition is math.isfinite:\n            return self\n        if condition in [math.isinf, math.isnan]:\n            return nothing()\n        constraints, pred = get_integer_predicate_bounds(condition)\n\n        start, end = self.start, self.end\n        if \"min_value\" in constraints:\n            start = max(constraints[\"min_value\"], -math.inf if start is None else start)\n        if \"max_value\" in constraints:\n            end = min(constraints[\"max_value\"], math.inf if end is None else end)\n\n        if start != self.start or end != self.end:\n            if start is not None and end is not None and start > end:\n                return nothing()\n            self = type(self)(start, end)\n        if pred is None:\n            return self\n        return super().filter(pred)\n\n\n@cacheable\n@defines_strategy(force_reusable_values=True)\ndef integers(\n    min_value: int | None = None,\n    max_value: int | None = None,\n) -> SearchStrategy[int]:\n    \"\"\"Returns a strategy which generates integers.\n\n    If min_value is not None then all values will be >= min_value. If\n    max_value is not None then all values will be <= max_value\n\n    Examples from this strategy will shrink towards zero, and negative values\n    will also shrink towards positive (i.e. -n may be replaced by +n).\n    \"\"\"\n    check_valid_bound(min_value, \"min_value\")\n    check_valid_bound(max_value, \"max_value\")\n    check_valid_interval(min_value, max_value, \"min_value\", \"max_value\")\n\n    if min_value is not None:\n        if min_value != int(min_value):\n            raise InvalidArgument(\n                f\"min_value={min_value!r} of type {type(min_value)!r} \"\n                \"cannot be exactly represented as an integer.\"\n            )\n        min_value = int(min_value)\n    if max_value is not None:\n        if max_value != int(max_value):\n            raise InvalidArgument(\n                f\"max_value={max_value!r} of type {type(max_value)!r} \"\n                \"cannot be exactly represented as an integer.\"\n            )\n        max_value = int(max_value)\n\n    return IntegersStrategy(min_value, max_value)\n\n\nclass FloatStrategy(SearchStrategy[float]):\n    \"\"\"A strategy for floating point numbers.\"\"\"\n\n    def __init__(\n        self,\n        *,\n        min_value: float,\n        max_value: float,\n        allow_nan: bool,\n        # The smallest nonzero number we can represent is usually a subnormal, but may\n        # be the smallest normal if we're running in unsafe denormals-are-zero mode.\n        # While that's usually an explicit error, we do need to handle the case where\n        # the user passes allow_subnormal=False.\n        smallest_nonzero_magnitude: float = SMALLEST_SUBNORMAL,\n    ):\n        super().__init__()\n        assert isinstance(allow_nan, bool)\n        assert smallest_nonzero_magnitude >= 0.0, \"programmer error if this is negative\"\n        if smallest_nonzero_magnitude == 0.0:  # pragma: no cover\n            raise FloatingPointError(\n                \"Got allow_subnormal=True, but we can't represent subnormal floats \"\n                \"right now, in violation of the IEEE-754 floating-point \"\n                \"specification.  This is usually because something was compiled with \"\n                \"-ffast-math or a similar option, which sets global processor state.  \"\n                \"See https://simonbyrne.github.io/notes/fastmath/ for a more detailed \"\n                \"writeup - and good luck!\"\n            )\n        self.min_value = min_value\n        self.max_value = max_value\n        self.allow_nan = allow_nan\n        self.smallest_nonzero_magnitude = smallest_nonzero_magnitude\n\n    def __repr__(self) -> str:\n        return (\n            f\"{self.__class__.__name__}({self.min_value=}, {self.max_value=}, \"\n            f\"{self.allow_nan=}, {self.smallest_nonzero_magnitude=})\"\n        ).replace(\"self.\", \"\")\n\n    def do_draw(self, data: ConjectureData) -> float:\n        return data.draw_float(\n            min_value=self.min_value,\n            max_value=self.max_value,\n            allow_nan=self.allow_nan,\n            smallest_nonzero_magnitude=self.smallest_nonzero_magnitude,\n        )\n\n    def filter(self, condition):\n        # Handle a few specific weird cases.\n        if condition is math.isfinite:\n            return FloatStrategy(\n                min_value=max(self.min_value, next_up(float(\"-inf\"))),\n                max_value=min(self.max_value, next_down(float(\"inf\"))),\n                allow_nan=False,\n                smallest_nonzero_magnitude=self.smallest_nonzero_magnitude,\n            )\n        if condition is math.isinf:\n            if permitted_infs := [\n                x\n                for x in (-math.inf, math.inf)\n                if self.min_value <= x <= self.max_value\n            ]:\n                return SampledFromStrategy(permitted_infs)\n            return nothing()\n        if condition is math.isnan:\n            if not self.allow_nan:\n                return nothing()\n            return NanStrategy()\n\n        constraints, pred = get_float_predicate_bounds(condition)\n        if not constraints:\n            return super().filter(pred)\n        min_bound = max(constraints.get(\"min_value\", -math.inf), self.min_value)\n        max_bound = min(constraints.get(\"max_value\", math.inf), self.max_value)\n\n        # Adjustments for allow_subnormal=False, if any need to be made\n        if -self.smallest_nonzero_magnitude < min_bound < 0:\n            min_bound = -0.0\n        elif 0 < min_bound < self.smallest_nonzero_magnitude:\n            min_bound = self.smallest_nonzero_magnitude\n        if -self.smallest_nonzero_magnitude < max_bound < 0:\n            max_bound = -self.smallest_nonzero_magnitude\n        elif 0 < max_bound < self.smallest_nonzero_magnitude:\n            max_bound = 0.0\n\n        if min_bound > max_bound:\n            return nothing()\n        if (\n            min_bound > self.min_value\n            or self.max_value > max_bound\n            or (self.allow_nan and (-math.inf < min_bound or max_bound < math.inf))\n        ):\n            self = type(self)(\n                min_value=min_bound,\n                max_value=max_bound,\n                allow_nan=False,\n                smallest_nonzero_magnitude=self.smallest_nonzero_magnitude,\n            )\n        if pred is None:\n            return self\n        return super().filter(pred)\n\n\n@cacheable\n@defines_strategy(force_reusable_values=True)\ndef floats(\n    min_value: Real | None = None,\n    max_value: Real | None = None,\n    *,\n    allow_nan: bool | None = None,\n    allow_infinity: bool | None = None,\n    allow_subnormal: bool | None = None,\n    width: Literal[16, 32, 64] = 64,\n    exclude_min: bool = False,\n    exclude_max: bool = False,\n) -> SearchStrategy[float]:\n    \"\"\"Returns a strategy which generates floats.\n\n    - If min_value is not None, all values will be ``>= min_value``\n      (or ``> min_value`` if ``exclude_min``).\n    - If max_value is not None, all values will be ``<= max_value``\n      (or ``< max_value`` if ``exclude_max``).\n    - If min_value or max_value is not None, it is an error to enable\n      allow_nan.\n    - If both min_value and max_value are not None, it is an error to enable\n      allow_infinity.\n    - If inferred values range does not include subnormal values, it is an error\n      to enable allow_subnormal.\n\n    Where not explicitly ruled out by the bounds,\n    :wikipedia:`subnormals <Subnormal_number>`, infinities, and NaNs are possible\n    values generated by this strategy.\n\n    The width argument specifies the maximum number of bits of precision\n    required to represent the generated float. Valid values are 16, 32, or 64.\n    Passing ``width=32`` will still use the builtin 64-bit :class:`~python:float` class,\n    but always for values which can be exactly represented as a 32-bit float.\n\n    The exclude_min and exclude_max argument can be used to generate numbers\n    from open or half-open intervals, by excluding the respective endpoints.\n    Excluding either signed zero will also exclude the other.\n    Attempting to exclude an endpoint which is None will raise an error;\n    use ``allow_infinity=False`` to generate finite floats.  You can however\n    use e.g. ``min_value=-math.inf, exclude_min=True`` to exclude only\n    one infinite endpoint.\n\n    Examples from this strategy have a complicated and hard to explain\n    shrinking behaviour, but it tries to improve \"human readability\". Finite\n    numbers will be preferred to infinity and infinity will be preferred to\n    NaN.\n    \"\"\"\n    check_type(bool, exclude_min, \"exclude_min\")\n    check_type(bool, exclude_max, \"exclude_max\")\n\n    if allow_nan is None:\n        allow_nan = bool(min_value is None and max_value is None)\n    elif allow_nan and (min_value is not None or max_value is not None):\n        raise InvalidArgument(f\"Cannot have {allow_nan=}, with min_value or max_value\")\n\n    if width not in (16, 32, 64):\n        raise InvalidArgument(\n            f\"Got {width=}, but the only valid values \"\n            \"are the integers 16, 32, and 64.\"\n        )\n    # Literal[16] accepts both 16 and 16.0. Normalize to the int 16 here, mainly\n    # for mypyc. We want to support width=16.0 to make e.g. width=mywidth / 2 for\n    # mywidth=32 easy.\n    width = cast(Literal[16, 32, 64], int(width))\n\n    check_valid_bound(min_value, \"min_value\")\n    check_valid_bound(max_value, \"max_value\")\n\n    if math.copysign(1.0, -0.0) == 1.0:  # pragma: no cover\n        raise FloatingPointError(\n            \"Your Python install can't represent -0.0, which is required by the \"\n            \"IEEE-754 floating-point specification.  This is probably because it was \"\n            \"compiled with an unsafe option like -ffast-math; for a more detailed \"\n            \"explanation see https://simonbyrne.github.io/notes/fastmath/\"\n        )\n    if allow_subnormal and next_up(0.0, width=width) == 0:  # pragma: no cover\n        # Not worth having separate CI envs and dependencies just to cover this branch;\n        # discussion in https://github.com/HypothesisWorks/hypothesis/issues/3092\n        #\n        # Erroring out here ensures that the database contents are interpreted\n        # consistently - which matters for such a foundational strategy, even if it's\n        # not always true for all user-composed strategies further up the stack.\n        from _hypothesis_ftz_detector import identify_ftz_culprits\n\n        try:\n            ftz_pkg = identify_ftz_culprits()\n        except Exception:\n            ftz_pkg = None\n        if ftz_pkg:\n            ftz_msg = (\n                f\"This seems to be because the `{ftz_pkg}` package was compiled with \"\n                f\"-ffast-math or a similar option, which sets global processor state \"\n                f\"- see https://simonbyrne.github.io/notes/fastmath/ for details.  \"\n                f\"If you don't know why {ftz_pkg} is installed, `pipdeptree -rp \"\n                f\"{ftz_pkg}` will show which packages depend on it.\"\n            )\n        else:\n            ftz_msg = (\n                \"This is usually because something was compiled with -ffast-math \"\n                \"or a similar option, which sets global processor state.  See \"\n                \"https://simonbyrne.github.io/notes/fastmath/ for a more detailed \"\n                \"writeup - and good luck!\"\n            )\n        raise FloatingPointError(\n            f\"Got {allow_subnormal=}, but we can't represent \"\n            f\"subnormal floats right now, in violation of the IEEE-754 floating-point \"\n            f\"specification.  {ftz_msg}\"\n        )\n\n    min_arg, max_arg = min_value, max_value\n    if min_value is not None:\n        min_value = float_of(min_value, width)\n        assert isinstance(min_value, float)\n    if max_value is not None:\n        max_value = float_of(max_value, width)\n        assert isinstance(max_value, float)\n\n    if min_value != min_arg:\n        raise InvalidArgument(\n            f\"min_value={min_arg!r} cannot be exactly represented as a float \"\n            f\"of width {width} - use {min_value=} instead.\"\n        )\n    if max_value != max_arg:\n        raise InvalidArgument(\n            f\"max_value={max_arg!r} cannot be exactly represented as a float \"\n            f\"of width {width} - use {max_value=} instead.\"\n        )\n\n    if exclude_min and (min_value is None or min_value == math.inf):\n        raise InvalidArgument(f\"Cannot exclude {min_value=}\")\n    if exclude_max and (max_value is None or max_value == -math.inf):\n        raise InvalidArgument(f\"Cannot exclude {max_value=}\")\n\n    assumed_allow_subnormal = allow_subnormal is None or allow_subnormal\n    if min_value is not None and (\n        exclude_min or (min_arg is not None and min_value < min_arg)\n    ):\n        min_value = next_up_normal(\n            min_value, width, allow_subnormal=assumed_allow_subnormal\n        )\n        if min_value == min_arg:\n            assert min_value == min_arg == 0\n            assert is_negative(min_arg)\n            assert not is_negative(min_value)\n            min_value = next_up_normal(\n                min_value, width, allow_subnormal=assumed_allow_subnormal\n            )\n        assert min_value > min_arg  # type: ignore\n    if max_value is not None and (\n        exclude_max or (max_arg is not None and max_value > max_arg)\n    ):\n        max_value = next_down_normal(\n            max_value, width, allow_subnormal=assumed_allow_subnormal\n        )\n        if max_value == max_arg:\n            assert max_value == max_arg == 0\n            assert is_negative(max_value)\n            assert not is_negative(max_arg)\n            max_value = next_down_normal(\n                max_value, width, allow_subnormal=assumed_allow_subnormal\n            )\n        assert max_value < max_arg  # type: ignore\n\n    if min_value == -math.inf:\n        min_value = None\n    if max_value == math.inf:\n        max_value = None\n\n    bad_zero_bounds = (\n        min_value == max_value == 0\n        and is_negative(max_value)\n        and not is_negative(min_value)\n    )\n    if (\n        min_value is not None\n        and max_value is not None\n        and (min_value > max_value or bad_zero_bounds)\n    ):\n        # This is a custom alternative to check_valid_interval, because we want\n        # to include the bit-width and exclusion information in the message.\n        msg = (\n            f\"There are no {width}-bit floating-point values between \"\n            f\"min_value={min_arg!r} and max_value={max_arg!r}\"\n        )\n        if exclude_min or exclude_max:\n            msg += f\", {exclude_min=} and {exclude_max=}\"\n        raise InvalidArgument(msg)\n\n    if allow_infinity is None:\n        allow_infinity = bool(min_value is None or max_value is None)\n    elif allow_infinity:\n        if min_value is not None and max_value is not None:\n            raise InvalidArgument(\n                f\"Cannot have {allow_infinity=}, with both min_value and max_value\"\n            )\n    elif min_value == math.inf:\n        if min_arg == math.inf:\n            raise InvalidArgument(\"allow_infinity=False excludes min_value=inf\")\n        raise InvalidArgument(\n            f\"exclude_min=True turns min_value={min_arg!r} into inf, \"\n            \"but allow_infinity=False\"\n        )\n    elif max_value == -math.inf:\n        if max_arg == -math.inf:\n            raise InvalidArgument(\"allow_infinity=False excludes max_value=-inf\")\n        raise InvalidArgument(\n            f\"exclude_max=True turns max_value={max_arg!r} into -inf, \"\n            \"but allow_infinity=False\"\n        )\n\n    smallest_normal = width_smallest_normals[width]\n    if allow_subnormal is None:\n        if min_value is not None and max_value is not None:\n            if min_value == max_value:\n                allow_subnormal = -smallest_normal < min_value < smallest_normal\n            else:\n                allow_subnormal = (\n                    min_value < smallest_normal and max_value > -smallest_normal\n                )\n        elif min_value is not None:\n            allow_subnormal = min_value < smallest_normal\n        elif max_value is not None:\n            allow_subnormal = max_value > -smallest_normal\n        else:\n            allow_subnormal = True\n    if allow_subnormal:\n        if min_value is not None and min_value >= smallest_normal:\n            raise InvalidArgument(\n                f\"allow_subnormal=True, but minimum value {min_value} \"\n                f\"excludes values below float{width}'s \"\n                f\"smallest positive normal {smallest_normal}\"\n            )\n        if max_value is not None and max_value <= -smallest_normal:\n            raise InvalidArgument(\n                f\"allow_subnormal=True, but maximum value {max_value} \"\n                f\"excludes values above float{width}'s \"\n                f\"smallest negative normal {-smallest_normal}\"\n            )\n\n    if min_value is None:\n        min_value = float(\"-inf\")\n    if max_value is None:\n        max_value = float(\"inf\")\n    if not allow_infinity:\n        min_value = max(min_value, next_up(float(\"-inf\")))\n        max_value = min(max_value, next_down(float(\"inf\")))\n    assert isinstance(min_value, float)\n    assert isinstance(max_value, float)\n    smallest_nonzero_magnitude = (\n        SMALLEST_SUBNORMAL if allow_subnormal else smallest_normal\n    )\n    result: SearchStrategy = FloatStrategy(\n        min_value=min_value,\n        max_value=max_value,\n        allow_nan=allow_nan,\n        smallest_nonzero_magnitude=smallest_nonzero_magnitude,\n    )\n\n    if width < 64:\n\n        def downcast(x: float) -> float:\n            try:\n                return float_of(x, width)\n            except OverflowError:  # pragma: no cover\n                reject()\n\n        result = result.map(downcast)\n    return result\n\n\nclass NanStrategy(SearchStrategy[float]):\n    \"\"\"Strategy for sampling the space of nan float values.\"\"\"\n\n    def do_draw(self, data: ConjectureData) -> float:\n        # Nans must have all exponent bits and the first mantissa bit set, so\n        # we generate by taking 64 random bits and setting the required ones.\n        sign_bit = int(data.draw_boolean()) << 63\n        nan_bits = float_to_int(math.nan)\n        mantissa_bits = data.draw_integer(0, 2**52 - 1)\n        return int_to_float(sign_bit | nan_bits | mantissa_bits)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/random.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport abc\nimport inspect\nimport math\nfrom dataclasses import dataclass, field\nfrom random import Random\nfrom typing import Any\n\nfrom hypothesis.control import should_note\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.reflection import define_function_signature\nfrom hypothesis.reporting import report\nfrom hypothesis.strategies._internal.core import lists, permutations, sampled_from\nfrom hypothesis.strategies._internal.numbers import floats, integers\nfrom hypothesis.strategies._internal.strategies import SearchStrategy\n\n\nclass HypothesisRandom(Random, abc.ABC):\n    \"\"\"A subclass of Random designed to expose the seed it was initially\n    provided with.\"\"\"\n\n    def __init__(self, *, note_method_calls: bool) -> None:\n        self._note_method_calls = note_method_calls\n\n    def __deepcopy__(self, table):\n        return self.__copy__()\n\n    @abc.abstractmethod\n    def seed(self, seed):\n        raise NotImplementedError\n\n    @abc.abstractmethod\n    def getstate(self):\n        raise NotImplementedError\n\n    @abc.abstractmethod\n    def setstate(self, state):\n        raise NotImplementedError\n\n    @abc.abstractmethod\n    def _hypothesis_do_random(self, method, kwargs):\n        raise NotImplementedError\n\n    def _hypothesis_log_random(self, method, kwargs, result):\n        if not (self._note_method_calls and should_note()):\n            return\n\n        args, kwargs = convert_kwargs(method, kwargs)\n        argstr = \", \".join(\n            list(map(repr, args)) + [f\"{k}={v!r}\" for k, v in kwargs.items()]\n        )\n        report(f\"{self!r}.{method}({argstr}) -> {result!r}\")\n\n\nRANDOM_METHODS = [\n    name\n    for name in [\n        \"_randbelow\",\n        \"betavariate\",\n        \"binomialvariate\",\n        \"choice\",\n        \"choices\",\n        \"expovariate\",\n        \"gammavariate\",\n        \"gauss\",\n        \"getrandbits\",\n        \"lognormvariate\",\n        \"normalvariate\",\n        \"paretovariate\",\n        \"randint\",\n        \"random\",\n        \"randrange\",\n        \"sample\",\n        \"shuffle\",\n        \"triangular\",\n        \"uniform\",\n        \"vonmisesvariate\",\n        \"weibullvariate\",\n        \"randbytes\",\n    ]\n    if hasattr(Random, name)\n]\n\n\n# Fake shims to get a good signature\ndef getrandbits(self, n: int) -> int:  # type: ignore\n    raise NotImplementedError\n\n\ndef random(self) -> float:  # type: ignore\n    raise NotImplementedError\n\n\ndef _randbelow(self, n: int) -> int:  # type: ignore\n    raise NotImplementedError\n\n\nSTUBS = {f.__name__: f for f in [getrandbits, random, _randbelow]}\n\n\nSIGNATURES: dict[str, inspect.Signature] = {}\n\n\ndef sig_of(name):\n    try:\n        return SIGNATURES[name]\n    except KeyError:\n        pass\n\n    target = getattr(Random, name)\n    result = inspect.signature(STUBS.get(name, target))\n    SIGNATURES[name] = result\n    return result\n\n\ndef define_copy_method(name):\n    target = getattr(Random, name)\n\n    def implementation(self, **kwargs):\n        result = self._hypothesis_do_random(name, kwargs)\n        self._hypothesis_log_random(name, kwargs, result)\n        return result\n\n    sig = inspect.signature(STUBS.get(name, target))\n\n    result = define_function_signature(target.__name__, target.__doc__, sig)(\n        implementation\n    )\n\n    result.__module__ = __name__\n    result.__qualname__ = \"HypothesisRandom.\" + result.__name__\n\n    setattr(HypothesisRandom, name, result)\n\n\nfor r in RANDOM_METHODS:\n    define_copy_method(r)\n\n\n@dataclass(slots=True, frozen=False)\nclass RandomState:\n    next_states: dict = field(default_factory=dict)\n    state_id: Any = None\n\n\ndef state_for_seed(data, seed):\n    if data.seeds_to_states is None:\n        data.seeds_to_states = {}\n\n    seeds_to_states = data.seeds_to_states\n    try:\n        state = seeds_to_states[seed]\n    except KeyError:\n        state = RandomState()\n        seeds_to_states[seed] = state\n\n    return state\n\n\ndef normalize_zero(f: float) -> float:\n    if f == 0.0:\n        return 0.0\n    else:\n        return f\n\n\nclass ArtificialRandom(HypothesisRandom):\n    VERSION = 10**6\n\n    def __init__(self, *, note_method_calls: bool, data: ConjectureData) -> None:\n        super().__init__(note_method_calls=note_method_calls)\n        self.__data = data\n        self.__state = RandomState()\n\n    def __repr__(self) -> str:\n        return \"HypothesisRandom(generated data)\"\n\n    def __copy__(self) -> \"ArtificialRandom\":\n        result = ArtificialRandom(\n            note_method_calls=self._note_method_calls,\n            data=self.__data,\n        )\n        result.setstate(self.getstate())\n        return result\n\n    def __convert_result(self, method, kwargs, result):\n        if method == \"choice\":\n            return kwargs.get(\"seq\")[result]\n        if method in (\"choices\", \"sample\"):\n            seq = kwargs[\"population\"]\n            return [seq[i] for i in result]\n        if method == \"shuffle\":\n            seq = kwargs[\"x\"]\n            original = list(seq)\n            for i, i2 in enumerate(result):\n                seq[i] = original[i2]\n            return None\n        return result\n\n    def _hypothesis_do_random(self, method, kwargs):\n        if method == \"choices\":\n            key = (method, len(kwargs[\"population\"]), kwargs.get(\"k\"))\n        elif method == \"choice\":\n            key = (method, len(kwargs[\"seq\"]))\n        elif method == \"shuffle\":\n            key = (method, len(kwargs[\"x\"]))\n        else:\n            key = (method, *sorted(kwargs))\n\n        try:\n            result, self.__state = self.__state.next_states[key]\n        except KeyError:\n            pass\n        else:\n            return self.__convert_result(method, kwargs, result)\n\n        if method == \"_randbelow\":\n            result = self.__data.draw_integer(0, kwargs[\"n\"] - 1)\n        elif method == \"random\":\n            # See https://github.com/HypothesisWorks/hypothesis/issues/4297\n            # for numerics/bounds of \"random\" and \"betavariate\"\n            result = self.__data.draw(floats(0, 1, exclude_max=True))\n        elif method == \"betavariate\":\n            result = self.__data.draw(floats(0, 1))\n        elif method == \"uniform\":\n            a = normalize_zero(kwargs[\"a\"])\n            b = normalize_zero(kwargs[\"b\"])\n            result = self.__data.draw(floats(a, b))\n        elif method in (\"weibullvariate\", \"gammavariate\"):\n            result = self.__data.draw(floats(min_value=0.0, allow_infinity=False))\n        elif method in (\"gauss\", \"normalvariate\"):\n            mu = kwargs[\"mu\"]\n            result = mu + self.__data.draw(\n                floats(allow_nan=False, allow_infinity=False)\n            )\n        elif method == \"vonmisesvariate\":\n            result = self.__data.draw(floats(0, 2 * math.pi))\n        elif method == \"randrange\":\n            if kwargs[\"stop\"] is None:\n                stop = kwargs[\"start\"]\n                start = 0\n            else:\n                start = kwargs[\"start\"]\n                stop = kwargs[\"stop\"]\n\n            step = kwargs[\"step\"]\n            if start == stop:\n                raise ValueError(f\"empty range for randrange({start}, {stop}, {step})\")\n\n            if step != 1:\n                endpoint = (stop - start) // step\n                if (start - stop) % step == 0:\n                    endpoint -= 1\n\n                i = self.__data.draw_integer(0, endpoint)\n                result = start + i * step\n            else:\n                result = self.__data.draw_integer(start, stop - 1)\n        elif method == \"randint\":\n            result = self.__data.draw_integer(kwargs[\"a\"], kwargs[\"b\"])\n        # New in Python 3.12, so not taken by our coverage job\n        elif method == \"binomialvariate\":  # pragma: no cover\n            result = self.__data.draw_integer(0, kwargs[\"n\"])\n        elif method == \"choice\":\n            seq = kwargs[\"seq\"]\n            result = self.__data.draw_integer(0, len(seq) - 1)\n        elif method == \"choices\":\n            k = kwargs[\"k\"]\n            result = self.__data.draw(\n                lists(\n                    integers(0, len(kwargs[\"population\"]) - 1),\n                    min_size=k,\n                    max_size=k,\n                )\n            )\n        elif method == \"sample\":\n            k = kwargs[\"k\"]\n            seq = kwargs[\"population\"]\n\n            if k > len(seq) or k < 0:\n                raise ValueError(\n                    f\"Sample size {k} not in expected range 0 <= k <= {len(seq)}\"\n                )\n\n            if k == 0:\n                result = []\n            else:\n                result = self.__data.draw(\n                    lists(\n                        sampled_from(range(len(seq))),\n                        min_size=k,\n                        max_size=k,\n                        unique=True,\n                    )\n                )\n\n        elif method == \"getrandbits\":\n            result = self.__data.draw_integer(0, 2 ** kwargs[\"n\"] - 1)\n        elif method == \"triangular\":\n            low = normalize_zero(kwargs[\"low\"])\n            high = normalize_zero(kwargs[\"high\"])\n            mode = normalize_zero(kwargs[\"mode\"])\n            if mode is None:\n                result = self.__data.draw(floats(low, high))\n            elif self.__data.draw_boolean(0.5):\n                result = self.__data.draw(floats(mode, high))\n            else:\n                result = self.__data.draw(floats(low, mode))\n        elif method in (\"paretovariate\", \"expovariate\", \"lognormvariate\"):\n            result = self.__data.draw(floats(min_value=0.0))\n        elif method == \"shuffle\":\n            result = self.__data.draw(permutations(range(len(kwargs[\"x\"]))))\n        elif method == \"randbytes\":\n            n = int(kwargs[\"n\"])\n            result = self.__data.draw_bytes(min_size=n, max_size=n)\n        else:\n            raise NotImplementedError(method)\n\n        new_state = RandomState()\n        self.__state.next_states[key] = (result, new_state)\n        self.__state = new_state\n\n        return self.__convert_result(method, kwargs, result)\n\n    def seed(self, seed):\n        self.__state = state_for_seed(self.__data, seed)\n\n    def getstate(self):\n        if self.__state.state_id is not None:\n            return self.__state.state_id\n\n        if self.__data.states_for_ids is None:\n            self.__data.states_for_ids = {}\n        states_for_ids = self.__data.states_for_ids\n        self.__state.state_id = len(states_for_ids)\n        states_for_ids[self.__state.state_id] = self.__state\n\n        return self.__state.state_id\n\n    def setstate(self, state):\n        self.__state = self.__data.states_for_ids[state]\n\n\nDUMMY_RANDOM = Random(0)\n\n\ndef convert_kwargs(name, kwargs):\n    kwargs = dict(kwargs)\n\n    signature = sig_of(name)\n    params = signature.parameters\n\n    bound = signature.bind(DUMMY_RANDOM, **kwargs)\n    bound.apply_defaults()\n\n    for k in list(kwargs):\n        if (\n            kwargs[k] is params[k].default\n            or params[k].kind != inspect.Parameter.KEYWORD_ONLY\n        ):\n            kwargs.pop(k)\n\n    arg_names = list(params)[1:]\n\n    args = []\n\n    for a in arg_names:\n        if params[a].kind == inspect.Parameter.KEYWORD_ONLY:\n            break\n        args.append(bound.arguments[a])\n        kwargs.pop(a, None)\n\n    while args:\n        name = arg_names[len(args) - 1]\n        if args[-1] is params[name].default:\n            args.pop()\n        else:\n            break\n\n    return (args, kwargs)\n\n\nclass TrueRandom(HypothesisRandom):\n    def __init__(self, seed, note_method_calls):\n        super().__init__(note_method_calls=note_method_calls)\n        self.__seed = seed\n        self.__random = Random(seed)\n\n    def _hypothesis_do_random(self, method, kwargs):\n        fn = getattr(self.__random, method)\n        try:\n            return fn(**kwargs)\n        except TypeError:\n            pass\n        args, kwargs = convert_kwargs(method, kwargs)\n        return fn(*args, **kwargs)\n\n    def __copy__(self) -> \"TrueRandom\":\n        result = TrueRandom(\n            seed=self.__seed,\n            note_method_calls=self._note_method_calls,\n        )\n        result.setstate(self.getstate())\n        return result\n\n    def __repr__(self) -> str:\n        return f\"Random({self.__seed!r})\"\n\n    def seed(self, seed):\n        self.__random.seed(seed)\n        self.__seed = seed\n\n    def getstate(self):\n        return self.__random.getstate()\n\n    def setstate(self, state):\n        self.__random.setstate(state)\n\n\nclass RandomStrategy(SearchStrategy[HypothesisRandom]):\n    def __init__(self, *, note_method_calls: bool, use_true_random: bool) -> None:\n        super().__init__()\n        self.__note_method_calls = note_method_calls\n        self.__use_true_random = use_true_random\n\n    def do_draw(self, data: ConjectureData) -> HypothesisRandom:\n        if self.__use_true_random:\n            seed = data.draw_integer(0, 2**64 - 1)\n            return TrueRandom(seed=seed, note_method_calls=self.__note_method_calls)\n        else:\n            return ArtificialRandom(\n                note_method_calls=self.__note_method_calls, data=data\n            )\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/recursive.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport threading\nimport warnings\nfrom collections.abc import Callable\nfrom contextlib import contextmanager\n\nfrom hypothesis.errors import HypothesisWarning, InvalidArgument\nfrom hypothesis.internal.reflection import (\n    get_pretty_function_description,\n    is_first_param_referenced_in_function,\n    is_identity_function,\n)\nfrom hypothesis.internal.validation import check_type\nfrom hypothesis.strategies._internal.strategies import (\n    OneOfStrategy,\n    SearchStrategy,\n    check_strategy,\n)\nfrom hypothesis.utils.deprecation import note_deprecation\n\n\nclass LimitReached(BaseException):\n    pass\n\n\nclass LimitedStrategy(SearchStrategy):\n    def __init__(self, strategy):\n        super().__init__()\n        self.base_strategy = strategy\n        self._threadlocal = threading.local()\n\n    @property\n    def marker(self):\n        return getattr(self._threadlocal, \"marker\", 0)\n\n    @marker.setter\n    def marker(self, value):\n        self._threadlocal.marker = value\n\n    @property\n    def currently_capped(self):\n        return getattr(self._threadlocal, \"currently_capped\", False)\n\n    @currently_capped.setter\n    def currently_capped(self, value):\n        self._threadlocal.currently_capped = value\n\n    def __repr__(self) -> str:\n        return f\"LimitedStrategy({self.base_strategy!r})\"\n\n    def do_validate(self) -> None:\n        self.base_strategy.validate()\n\n    def do_draw(self, data):\n        assert self.currently_capped\n        if self.marker <= 0:\n            raise LimitReached\n        self.marker -= 1\n        return data.draw(self.base_strategy)\n\n    @contextmanager\n    def capped(self, max_templates):\n        try:\n            was_capped = self.currently_capped\n            self.currently_capped = True\n            self.marker = max_templates\n            yield\n        finally:\n            self.currently_capped = was_capped\n\n\nclass RecursiveStrategy(SearchStrategy):\n    def __init__(\n        self,\n        base: SearchStrategy,\n        extend: Callable[[SearchStrategy], SearchStrategy],\n        min_leaves: int | None,\n        max_leaves: int,\n    ):\n        super().__init__()\n        self.min_leaves = min_leaves\n        self.max_leaves = max_leaves\n        self.base = base\n        self.limited_base = LimitedStrategy(base)\n        self.extend = extend\n\n        strategies = [self.limited_base, self.extend(self.limited_base)]\n        while 2 ** (len(strategies) - 1) <= max_leaves:\n            strategies.append(extend(OneOfStrategy(tuple(strategies))))\n        # If min_leaves > 1, we can never draw from base directly\n        if min_leaves is not None and min_leaves > 1:\n            strategies = strategies[1:]\n        self.strategy = OneOfStrategy(strategies)\n\n    def __repr__(self) -> str:\n        if not hasattr(self, \"_cached_repr\"):\n            self._cached_repr = (\n                f\"recursive({self.base!r}, \"\n                f\"{get_pretty_function_description(self.extend)}, \"\n                f\"min_leaves={self.min_leaves}, max_leaves={self.max_leaves})\"\n            )\n        return self._cached_repr\n\n    def do_validate(self) -> None:\n        check_strategy(self.base, \"base\")\n        extended = self.extend(self.limited_base)\n        check_strategy(extended, f\"extend({self.limited_base!r})\")\n        self.limited_base.validate()\n        extended.validate()\n\n        if is_identity_function(self.extend):\n            warnings.warn(\n                \"extend=lambda x: x is a no-op; you probably want to use a \"\n                \"different extend function, or just use the base strategy directly.\",\n                HypothesisWarning,\n                stacklevel=5,\n            )\n\n        if not is_first_param_referenced_in_function(self.extend):\n            msg = (\n                f\"extend={get_pretty_function_description(self.extend)} doesn't use \"\n                \"it's argument, and thus can't actually recurse!\"\n            )\n            if self.min_leaves is None:\n                note_deprecation(\n                    msg,\n                    since=\"2026-01-12\",\n                    has_codemod=False,\n                    stacklevel=1,\n                )\n            else:\n                raise InvalidArgument(msg)\n\n        if self.min_leaves is not None:\n            check_type(int, self.min_leaves, \"min_leaves\")\n        check_type(int, self.max_leaves, \"max_leaves\")\n        if self.min_leaves is not None and self.min_leaves <= 0:\n            raise InvalidArgument(\n                f\"min_leaves={self.min_leaves!r} must be greater than zero\"\n            )\n        if self.max_leaves <= 0:\n            raise InvalidArgument(\n                f\"max_leaves={self.max_leaves!r} must be greater than zero\"\n            )\n        if (self.min_leaves or 1) > self.max_leaves:\n            raise InvalidArgument(\n                f\"min_leaves={self.min_leaves!r} must be less than or equal to \"\n                f\"max_leaves={self.max_leaves!r}\"\n            )\n\n    def do_draw(self, data):\n        min_leaves_retries = 0\n        while True:\n            try:\n                with self.limited_base.capped(self.max_leaves):\n                    result = data.draw(self.strategy)\n                    leaves_drawn = self.max_leaves - self.limited_base.marker\n                    if self.min_leaves and leaves_drawn < self.min_leaves:\n                        data.events[\n                            f\"Draw for {self!r} had fewer than \"\n                            f\"min_leaves={self.min_leaves} and had to be retried\"\n                        ] = \"\"\n                        min_leaves_retries += 1\n                        if min_leaves_retries < 5:\n                            continue\n                        data.mark_invalid(f\"min_leaves={self.min_leaves} unsatisfied\")\n                    return result\n            except LimitReached:\n                data.events[\n                    f\"Draw for {self!r} exceeded \"\n                    f\"max_leaves={self.max_leaves} and had to be retried\"\n                ] = \"\"\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/regex.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport operator\nimport re\n\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal import charmap\nfrom hypothesis.strategies._internal.lazy import unwrap_strategies\nfrom hypothesis.strategies._internal.strings import OneCharStringStrategy\n\ntry:  # pragma: no cover\n    import re._constants as sre\n    import re._parser as sre_parse\n\n    ATOMIC_GROUP = sre.ATOMIC_GROUP\n    POSSESSIVE_REPEAT = sre.POSSESSIVE_REPEAT\nexcept ImportError:  # Python < 3.11\n    import sre_constants as sre\n    import sre_parse\n\n    ATOMIC_GROUP = object()\n    POSSESSIVE_REPEAT = object()\n\nfrom hypothesis import reject, strategies as st\nfrom hypothesis.internal.charmap import as_general_categories, categories\nfrom hypothesis.internal.compat import add_note, int_to_byte\n\nUNICODE_CATEGORIES = set(categories())\n\n\nSPACE_CHARS = set(\" \\t\\n\\r\\f\\v\")\nUNICODE_SPACE_CHARS = SPACE_CHARS | set(\"\\x1c\\x1d\\x1e\\x1f\\x85\")\nUNICODE_DIGIT_CATEGORIES = {\"Nd\"}\nUNICODE_SPACE_CATEGORIES = set(as_general_categories([\"Z\"]))\nUNICODE_LETTER_CATEGORIES = set(as_general_categories([\"L\"]))\nUNICODE_WORD_CATEGORIES = set(as_general_categories([\"L\", \"N\"]))\n\n# This is verbose, but correct on all versions of Python\nBYTES_ALL = {int_to_byte(i) for i in range(256)}\nBYTES_DIGIT = {b for b in BYTES_ALL if re.match(b\"\\\\d\", b)}\nBYTES_SPACE = {b for b in BYTES_ALL if re.match(b\"\\\\s\", b)}\nBYTES_WORD = {b for b in BYTES_ALL if re.match(b\"\\\\w\", b)}\nBYTES_LOOKUP = {\n    sre.CATEGORY_DIGIT: BYTES_DIGIT,\n    sre.CATEGORY_SPACE: BYTES_SPACE,\n    sre.CATEGORY_WORD: BYTES_WORD,\n    sre.CATEGORY_NOT_DIGIT: BYTES_ALL - BYTES_DIGIT,\n    sre.CATEGORY_NOT_SPACE: BYTES_ALL - BYTES_SPACE,\n    sre.CATEGORY_NOT_WORD: BYTES_ALL - BYTES_WORD,\n}\n\n\nGROUP_CACHE_STRATEGY: st.SearchStrategy[dict] = st.shared(\n    st.builds(dict), key=\"hypothesis.regex.group_cache\"\n)\n\n\nclass IncompatibleWithAlphabet(InvalidArgument):\n    pass\n\n\n@st.composite\ndef update_group(draw, group_name, strategy):\n    cache = draw(GROUP_CACHE_STRATEGY)\n    result = draw(strategy)\n    cache[group_name] = result\n    return result\n\n\n@st.composite\ndef reuse_group(draw, group_name):\n    cache = draw(GROUP_CACHE_STRATEGY)\n    try:\n        return cache[group_name]\n    except KeyError:\n        reject()\n\n\n@st.composite\ndef group_conditional(draw, group_name, if_yes, if_no):\n    cache = draw(GROUP_CACHE_STRATEGY)\n    if group_name in cache:\n        return draw(if_yes)\n    else:\n        return draw(if_no)\n\n\n@st.composite\ndef clear_cache_after_draw(draw, base_strategy):\n    cache = draw(GROUP_CACHE_STRATEGY)\n    result = draw(base_strategy)\n    cache.clear()\n    return result\n\n\ndef chars_not_in_alphabet(alphabet, string):\n    # Given a string, return a tuple of the characters which are not in alphabet\n    if alphabet is None:\n        return ()\n    intset = unwrap_strategies(alphabet).intervals\n    return tuple(c for c in string if c not in intset)\n\n\nclass Context:\n    __slots__ = [\"flags\"]\n\n    def __init__(self, flags):\n        self.flags = flags\n\n\nclass CharactersBuilder:\n    \"\"\"Helper object that allows to configure `characters` strategy with\n    various unicode categories and characters. Also allows negation of\n    configured set.\n\n    :param negate: If True, configure :func:`hypothesis.strategies.characters`\n        to match anything other than configured character set\n    :param flags: Regex flags. They affect how and which characters are matched\n    \"\"\"\n\n    def __init__(self, *, negate=False, flags=0, alphabet):\n        self._categories = set()\n        self._whitelist_chars = set()\n        self._blacklist_chars = set()\n        self._negate = negate\n        self._ignorecase = flags & re.IGNORECASE\n        self.code_to_char = chr\n        self._alphabet = unwrap_strategies(alphabet)\n        if flags & re.ASCII:\n            self._alphabet = OneCharStringStrategy(\n                self._alphabet.intervals & charmap.query(max_codepoint=127)\n            )\n\n    @property\n    def strategy(self):\n        \"\"\"Returns resulting strategy that generates configured char set.\"\"\"\n        # Start by getting the set of all characters allowed by the pattern\n        white_chars = self._whitelist_chars - self._blacklist_chars\n        multi_chars = {c for c in white_chars if len(c) > 1}\n        intervals = charmap.query(\n            categories=self._categories,\n            exclude_characters=self._blacklist_chars,\n            include_characters=white_chars - multi_chars,\n        )\n        # Then take the complement if this is from a negated character class\n        if self._negate:\n            intervals = charmap.query() - intervals\n            multi_chars.clear()\n        # and finally return the intersection with our alphabet\n        return OneCharStringStrategy(intervals & self._alphabet.intervals) | (\n            st.sampled_from(sorted(multi_chars)) if multi_chars else st.nothing()\n        )\n\n    def add_category(self, category):\n        \"\"\"Update unicode state to match sre_parse object ``category``.\"\"\"\n        if category == sre.CATEGORY_DIGIT:\n            self._categories |= UNICODE_DIGIT_CATEGORIES\n        elif category == sre.CATEGORY_NOT_DIGIT:\n            self._categories |= UNICODE_CATEGORIES - UNICODE_DIGIT_CATEGORIES\n        elif category == sre.CATEGORY_SPACE:\n            self._categories |= UNICODE_SPACE_CATEGORIES\n            self._whitelist_chars |= UNICODE_SPACE_CHARS\n        elif category == sre.CATEGORY_NOT_SPACE:\n            self._categories |= UNICODE_CATEGORIES - UNICODE_SPACE_CATEGORIES\n            self._blacklist_chars |= UNICODE_SPACE_CHARS\n        elif category == sre.CATEGORY_WORD:\n            self._categories |= UNICODE_WORD_CATEGORIES\n            self._whitelist_chars.add(\"_\")\n        elif category == sre.CATEGORY_NOT_WORD:\n            self._categories |= UNICODE_CATEGORIES - UNICODE_WORD_CATEGORIES\n            self._blacklist_chars.add(\"_\")\n        else:\n            raise NotImplementedError(f\"Unknown character category: {category}\")\n\n    def add_char(self, c):\n        \"\"\"Add given char to the whitelist.\"\"\"\n        self._whitelist_chars.add(c)\n        if (\n            self._ignorecase\n            and re.match(re.escape(c), c.swapcase(), flags=re.IGNORECASE) is not None\n        ):\n            # Note that it is possible that `len(c.swapcase()) > 1`\n            self._whitelist_chars.add(c.swapcase())\n\n\nclass BytesBuilder(CharactersBuilder):\n    def __init__(self, *, negate=False, flags=0):\n        self._whitelist_chars = set()\n        self._blacklist_chars = set()\n        self._negate = negate\n        self._alphabet = None\n        self._ignorecase = flags & re.IGNORECASE\n        self.code_to_char = int_to_byte\n\n    @property\n    def strategy(self):\n        \"\"\"Returns resulting strategy that generates configured char set.\"\"\"\n        allowed = self._whitelist_chars\n        if self._negate:\n            allowed = BYTES_ALL - allowed\n        return st.sampled_from(sorted(allowed))\n\n    def add_category(self, category):\n        \"\"\"Update characters state to match sre_parse object ``category``.\"\"\"\n        self._whitelist_chars |= BYTES_LOOKUP[category]\n\n\n@st.composite\ndef maybe_pad(draw, regex, strategy, left_pad_strategy, right_pad_strategy):\n    \"\"\"Attempt to insert padding around the result of a regex draw while\n    preserving the match.\"\"\"\n    result = draw(strategy)\n    left_pad = draw(left_pad_strategy)\n    if left_pad and regex.search(left_pad + result):\n        result = left_pad + result\n    right_pad = draw(right_pad_strategy)\n    if right_pad and regex.search(result + right_pad):\n        result += right_pad\n    return result\n\n\ndef base_regex_strategy(regex, parsed=None, alphabet=None):\n    if parsed is None:\n        parsed = sre_parse.parse(regex.pattern, flags=regex.flags)\n    try:\n        s = _strategy(\n            parsed,\n            context=Context(flags=regex.flags),\n            is_unicode=isinstance(regex.pattern, str),\n            alphabet=alphabet,\n        )\n    except Exception as err:\n        add_note(err, f\"{alphabet=} {regex=}\")\n        raise\n    return clear_cache_after_draw(s)\n\n\ndef regex_strategy(\n    regex, fullmatch, *, alphabet, _temp_jsonschema_hack_no_end_newline=False\n):\n    if not hasattr(regex, \"pattern\"):\n        regex = re.compile(regex)\n\n    is_unicode = isinstance(regex.pattern, str)\n\n    parsed = sre_parse.parse(regex.pattern, flags=regex.flags)\n\n    if fullmatch:\n        if not parsed:\n            return st.just(\"\" if is_unicode else b\"\")\n        return base_regex_strategy(regex, parsed, alphabet).filter(regex.fullmatch)\n\n    if not parsed:\n        if is_unicode:\n            return st.text(alphabet=alphabet)\n        else:\n            return st.binary()\n\n    if is_unicode:\n        base_padding_strategy = st.text(alphabet=alphabet)\n        empty = st.just(\"\")\n        newline = st.just(\"\\n\")\n    else:\n        base_padding_strategy = st.binary()\n        empty = st.just(b\"\")\n        newline = st.just(b\"\\n\")\n\n    right_pad = base_padding_strategy\n    left_pad = base_padding_strategy\n\n    if parsed[-1][0] == sre.AT:\n        if parsed[-1][1] == sre.AT_END_STRING:\n            right_pad = empty\n        elif parsed[-1][1] == sre.AT_END:\n            if regex.flags & re.MULTILINE:\n                right_pad = st.one_of(\n                    empty, st.builds(operator.add, newline, right_pad)\n                )\n            else:\n                right_pad = st.one_of(empty, newline)\n\n            # This will be removed when a regex-syntax-translation library exists.\n            # It's a pretty nasty hack, but means that we can match the semantics\n            # of JSONschema's compatible subset of ECMA regex, which is important\n            # for hypothesis-jsonschema and Schemathesis. See e.g.\n            # https://github.com/schemathesis/schemathesis/issues/1241\n            if _temp_jsonschema_hack_no_end_newline:\n                right_pad = empty\n\n    if parsed[0][0] == sre.AT:\n        if parsed[0][1] == sre.AT_BEGINNING_STRING:\n            left_pad = empty\n        elif parsed[0][1] == sre.AT_BEGINNING:\n            if regex.flags & re.MULTILINE:\n                left_pad = st.one_of(empty, st.builds(operator.add, left_pad, newline))\n            else:\n                left_pad = empty\n\n    base = base_regex_strategy(regex, parsed, alphabet).filter(regex.search)\n\n    return maybe_pad(regex, base, left_pad, right_pad)\n\n\ndef _strategy(codes, context, is_unicode, *, alphabet):\n    \"\"\"Convert SRE regex parse tree to strategy that generates strings matching\n    that regex represented by that parse tree.\n\n    `codes` is either a list of SRE regex elements representations or a\n    particular element representation. Each element is a tuple of element code\n    (as string) and parameters. E.g. regex 'ab[0-9]+' compiles to following\n    elements:\n\n        [\n            (LITERAL, 97),\n            (LITERAL, 98),\n            (MAX_REPEAT, (1, 4294967295, [\n                (IN, [\n                    (RANGE, (48, 57))\n                ])\n            ]))\n        ]\n\n    The function recursively traverses regex element tree and converts each\n    element to strategy that generates strings that match that element.\n\n    Context stores\n    1. List of groups (for backreferences)\n    2. Active regex flags (e.g. IGNORECASE, DOTALL, UNICODE, they affect\n       behavior of various inner strategies)\n    \"\"\"\n\n    def recurse(codes):\n        return _strategy(codes, context, is_unicode, alphabet=alphabet)\n\n    if is_unicode:\n        empty = \"\"\n        to_char = chr\n    else:\n        empty = b\"\"\n        to_char = int_to_byte\n        binary_char = st.binary(min_size=1, max_size=1)\n\n    if not isinstance(codes, tuple):\n        # List of codes\n        strategies = []\n\n        i = 0\n        while i < len(codes):\n            if codes[i][0] == sre.LITERAL and not context.flags & re.IGNORECASE:\n                # Merge subsequent \"literals\" into one `just()` strategy\n                # that generates corresponding text if no IGNORECASE\n                j = i + 1\n                while j < len(codes) and codes[j][0] == sre.LITERAL:\n                    j += 1\n\n                if i + 1 < j:\n                    chars = empty.join(to_char(charcode) for _, charcode in codes[i:j])\n                    if invalid := chars_not_in_alphabet(alphabet, chars):\n                        raise IncompatibleWithAlphabet(\n                            f\"Literal {chars!r} contains characters {invalid!r} \"\n                            f\"which are not in the specified alphabet\"\n                        )\n                    strategies.append(st.just(chars))\n                    i = j\n                    continue\n\n            strategies.append(recurse(codes[i]))\n            i += 1\n\n        # We handle this separately at the top level, but some regex can\n        # contain empty lists internally, so we need to handle this here too.\n        if not strategies:\n            return st.just(empty)\n\n        if len(strategies) == 1:\n            return strategies[0]\n        return st.tuples(*strategies).map(empty.join)\n    else:\n        # Single code\n        code, value = codes\n        if code == sre.LITERAL:\n            # Regex 'a' (single char)\n            c = to_char(value)\n            if chars_not_in_alphabet(alphabet, c):\n                raise IncompatibleWithAlphabet(\n                    f\"Literal {c!r} is not in the specified alphabet\"\n                )\n            if (\n                context.flags & re.IGNORECASE\n                and c != c.swapcase()\n                and re.match(re.escape(c), c.swapcase(), re.IGNORECASE) is not None\n                and not chars_not_in_alphabet(alphabet, c.swapcase())\n            ):\n                # We do the explicit check for swapped-case matching because\n                # eg 'ß'.upper() == 'SS' and ignorecase doesn't match it.\n                return st.sampled_from([c, c.swapcase()])\n            return st.just(c)\n\n        elif code == sre.NOT_LITERAL:\n            # Regex '[^a]' (negation of a single char)\n            c = to_char(value)\n            blacklist = {c}\n            if (\n                context.flags & re.IGNORECASE\n                and re.match(re.escape(c), c.swapcase(), re.IGNORECASE) is not None\n            ):\n                # There are a few cases where .swapcase() returns two characters,\n                # but is still a case-insensitive match.  In such cases we add *both*\n                # characters to our blacklist, to avoid doing the wrong thing for\n                # patterns such as r\"[^\\u0130]+\" where \"i\\u0307\" matches.\n                #\n                # (that's respectively 'Latin letter capital I with dot above' and\n                # 'latin latter i' + 'combining dot above'; see issue #2657)\n                #\n                # As a final additional wrinkle, \"latin letter capital I\" *also*\n                # case-insensitive-matches, with or without combining dot character.\n                # We therefore have to chain .swapcase() calls until a fixpoint.\n                stack = [c.swapcase()]\n                while stack:\n                    for char in stack.pop():\n                        blacklist.add(char)\n                        stack.extend(set(char.swapcase()) - blacklist)\n\n            if is_unicode:\n                return OneCharStringStrategy(\n                    unwrap_strategies(alphabet).intervals\n                    & charmap.query(exclude_characters=blacklist)\n                )\n            else:\n                return binary_char.filter(lambda c: c not in blacklist)\n\n        elif code == sre.IN:\n            # Regex '[abc0-9]' (set of characters)\n            negate = value[0][0] == sre.NEGATE\n            if is_unicode:\n                builder = CharactersBuilder(\n                    flags=context.flags, negate=negate, alphabet=alphabet\n                )\n            else:\n                builder = BytesBuilder(flags=context.flags, negate=negate)\n\n            for charset_code, charset_value in value:\n                if charset_code == sre.NEGATE:\n                    # Regex '[^...]' (negation)\n                    # handled by builder = CharactersBuilder(...) above\n                    pass\n                elif charset_code == sre.LITERAL:\n                    # Regex '[a]' (single char)\n                    c = builder.code_to_char(charset_value)\n                    if chars_not_in_alphabet(builder._alphabet, c):\n                        raise IncompatibleWithAlphabet(\n                            f\"Literal {c!r} is not in the specified alphabet\"\n                        )\n                    builder.add_char(c)\n                elif charset_code == sre.RANGE:\n                    # Regex '[a-z]' (char range)\n                    low, high = charset_value\n                    chars = empty.join(map(builder.code_to_char, range(low, high + 1)))\n                    if len(chars) == len(\n                        invalid := set(chars_not_in_alphabet(alphabet, chars))\n                    ):\n                        raise IncompatibleWithAlphabet(\n                            f\"Charset '[{chr(low)}-{chr(high)}]' contains characters {invalid!r} \"\n                            f\"which are not in the specified alphabet\"\n                        )\n                    for c in chars:\n                        if isinstance(c, int):\n                            c = int_to_byte(c)\n                        if c not in invalid:\n                            builder.add_char(c)\n                elif charset_code == sre.CATEGORY:\n                    # Regex '[\\w]' (char category)\n                    builder.add_category(charset_value)\n                else:\n                    # Currently there are no known code points other than\n                    # handled here. This code is just future proofing\n                    raise NotImplementedError(f\"Unknown charset code: {charset_code}\")\n            return builder.strategy\n\n        elif code == sre.ANY:\n            # Regex '.' (any char)\n            if is_unicode:\n                assert alphabet is not None\n                if context.flags & re.DOTALL:\n                    return alphabet\n                return OneCharStringStrategy(\n                    unwrap_strategies(alphabet).intervals\n                    & charmap.query(exclude_characters=\"\\n\")\n                )\n            else:\n                if context.flags & re.DOTALL:\n                    return binary_char\n                return binary_char.filter(lambda c: c != b\"\\n\")\n\n        elif code == sre.AT:\n            # Regexes like '^...', '...$', '\\bfoo', '\\Bfoo'\n            # An empty string (or newline) will match the token itself, but\n            # we don't and can't check the position (eg '%' at the end)\n            return st.just(empty)\n\n        elif code == sre.SUBPATTERN:\n            # Various groups: '(...)', '(:...)' or '(?P<name>...)'\n            old_flags = context.flags\n            context.flags = (context.flags | value[1]) & ~value[2]\n\n            strat = _strategy(value[-1], context, is_unicode, alphabet=alphabet)\n\n            context.flags = old_flags\n\n            if value[0]:\n                strat = update_group(value[0], strat)\n\n            return strat\n\n        elif code == sre.GROUPREF:\n            # Regex '\\\\1' or '(?P=name)' (group reference)\n            return reuse_group(value)\n\n        elif code == sre.ASSERT:\n            # Regex '(?=...)' or '(?<=...)' (positive lookahead/lookbehind)\n            return recurse(value[1])\n\n        elif code == sre.ASSERT_NOT:\n            # Regex '(?!...)' or '(?<!...)' (negative lookahead/lookbehind)\n            return st.just(empty)\n\n        elif code == sre.BRANCH:\n            # Regex 'a|b|c' (branch)\n            branches = []\n            errors = []\n            for branch in value[1]:\n                try:\n                    branches.append(recurse(branch))\n                except IncompatibleWithAlphabet as e:\n                    errors.append(str(e))\n            if errors and not branches:\n                raise IncompatibleWithAlphabet(\"\\n\".join(errors))\n            return st.one_of(branches)\n\n        elif code in [sre.MIN_REPEAT, sre.MAX_REPEAT, POSSESSIVE_REPEAT]:\n            # Regexes 'a?', 'a*', 'a+' and their non-greedy variants\n            # (repeaters)\n            at_least, at_most, subregex = value\n            if at_most == sre.MAXREPEAT:\n                at_most = None\n            if at_least == 0 and at_most == 1:\n                return st.just(empty) | recurse(subregex)\n            return st.lists(recurse(subregex), min_size=at_least, max_size=at_most).map(\n                empty.join\n            )\n\n        elif code == sre.GROUPREF_EXISTS:\n            # Regex '(?(id/name)yes-pattern|no-pattern)'\n            # (if group exists choice)\n            return group_conditional(\n                value[0],\n                recurse(value[1]),\n                recurse(value[2]) if value[2] else st.just(empty),\n            )\n        elif code == ATOMIC_GROUP:  # pragma: no cover  # new in Python 3.11\n            return _strategy(value, context, is_unicode, alphabet=alphabet)\n\n        else:\n            # Currently there are no known code points other than handled here.\n            # This code is just future proofing\n            raise NotImplementedError(\n                f\"Unknown code point: {code!r}.  Please open an issue.\"\n            )\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/shared.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport warnings\nfrom collections.abc import Hashable\nfrom typing import Any\n\nfrom hypothesis.errors import HypothesisWarning\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.strategies._internal import SearchStrategy\nfrom hypothesis.strategies._internal.strategies import Ex\n\n\nclass SharedStrategy(SearchStrategy[Ex]):\n    def __init__(self, base: SearchStrategy[Ex], key: Hashable | None = None):\n        super().__init__()\n        self.key = key\n        self.base = base\n\n    def __repr__(self) -> str:\n        if self.key is not None:\n            return f\"shared({self.base!r}, key={self.key!r})\"\n        else:\n            return f\"shared({self.base!r})\"\n\n    def calc_label(self) -> int:\n        return self.base.calc_label()\n\n    # Ideally would be -> Ex, but key collisions with different-typed values are\n    # possible. See https://github.com/HypothesisWorks/hypothesis/issues/4301.\n    def do_draw(self, data: ConjectureData) -> Any:\n        key = self.key or self\n        if key not in data._shared_strategy_draws:\n            drawn = data.draw(self.base)\n            data._shared_strategy_draws[key] = (drawn, self)\n        else:\n            drawn, other = data._shared_strategy_draws[key]\n\n            # Check that the strategies shared under this key are equivalent\n            if self.label != other.label:\n                warnings.warn(\n                    f\"Different strategies are shared under {key=}. This\"\n                    \" risks drawing values that are not valid examples for the strategy,\"\n                    \" or that have a narrower range than expected.\"\n                    f\" Conflicting strategies: ({self!r}, {other!r}).\",\n                    HypothesisWarning,\n                    stacklevel=1,\n                )\n        return drawn\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/strategies.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport sys\nimport threading\nimport warnings\nfrom collections import abc, defaultdict\nfrom collections.abc import Callable, Sequence\nfrom functools import lru_cache\nfrom random import shuffle\nfrom threading import RLock\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    ClassVar,\n    Generic,\n    Literal,\n    TypeAlias,\n    TypeVar,\n    cast,\n    overload,\n)\n\nfrom hypothesis._settings import HealthCheck, Phase, Verbosity, settings\nfrom hypothesis.control import _current_build_context, current_build_context\nfrom hypothesis.errors import (\n    HypothesisException,\n    HypothesisWarning,\n    InvalidArgument,\n    NonInteractiveExampleWarning,\n    UnsatisfiedAssumption,\n)\nfrom hypothesis.internal.conjecture import utils as cu\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.conjecture.utils import (\n    calc_label_from_cls,\n    calc_label_from_hash,\n    calc_label_from_name,\n    combine_labels,\n)\nfrom hypothesis.internal.coverage import check_function\nfrom hypothesis.internal.reflection import (\n    get_pretty_function_description,\n    is_identity_function,\n)\nfrom hypothesis.strategies._internal.utils import defines_strategy\nfrom hypothesis.utils.conventions import UniqueIdentifier\n\nif TYPE_CHECKING:\n    Ex = TypeVar(\"Ex\", covariant=True, default=Any)\nelse:\n    Ex = TypeVar(\"Ex\", covariant=True)\n\nT = TypeVar(\"T\")\nT3 = TypeVar(\"T3\")\nT4 = TypeVar(\"T4\")\nT5 = TypeVar(\"T5\")\nMappedFrom = TypeVar(\"MappedFrom\")\nMappedTo = TypeVar(\"MappedTo\")\nRecurT: TypeAlias = Callable[[\"SearchStrategy\"], bool]\ncalculating = UniqueIdentifier(\"calculating\")\n\nMAPPED_SEARCH_STRATEGY_DO_DRAW_LABEL = calc_label_from_name(\n    \"another attempted draw in MappedStrategy\"\n)\n\nFILTERED_SEARCH_STRATEGY_DO_DRAW_LABEL = calc_label_from_name(\n    \"single loop iteration in FilteredStrategy\"\n)\n\nlabel_lock = RLock()\n\n\ndef recursive_property(strategy: \"SearchStrategy\", name: str, default: object) -> Any:\n    \"\"\"Handle properties which may be mutually recursive among a set of\n    strategies.\n\n    These are essentially lazily cached properties, with the ability to set\n    an override: If the property has not been explicitly set, we calculate\n    it on first access and memoize the result for later.\n\n    The problem is that for properties that depend on each other, a naive\n    calculation strategy may hit infinite recursion. Consider for example\n    the property is_empty. A strategy defined as x = st.deferred(lambda: x)\n    is certainly empty (in order to draw a value from x we would have to\n    draw a value from x, for which we would have to draw a value from x,\n    ...), but in order to calculate it the naive approach would end up\n    calling x.is_empty in order to calculate x.is_empty in order to etc.\n\n    The solution is one of fixed point calculation. We start with a default\n    value that is the value of the property in the absence of evidence to\n    the contrary, and then update the values of the property for all\n    dependent strategies until we reach a fixed point.\n\n    The approach taken roughly follows that in section 4.2 of Adams,\n    Michael D., Celeste Hollenbeck, and Matthew Might. \"On the complexity\n    and performance of parsing with derivatives.\" ACM SIGPLAN Notices 51.6\n    (2016): 224-236.\n    \"\"\"\n    assert name in {\"is_empty\", \"has_reusable_values\", \"is_cacheable\"}\n    cache_key = \"cached_\" + name\n    calculation = \"calc_\" + name\n    force_key = \"force_\" + name\n\n    def forced_value(target: SearchStrategy) -> Any:\n        try:\n            return getattr(target, force_key)\n        except AttributeError:\n            return getattr(target, cache_key)\n\n    try:\n        return forced_value(strategy)\n    except AttributeError:\n        pass\n\n    mapping: dict[SearchStrategy, Any] = {}\n    sentinel = object()\n    hit_recursion = False\n\n    # For a first pass we do a direct recursive calculation of the\n    # property, but we block recursively visiting a value in the\n    # computation of its property: When that happens, we simply\n    # note that it happened and return the default value.\n    def recur(strat: SearchStrategy) -> Any:\n        nonlocal hit_recursion\n        try:\n            return forced_value(strat)\n        except AttributeError:\n            pass\n        result = mapping.get(strat, sentinel)\n        if result is calculating:\n            hit_recursion = True\n            return default\n        elif result is sentinel:\n            mapping[strat] = calculating\n            mapping[strat] = getattr(strat, calculation)(recur)\n            return mapping[strat]\n        return result\n\n    recur(strategy)\n\n    # If we hit self-recursion in the computation of any strategy\n    # value, our mapping at the end is imprecise - it may or may\n    # not have the right values in it. We now need to proceed with\n    # a more careful fixed point calculation to get the exact\n    # values. Hopefully our mapping is still pretty good and it\n    # won't take a large number of updates to reach a fixed point.\n    if hit_recursion:\n        needs_update = set(mapping)\n\n        # We track which strategies use which in the course of\n        # calculating their property value. If A ever uses B in\n        # the course of calculating its value, then whenever the\n        # value of B changes we might need to update the value of\n        # A.\n        listeners: dict[SearchStrategy, set[SearchStrategy]] = defaultdict(set)\n    else:\n        needs_update = None\n\n    def recur2(strat: SearchStrategy) -> Any:\n        def recur_inner(other: SearchStrategy) -> Any:\n            try:\n                return forced_value(other)\n            except AttributeError:\n                pass\n            listeners[other].add(strat)\n            result = mapping.get(other, sentinel)\n            if result is sentinel:\n                assert needs_update is not None\n                needs_update.add(other)\n                mapping[other] = default\n                return default\n            return result\n\n        return recur_inner\n\n    count = 0\n    seen = set()\n    while needs_update:\n        count += 1\n        # If we seem to be taking a really long time to stabilize we\n        # start tracking seen values to attempt to detect an infinite\n        # loop. This should be impossible, and most code will never\n        # hit the count, but having an assertion for it means that\n        # testing is easier to debug and we don't just have a hung\n        # test.\n        # Note: This is actually covered, by test_very_deep_deferral\n        # in tests/cover/test_deferred_strategies.py. Unfortunately it\n        # runs into a coverage bug. See\n        # https://github.com/nedbat/coveragepy/issues/605\n        # for details.\n        if count > 50:  # pragma: no cover\n            key = frozenset(mapping.items())\n            assert key not in seen, (key, name)\n            seen.add(key)\n        to_update = needs_update\n        needs_update = set()\n        for strat in to_update:\n            new_value = getattr(strat, calculation)(recur2(strat))\n            if new_value != mapping[strat]:\n                needs_update.update(listeners[strat])\n                mapping[strat] = new_value\n\n    # We now have a complete and accurate calculation of the\n    # property values for everything we have seen in the course of\n    # running this calculation. We simultaneously update all of\n    # them (not just the strategy we started out with).\n    for k, v in mapping.items():\n        setattr(k, cache_key, v)\n    return getattr(strategy, cache_key)\n\n\nclass SearchStrategy(Generic[Ex]):\n    \"\"\"A ``SearchStrategy`` tells Hypothesis how to generate that kind of input.\n\n    This class is only part of the public API for use in type annotations, so that\n    you can write e.g. ``-> SearchStrategy[Foo]`` for your function which returns\n    ``builds(Foo, ...)``.  Do not inherit from or directly instantiate this class.\n    \"\"\"\n\n    __module__: str = \"hypothesis.strategies\"\n    LABELS: ClassVar[dict[type, int]] = {}\n    # triggers `assert isinstance(label, int)` under threading when setting this\n    # in init instead of a classvar. I'm not sure why, init should be safe. But\n    # this works so I'm not looking into it further atm.\n    __label: int | UniqueIdentifier | None = None\n\n    def __init__(self):\n        self.validate_called: dict[int, bool] = {}\n\n    def is_currently_empty(self, data: ConjectureData) -> bool:\n        \"\"\"\n        Returns whether this strategy is currently empty. Unlike ``empty``,\n        which is computed based on static information and cannot change,\n        ``is_currently_empty`` may change over time based on choices made\n        during the test case.\n\n        This is currently only used for stateful testing, where |Bundle| grows a\n        list of values to choose from over the course of a test case.\n\n        ``data`` will only be used for introspection. No values will be drawn\n        from it in a way that modifies the choice sequence.\n        \"\"\"\n        return self.is_empty\n\n    @property\n    def is_empty(self) -> Any:\n        # Returns True if this strategy can never draw a value and will always\n        # result in the data being marked invalid.\n        # The fact that this returns False does not guarantee that a valid value\n        # can be drawn - this is not intended to be perfect, and is primarily\n        # intended to be an optimisation for some cases.\n        return recursive_property(self, \"is_empty\", True)\n\n    # Returns True if values from this strategy can safely be reused without\n    # this causing unexpected behaviour.\n\n    # True if values from this strategy can be implicitly reused (e.g. as\n    # background values in a numpy array) without causing surprising\n    # user-visible behaviour. Should be false for built-in strategies that\n    # produce mutable values, and for strategies that have been mapped/filtered\n    # by arbitrary user-provided functions.\n    @property\n    def has_reusable_values(self) -> Any:\n        return recursive_property(self, \"has_reusable_values\", True)\n\n    @property\n    def is_cacheable(self) -> Any:\n        \"\"\"\n        Whether it is safe to hold on to instances of this strategy in a cache.\n        See _STRATEGY_CACHE.\n        \"\"\"\n        return recursive_property(self, \"is_cacheable\", True)\n\n    def calc_is_cacheable(self, recur: RecurT) -> bool:\n        return True\n\n    def calc_is_empty(self, recur: RecurT) -> bool:\n        # Note: It is correct and significant that the default return value\n        # from calc_is_empty is False despite the default value for is_empty\n        # being true. The reason for this is that strategies should be treated\n        # as empty absent evidence to the contrary, but most basic strategies\n        # are trivially non-empty and it would be annoying to have to override\n        # this method to show that.\n        return False\n\n    def calc_has_reusable_values(self, recur: RecurT) -> bool:\n        return False\n\n    def example(self) -> Ex:  # FIXME\n        \"\"\"Provide an example of the sort of value that this strategy generates.\n\n        This method is designed for use in a REPL, and will raise an error if\n        called from inside |@given| or a strategy definition.  For serious use,\n        see |@composite| or |st.data|.\n        \"\"\"\n        if getattr(sys, \"ps1\", None) is None and (\n            # The main module's __spec__ is None when running interactively\n            # or running a source file directly.\n            # See https://docs.python.org/3/reference/import.html#main-spec.\n            sys.modules[\"__main__\"].__spec__ is not None\n            # __spec__ is also None under pytest-xdist. To avoid an unfortunate\n            # missed alarm here, always warn under pytest.\n            or os.environ.get(\"PYTEST_CURRENT_TEST\") is not None\n        ):  # pragma: no branch\n            # The other branch *is* covered in cover/test_interactive_example.py;\n            # but as that uses `pexpect` for an interactive session `coverage`\n            # doesn't see it.\n            warnings.warn(\n                \"The `.example()` method is good for exploring strategies, but should \"\n                \"only be used interactively.  We recommend using `@given` for tests - \"\n                \"it performs better, saves and replays failures to avoid flakiness, \"\n                f\"and reports minimal examples. (strategy: {self!r})\",\n                NonInteractiveExampleWarning,\n                stacklevel=2,\n            )\n\n        context = _current_build_context.value\n        if context is not None:\n            if context.data is not None and context.data.depth > 0:\n                raise HypothesisException(\n                    \"Using example() inside a strategy definition is a bad \"\n                    \"idea. Instead consider using hypothesis.strategies.builds() \"\n                    \"or @hypothesis.strategies.composite to define your strategy.\"\n                    \" See https://hypothesis.readthedocs.io/en/latest/reference/\"\n                    \"strategies.html#hypothesis.strategies.builds or \"\n                    \"https://hypothesis.readthedocs.io/en/latest/reference/\"\n                    \"strategies.html#hypothesis.strategies.composite for more \"\n                    \"details.\"\n                )\n            else:\n                raise HypothesisException(\n                    \"Using example() inside a test function is a bad \"\n                    \"idea. Instead consider using hypothesis.strategies.data() \"\n                    \"to draw more examples during testing. See \"\n                    \"https://hypothesis.readthedocs.io/en/latest/reference/\"\n                    \"strategies.html#hypothesis.strategies.data for more details.\"\n                )\n\n        try:\n            return self.__examples.pop()\n        except (AttributeError, IndexError):\n            self.__examples: list[Ex] = []\n\n        from hypothesis.core import given\n\n        # Note: this function has a weird name because it might appear in\n        # tracebacks, and we want users to know that they can ignore it.\n        @given(self)\n        @settings(\n            database=None,\n            # generate only a few examples at a time to avoid slow interactivity\n            # for large strategies. The overhead of @given is very small relative\n            # to generation, so a small batch size is fine.\n            max_examples=10,\n            deadline=None,\n            verbosity=Verbosity.quiet,\n            phases=(Phase.generate,),\n            suppress_health_check=list(HealthCheck),\n        )\n        def example_generating_inner_function(\n            ex: Ex,  # type: ignore # mypy is overzealous in preventing covariant params\n        ) -> None:\n            self.__examples.append(ex)\n\n        example_generating_inner_function()\n        shuffle(self.__examples)\n        return self.__examples.pop()\n\n    def map(self, pack: Callable[[Ex], T]) -> \"SearchStrategy[T]\":\n        \"\"\"Returns a new strategy which generates a value from this one, and\n        then returns ``pack(value)``.  For example, ``integers().map(str)``\n        could generate ``str(5)`` == ``\"5\"``.\n        \"\"\"\n        if is_identity_function(pack):\n            return self  # type: ignore  # Mypy has no way to know that `Ex == T`\n        return MappedStrategy(self, pack=pack)\n\n    def flatmap(\n        self, expand: Callable[[Ex], \"SearchStrategy[T]\"]\n    ) -> \"SearchStrategy[T]\":  # FIXME\n        \"\"\"Old syntax for a special case of |@composite|:\n\n        .. code-block:: python\n\n            @st.composite\n            def flatmap_like(draw, base_strategy, expand):\n                value = draw(base_strategy)\n                new_strategy = expand(value)\n                return draw(new_strategy)\n\n        We find that the greater readability of |@composite| usually outweighs\n        the verbosity, with a few exceptions for simple cases or recipes like\n        ``from_type(type).flatmap(from_type)`` (\"pick a type, get a strategy for\n        any instance of that type, and then generate one of those\").\n        \"\"\"\n        from hypothesis.strategies._internal.flatmapped import FlatMapStrategy\n\n        return FlatMapStrategy(self, expand=expand)\n\n    # Note that we previously had condition extracted to a type alias as\n    # PredicateT. However, that was only useful when not specifying a relationship\n    # between the generic Ts and some other function param / return value.\n    # If we do want to - like here, where we want to say that the Ex arg to condition\n    # is of the same type as the strategy's Ex - then you need to write out the\n    # entire Callable[[Ex], Any] expression rather than use a type alias.\n    # TypeAlias is *not* simply a macro that inserts the text. TypeAlias will not\n    # reference the local TypeVar context.\n    def filter(self, condition: Callable[[Ex], Any]) -> \"SearchStrategy[Ex]\":\n        \"\"\"Returns a new strategy that generates values from this strategy\n        which satisfy the provided condition.\n\n        Note that if the condition is too hard to satisfy this might result\n        in your tests failing with an Unsatisfiable exception.\n        A basic version of the filtering logic would look something like:\n\n        .. code-block:: python\n\n            @st.composite\n            def filter_like(draw, strategy, condition):\n                for _ in range(3):\n                    value = draw(strategy)\n                    if condition(value):\n                        return value\n                assume(False)\n        \"\"\"\n        return FilteredStrategy(self, conditions=(condition,))\n\n    @property\n    def branches(self) -> Sequence[\"SearchStrategy[Ex]\"]:\n        return [self]\n\n    def __or__(self, other: \"SearchStrategy[T]\") -> \"SearchStrategy[Ex | T]\":\n        \"\"\"Return a strategy which produces values by randomly drawing from one\n        of this strategy or the other strategy.\n\n        This method is part of the public API.\n        \"\"\"\n        if not isinstance(other, SearchStrategy):\n            raise ValueError(f\"Cannot | a SearchStrategy with {other!r}\")\n\n        # Unwrap explicitly or'd strategies. This turns the\n        # common case of e.g. st.integers() | st.integers() | st.integers() from\n        #\n        #   one_of(one_of(integers(), integers()), integers())\n        #\n        # into\n        #\n        #   one_of(integers(), integers(), integers())\n        #\n        # This is purely an aesthetic unwrapping, for e.g. reprs. In practice\n        # we use .branches / .element_strategies to get the list of possible\n        # strategies, so this unwrapping is *not* necessary for correctness.\n        strategies: list[SearchStrategy] = []\n        strategies.extend(\n            self.original_strategies if isinstance(self, OneOfStrategy) else [self]\n        )\n        strategies.extend(\n            other.original_strategies if isinstance(other, OneOfStrategy) else [other]\n        )\n        return OneOfStrategy(strategies)\n\n    def __bool__(self) -> bool:\n        warnings.warn(\n            f\"bool({self!r}) is always True, did you mean to draw a value?\",\n            HypothesisWarning,\n            stacklevel=2,\n        )\n        return True\n\n    def validate(self) -> None:\n        \"\"\"Throw an exception if the strategy is not valid.\n\n        Strategies should implement ``do_validate``, which is called by this\n        method. They should not override ``validate``.\n\n        This can happen due to invalid arguments, or lazy construction.\n        \"\"\"\n        thread_id = threading.get_ident()\n        if self.validate_called.get(thread_id, False):\n            return\n        # we need to set validate_called before calling do_validate, for\n        # recursive / deferred strategies. But if a thread switches after\n        # validate_called but before do_validate, we might have a strategy\n        # which does weird things like drawing when do_validate would error but\n        # its params are technically valid (e.g. a param was passed as 1.0\n        # instead of 1) and get into weird internal states.\n        #\n        # There are two ways to fix this.\n        # (1) The first is a per-strategy lock around do_validate. Even though we\n        #   expect near-zero lock contention, this still adds the lock overhead.\n        # (2) The second is allowing concurrent .validate calls. Since validation\n        #   is (assumed to be) deterministic, both threads will produce the same\n        #   end state, so the validation order or race conditions does not matter.\n        #\n        # In order to avoid the lock overhead of (1), we use (2) here. See also\n        # discussion in https://github.com/HypothesisWorks/hypothesis/pull/4473.\n        try:\n            self.validate_called[thread_id] = True\n            self.do_validate()\n            self.is_empty\n            self.has_reusable_values\n        except Exception:\n            self.validate_called[thread_id] = False\n            raise\n\n    @property\n    def class_label(self) -> int:\n        cls = self.__class__\n        try:\n            return cls.LABELS[cls]\n        except KeyError:\n            pass\n        result = calc_label_from_cls(cls)\n        cls.LABELS[cls] = result\n        return result\n\n    @property\n    def label(self) -> int:\n        if isinstance((label := self.__label), int):\n            # avoid locking if we've already completely computed the label.\n            return label\n\n        with label_lock:\n            if self.__label is calculating:\n                return 0\n            self.__label = calculating\n            self.__label = self.calc_label()\n            return self.__label\n\n    def calc_label(self) -> int:\n        return self.class_label\n\n    def do_validate(self) -> None:\n        pass\n\n    def do_draw(self, data: ConjectureData) -> Ex:\n        raise NotImplementedError(f\"{type(self).__name__}.do_draw\")\n\n\ndef _is_hashable(value: object) -> tuple[bool, int | None]:\n    # hashing can be expensive; return the hash value if we compute it, so that\n    # callers don't have to recompute.\n    try:\n        return (True, hash(value))\n    except TypeError:\n        return (False, None)\n\n\ndef is_hashable(value: object) -> bool:\n    return _is_hashable(value)[0]\n\n\nclass SampledFromStrategy(SearchStrategy[Ex]):\n    \"\"\"A strategy which samples from a set of elements. This is essentially\n    equivalent to using a OneOfStrategy over Just strategies but may be more\n    efficient and convenient.\n    \"\"\"\n\n    _MAX_FILTER_CALLS: ClassVar[int] = 10_000\n\n    def __init__(\n        self,\n        elements: Sequence[Ex],\n        *,\n        force_repr: str | None = None,\n        force_repr_braces: tuple[str, str] | None = None,\n        transformations: tuple[\n            tuple[Literal[\"filter\", \"map\"], Callable[[Ex], Any]],\n            ...,\n        ] = (),\n    ):\n        super().__init__()\n        self.elements = cu.check_sample(elements, \"sampled_from\")\n        assert self.elements\n        self.force_repr = force_repr\n        self.force_repr_braces = force_repr_braces\n        self._transformations = transformations\n\n        self._cached_repr: str | None = None\n\n    def map(self, pack: Callable[[Ex], T]) -> SearchStrategy[T]:\n        s = type(self)(\n            self.elements,\n            force_repr=self.force_repr,\n            force_repr_braces=self.force_repr_braces,\n            transformations=(*self._transformations, (\"map\", pack)),\n        )\n        # guaranteed by the (\"map\", pack) transformation\n        return cast(SearchStrategy[T], s)\n\n    def filter(self, condition: Callable[[Ex], Any]) -> SearchStrategy[Ex]:\n        return type(self)(\n            self.elements,\n            force_repr=self.force_repr,\n            force_repr_braces=self.force_repr_braces,\n            transformations=(*self._transformations, (\"filter\", condition)),\n        )\n\n    def __repr__(self):\n        if self._cached_repr is None:\n            rep = get_pretty_function_description\n            elements_s = (\n                \", \".join(rep(v) for v in self.elements[:512]) + \", ...\"\n                if len(self.elements) > 512\n                else \", \".join(rep(v) for v in self.elements)\n            )\n            braces = self.force_repr_braces or (\"(\", \")\")\n            instance_s = (\n                self.force_repr or f\"sampled_from({braces[0]}{elements_s}{braces[1]})\"\n            )\n            transforms_s = \"\".join(\n                f\".{name}({get_pretty_function_description(f)})\"\n                for name, f in self._transformations\n            )\n            repr_s = instance_s + transforms_s\n            self._cached_repr = repr_s\n        return self._cached_repr\n\n    def calc_label(self) -> int:\n        # strategy.label is effectively an under-approximation of structural\n        # equality (i.e., some strategies may have the same label when they are not\n        # structurally identical). More importantly for calculating the\n        # SampledFromStrategy label, we might have hash(s1) != hash(s2) even\n        # when s1 and s2 are structurally identical. For instance:\n        #\n        #   s1 = st.sampled_from([st.none()])\n        #   s2 = st.sampled_from([st.none()])\n        #   assert hash(s1) != hash(s2)\n        #\n        # (see also test cases in test_labels.py).\n        #\n        # We therefore use the labels of any component strategies when calculating\n        # our label, and only use the hash if it is not a strategy.\n        #\n        # That's the ideal, anyway. In reality the logic is more complicated than\n        # necessary in order to be efficient in the presence of (very) large sequences:\n        # * add an unabashed special case for range, to avoid iteration over an\n        #   enormous range when we know it is entirely integers.\n        # * if there is at least one strategy in self.elements, use strategy label,\n        #   and the element hash otherwise.\n        # * if there are no strategies in self.elements, take the hash of the\n        #   entire sequence. This prevents worst-case performance of hashing each\n        #   element when a hash of the entire sequence would have sufficed.\n        #\n        # The worst case performance of this scheme is\n        # itertools.chain(range(2**100), [st.none()]), where it degrades to\n        # hashing every int in the range.\n        (elements_is_hashable, hash_value) = _is_hashable(self.elements)\n        if isinstance(self.elements, range) or (\n            elements_is_hashable\n            and not any(isinstance(e, SearchStrategy) for e in self.elements)\n        ):\n            return combine_labels(\n                self.class_label, calc_label_from_name(str(hash_value))\n            )\n\n        labels = [self.class_label]\n        for element in self.elements:\n            if not is_hashable(element):\n                continue\n\n            labels.append(\n                element.label\n                if isinstance(element, SearchStrategy)\n                else calc_label_from_hash(element)\n            )\n\n        return combine_labels(*labels)\n\n    def calc_has_reusable_values(self, recur: RecurT) -> bool:\n        # Because our custom .map/.filter implementations skip the normal\n        # wrapper strategies (which would automatically return False for us),\n        # we need to manually return False here if any transformations have\n        # been applied.\n        return not self._transformations\n\n    def calc_is_cacheable(self, recur: RecurT) -> bool:\n        return is_hashable(self.elements)\n\n    def _transform(\n        self,\n        # https://github.com/python/mypy/issues/7049, we're not writing `element`\n        # anywhere in the class so this is still type-safe. mypy is being more\n        # conservative than necessary\n        element: Ex,  # type: ignore\n    ) -> Ex | UniqueIdentifier:\n        # Used in UniqueSampledListStrategy\n        for name, f in self._transformations:\n            if name == \"map\":\n                result = f(element)\n                if build_context := _current_build_context.value:\n                    build_context.record_call(result, f, args=[element], kwargs={})\n                element = result\n            else:\n                assert name == \"filter\"\n                if not f(element):\n                    return filter_not_satisfied\n        return element\n\n    def do_draw(self, data: ConjectureData) -> Ex:\n        result = self.do_filtered_draw(data)\n        if isinstance(result, SearchStrategy) and all(\n            isinstance(x, SearchStrategy) for x in self.elements\n        ):\n            data._sampled_from_all_strategies_elements_message = (\n                \"sampled_from was given a collection of strategies: \"\n                \"{!r}. Was one_of intended?\",\n                self.elements,\n            )\n        if result is filter_not_satisfied:\n            data.mark_invalid(f\"Aborted test because unable to satisfy {self!r}\")\n        assert not isinstance(result, UniqueIdentifier)\n        return result\n\n    def get_element(self, i: int) -> Ex | UniqueIdentifier:\n        return self._transform(self.elements[i])\n\n    def do_filtered_draw(self, data: ConjectureData) -> Ex | UniqueIdentifier:\n        # Set of indices that have been tried so far, so that we never test\n        # the same element twice during a draw.\n        known_bad_indices: set[int] = set()\n\n        # Start with ordinary rejection sampling. It's fast if it works, and\n        # if it doesn't work then it was only a small amount of overhead.\n        for _ in range(3):\n            i = data.draw_integer(0, len(self.elements) - 1)\n            if i not in known_bad_indices:\n                element = self.get_element(i)\n                if element is not filter_not_satisfied:\n                    return element\n                if not known_bad_indices:\n                    data.events[f\"Retried draw from {self!r} to satisfy filter\"] = \"\"\n                known_bad_indices.add(i)\n\n        # If we've tried all the possible elements, give up now.\n        max_good_indices = len(self.elements) - len(known_bad_indices)\n        if not max_good_indices:\n            return filter_not_satisfied\n\n        # Impose an arbitrary cutoff to prevent us from wasting too much time\n        # on very large element lists.\n        max_good_indices = min(max_good_indices, self._MAX_FILTER_CALLS - 3)\n\n        # Before building the list of allowed indices, speculatively choose\n        # one of them. We don't yet know how many allowed indices there will be,\n        # so this choice might be out-of-bounds, but that's OK.\n        speculative_index = data.draw_integer(0, max_good_indices - 1)\n\n        # Calculate the indices of allowed values, so that we can choose one\n        # of them at random. But if we encounter the speculatively-chosen one,\n        # just use that and return immediately.  Note that we also track the\n        # allowed elements, in case of .map(some_stateful_function)\n        allowed: list[tuple[int, Ex]] = []\n        for i in range(min(len(self.elements), self._MAX_FILTER_CALLS - 3)):\n            if i not in known_bad_indices:\n                element = self.get_element(i)\n                if element is not filter_not_satisfied:\n                    assert not isinstance(element, UniqueIdentifier)\n                    allowed.append((i, element))\n                    if len(allowed) > speculative_index:\n                        # Early-exit case: We reached the speculative index, so\n                        # we just return the corresponding element.\n                        data.draw_integer(0, len(self.elements) - 1, forced=i)\n                        return element\n\n        # The speculative index didn't work out, but at this point we've built\n        # and can choose from the complete list of allowed indices and elements.\n        if allowed:\n            i, element = data.choice(allowed)\n            data.draw_integer(0, len(self.elements) - 1, forced=i)\n            return element\n        # If there are no allowed indices, the filter couldn't be satisfied.\n        return filter_not_satisfied\n\n\nclass OneOfStrategy(SearchStrategy[Ex]):\n    \"\"\"Implements a union of strategies. Given a number of strategies this\n    generates values which could have come from any of them.\n\n    The conditional distribution draws uniformly at random from some\n    non-empty subset of these strategies and then draws from the\n    conditional distribution of that strategy.\n    \"\"\"\n\n    def __init__(self, strategies: Sequence[SearchStrategy[Ex]]):\n        super().__init__()\n        self.original_strategies = tuple(strategies)\n        self.__element_strategies: Sequence[SearchStrategy[Ex]] | None = None\n        self.__in_branches = False\n        self._branches_lock = RLock()\n\n    def calc_is_empty(self, recur: RecurT) -> bool:\n        return all(recur(e) for e in self.original_strategies)\n\n    def calc_has_reusable_values(self, recur: RecurT) -> bool:\n        return all(recur(e) for e in self.original_strategies)\n\n    def calc_is_cacheable(self, recur: RecurT) -> bool:\n        return all(recur(e) for e in self.original_strategies)\n\n    @property\n    def element_strategies(self) -> Sequence[SearchStrategy[Ex]]:\n        if self.__element_strategies is None:\n            # While strategies are hashable, they use object.__hash__ and are\n            # therefore distinguished only by identity.\n            #\n            # In principle we could \"just\" define a __hash__ method\n            # (and __eq__, but that's easy in terms of type() and hash())\n            # to make this more powerful, but this is harder than it sounds:\n            #\n            # 1. Strategies are often distinguished by non-hashable attributes,\n            #    or by attributes that have the same hash value (\"^.+\" / b\"^.+\").\n            # 2. LazyStrategy: can't reify the wrapped strategy without breaking\n            #    laziness, so there's a hash each for the lazy and the nonlazy.\n            #\n            # Having made several attempts, the minor benefits of making strategies\n            # hashable are simply not worth the engineering effort it would take.\n            # See also issues #2291 and #2327.\n            seen: set[SearchStrategy] = {self}\n            strategies: list[SearchStrategy] = []\n            for arg in self.original_strategies:\n                check_strategy(arg)\n                if not arg.is_empty:\n                    for s in arg.branches:\n                        if s not in seen and not s.is_empty:\n                            seen.add(s)\n                            strategies.append(s)\n            self.__element_strategies = strategies\n        return self.__element_strategies\n\n    def calc_label(self) -> int:\n        return combine_labels(\n            self.class_label, *(p.label for p in self.original_strategies)\n        )\n\n    def do_draw(self, data: ConjectureData) -> Ex:\n        strategy = data.draw(\n            SampledFromStrategy(self.element_strategies).filter(\n                lambda s: not s.is_currently_empty(data)\n            )\n        )\n        return data.draw(strategy)\n\n    def __repr__(self) -> str:\n        return \"one_of({})\".format(\", \".join(map(repr, self.original_strategies)))\n\n    def do_validate(self) -> None:\n        for e in self.element_strategies:\n            e.validate()\n\n    @property\n    def branches(self) -> Sequence[SearchStrategy[Ex]]:\n        if self.__element_strategies is not None:\n            # common fast path which avoids the lock\n            return self.element_strategies\n\n        with self._branches_lock:\n            if not self.__in_branches:\n                try:\n                    self.__in_branches = True\n                    return self.element_strategies\n                finally:\n                    self.__in_branches = False\n            else:\n                return [self]\n\n    def filter(self, condition: Callable[[Ex], Any]) -> SearchStrategy[Ex]:\n        return FilteredStrategy(\n            OneOfStrategy([s.filter(condition) for s in self.original_strategies]),\n            conditions=(),\n        )\n\n\n@overload\ndef one_of(\n    __args: Sequence[SearchStrategy[Ex]],\n) -> SearchStrategy[Ex]:  # pragma: no cover\n    ...\n\n\n@overload\ndef one_of(__a1: SearchStrategy[Ex]) -> SearchStrategy[Ex]:  # pragma: no cover\n    ...\n\n\n@overload\ndef one_of(\n    __a1: SearchStrategy[Ex], __a2: SearchStrategy[T]\n) -> SearchStrategy[Ex | T]:  # pragma: no cover\n    ...\n\n\n@overload\ndef one_of(\n    __a1: SearchStrategy[Ex], __a2: SearchStrategy[T], __a3: SearchStrategy[T3]\n) -> SearchStrategy[Ex | T | T3]:  # pragma: no cover\n    ...\n\n\n@overload\ndef one_of(\n    __a1: SearchStrategy[Ex],\n    __a2: SearchStrategy[T],\n    __a3: SearchStrategy[T3],\n    __a4: SearchStrategy[T4],\n) -> SearchStrategy[Ex | T | T3 | T4]:  # pragma: no cover\n    ...\n\n\n@overload\ndef one_of(\n    __a1: SearchStrategy[Ex],\n    __a2: SearchStrategy[T],\n    __a3: SearchStrategy[T3],\n    __a4: SearchStrategy[T4],\n    __a5: SearchStrategy[T5],\n) -> SearchStrategy[Ex | T | T3 | T4 | T5]:  # pragma: no cover\n    ...\n\n\n@overload\ndef one_of(*args: SearchStrategy[Any]) -> SearchStrategy[Any]:  # pragma: no cover\n    ...\n\n\n@defines_strategy(eager=True)\ndef one_of(\n    *args: Sequence[SearchStrategy[Any]] | SearchStrategy[Any],\n) -> SearchStrategy[Any]:\n    # Mypy workaround alert:  Any is too loose above; the return parameter\n    # should be the union of the input parameters.  Unfortunately, Mypy <=0.600\n    # raises errors due to incompatible inputs instead.  See #1270 for links.\n    # v0.610 doesn't error; it gets inference wrong for 2+ arguments instead.\n    \"\"\"Return a strategy which generates values from any of the argument\n    strategies.\n\n    This may be called with one iterable argument instead of multiple\n    strategy arguments, in which case ``one_of(x)`` and ``one_of(*x)`` are\n    equivalent.\n\n    Examples from this strategy will generally shrink to ones that come from\n    strategies earlier in the list, then shrink according to behaviour of the\n    strategy that produced them. In order to get good shrinking behaviour,\n    try to put simpler strategies first. e.g. ``one_of(none(), text())`` is\n    better than ``one_of(text(), none())``.\n\n    This is especially important when using recursive strategies. e.g.\n    ``x = st.deferred(lambda: st.none() | st.tuples(x, x))`` will shrink well,\n    but ``x = st.deferred(lambda: st.tuples(x, x) | st.none())`` will shrink\n    very badly indeed.\n    \"\"\"\n    if len(args) == 1 and not isinstance(args[0], SearchStrategy):\n        try:\n            args = tuple(args[0])\n        except TypeError:\n            pass\n    if len(args) == 1 and isinstance(args[0], SearchStrategy):\n        # This special-case means that we can one_of over lists of any size\n        # without incurring any performance overhead when there is only one\n        # strategy, and keeps our reprs simple.\n        return args[0]\n    if args and not any(isinstance(a, SearchStrategy) for a in args):\n        # And this special case is to give a more-specific error message if it\n        # seems that the user has confused `one_of()` for  `sampled_from()`;\n        # the remaining validation is left to OneOfStrategy.  See PR #2627.\n        raise InvalidArgument(\n            f\"Did you mean st.sampled_from({list(args)!r})?  st.one_of() is used \"\n            \"to combine strategies, but all of the arguments were of other types.\"\n        )\n    # we've handled the case where args is a one-element sequence [(s1, s2, ...)]\n    # above, so we can assume it's an actual sequence of strategies.\n    args = cast(Sequence[SearchStrategy], args)\n    return OneOfStrategy(args)\n\n\nclass MappedStrategy(SearchStrategy[MappedTo], Generic[MappedFrom, MappedTo]):\n    \"\"\"A strategy which is defined purely by conversion to and from another\n    strategy.\n\n    Its parameter and distribution come from that other strategy.\n    \"\"\"\n\n    def __init__(\n        self,\n        strategy: SearchStrategy[MappedFrom],\n        pack: Callable[[MappedFrom], MappedTo],\n    ) -> None:\n        super().__init__()\n        self.mapped_strategy = strategy\n        self.pack = pack\n\n    def calc_is_empty(self, recur: RecurT) -> bool:\n        return recur(self.mapped_strategy)\n\n    def calc_is_cacheable(self, recur: RecurT) -> bool:\n        return recur(self.mapped_strategy)\n\n    def __repr__(self) -> str:\n        if not hasattr(self, \"_cached_repr\"):\n            self._cached_repr = f\"{self.mapped_strategy!r}.map({get_pretty_function_description(self.pack)})\"\n        return self._cached_repr\n\n    def do_validate(self) -> None:\n        self.mapped_strategy.validate()\n\n    def do_draw(self, data: ConjectureData) -> MappedTo:\n        with warnings.catch_warnings():\n            if isinstance(self.pack, type) and issubclass(\n                self.pack, (abc.Mapping, abc.Set)\n            ):\n                warnings.simplefilter(\"ignore\", BytesWarning)\n            for _ in range(3):\n                try:\n                    data.start_span(MAPPED_SEARCH_STRATEGY_DO_DRAW_LABEL)\n                    x = data.draw(self.mapped_strategy)\n                    result = self.pack(x)\n                    data.stop_span()\n                    current_build_context().record_call(\n                        result, self.pack, args=[x], kwargs={}\n                    )\n                    return result\n                except UnsatisfiedAssumption:\n                    data.stop_span(discard=True)\n        raise UnsatisfiedAssumption\n\n    @property\n    def branches(self) -> Sequence[SearchStrategy[MappedTo]]:\n        return [\n            MappedStrategy(strategy, pack=self.pack)\n            for strategy in self.mapped_strategy.branches\n        ]\n\n    def filter(\n        self, condition: Callable[[MappedTo], Any]\n    ) -> \"SearchStrategy[MappedTo]\":\n        # Includes a special case so that we can rewrite filters on collection\n        # lengths, when most collections are `st.lists(...).map(the_type)`.\n        ListStrategy = _list_strategy_type()\n        if not isinstance(self.mapped_strategy, ListStrategy) or not (\n            (isinstance(self.pack, type) and issubclass(self.pack, abc.Collection))\n            or self.pack in _collection_ish_functions()\n        ):\n            return super().filter(condition)\n\n        # Check whether our inner list strategy can rewrite this filter condition.\n        # If not, discard the result and _only_ apply a new outer filter.\n        new = ListStrategy.filter(self.mapped_strategy, condition)\n        if getattr(new, \"filtered_strategy\", None) is self.mapped_strategy:\n            return super().filter(condition)  # didn't rewrite\n\n        # Apply a new outer filter even though we rewrote the inner strategy,\n        # because some collections can change the list length (dict, set, etc).\n        return FilteredStrategy(type(self)(new, self.pack), conditions=(condition,))\n\n\n@lru_cache\ndef _list_strategy_type() -> Any:\n    from hypothesis.strategies._internal.collections import ListStrategy\n\n    return ListStrategy\n\n\ndef _collection_ish_functions() -> Sequence[Any]:\n    funcs = [sorted]\n    if np := sys.modules.get(\"numpy\"):\n        # c.f. https://numpy.org/doc/stable/reference/routines.array-creation.html\n        # Probably only `np.array` and `np.asarray` will be used in practice,\n        # but why should that stop us when we've already gone this far?\n        funcs += [\n            np.empty_like,\n            np.eye,\n            np.identity,\n            np.ones_like,\n            np.zeros_like,\n            np.array,\n            np.asarray,\n            np.asanyarray,\n            np.ascontiguousarray,\n            np.asmatrix,\n            np.copy,\n            np.rec.array,\n            np.rec.fromarrays,\n            np.rec.fromrecords,\n            np.diag,\n            # bonus undocumented functions from tab-completion:\n            np.asarray_chkfinite,\n            np.asfortranarray,\n        ]\n\n    return funcs\n\n\nfilter_not_satisfied = UniqueIdentifier(\"filter not satisfied\")\n\n\nclass FilteredStrategy(SearchStrategy[Ex]):\n    def __init__(\n        self, strategy: SearchStrategy[Ex], conditions: tuple[Callable[[Ex], Any], ...]\n    ):\n        super().__init__()\n        if isinstance(strategy, FilteredStrategy):\n            # Flatten chained filters into a single filter with multiple conditions.\n            self.flat_conditions: tuple[Callable[[Ex], Any], ...] = (\n                strategy.flat_conditions + conditions\n            )\n            self.filtered_strategy: SearchStrategy[Ex] = strategy.filtered_strategy\n        else:\n            self.flat_conditions = conditions\n            self.filtered_strategy = strategy\n\n        assert isinstance(self.flat_conditions, tuple)\n        assert not isinstance(self.filtered_strategy, FilteredStrategy)\n\n        self.__condition: Callable[[Ex], Any] | None = None\n\n    def calc_is_empty(self, recur: RecurT) -> bool:\n        return recur(self.filtered_strategy)\n\n    def calc_is_cacheable(self, recur: RecurT) -> bool:\n        return recur(self.filtered_strategy)\n\n    def __repr__(self) -> str:\n        if not hasattr(self, \"_cached_repr\"):\n            self._cached_repr = \"{!r}{}\".format(\n                self.filtered_strategy,\n                \"\".join(\n                    f\".filter({get_pretty_function_description(cond)})\"\n                    for cond in self.flat_conditions\n                ),\n            )\n        return self._cached_repr\n\n    def do_validate(self) -> None:\n        # Start by validating our inner filtered_strategy.  If this was a LazyStrategy,\n        # validation also reifies it so that subsequent calls to e.g. `.filter()` will\n        # be passed through.\n        self.filtered_strategy.validate()\n        # So now we have a reified inner strategy, we'll replay all our saved\n        # predicates in case some or all of them can be rewritten.  Note that this\n        # replaces the `fresh` strategy too!\n        fresh = self.filtered_strategy\n        for cond in self.flat_conditions:\n            fresh = fresh.filter(cond)\n        if isinstance(fresh, FilteredStrategy):\n            # In this case we have at least some non-rewritten filter predicates,\n            # so we just re-initialize the strategy.\n            FilteredStrategy.__init__(\n                self, fresh.filtered_strategy, fresh.flat_conditions\n            )\n        else:\n            # But if *all* the predicates were rewritten... well, do_validate() is\n            # an in-place method so we still just re-initialize the strategy!\n            FilteredStrategy.__init__(self, fresh, ())\n\n    def filter(self, condition: Callable[[Ex], Any]) -> \"FilteredStrategy[Ex]\":\n        # If we can, it's more efficient to rewrite our strategy to satisfy the\n        # condition.  We therefore exploit the fact that the order of predicates\n        # doesn't matter (`f(x) and g(x) == g(x) and f(x)`) by attempting to apply\n        # condition directly to our filtered strategy as the inner-most filter.\n        out = self.filtered_strategy.filter(condition)\n        # If it couldn't be rewritten, we'll get a new FilteredStrategy - and then\n        # combine the conditions of each in our expected newest=last order.\n        if isinstance(out, FilteredStrategy):\n            return FilteredStrategy(\n                out.filtered_strategy, self.flat_conditions + out.flat_conditions\n            )\n        # But if it *could* be rewritten, we can return the more efficient form!\n        return FilteredStrategy(out, self.flat_conditions)\n\n    @property\n    def condition(self) -> Callable[[Ex], Any]:\n        # We write this defensively to avoid any threading race conditions\n        # with our manual FilteredStrategy.__init__ for filter-rewriting.\n        # See https://github.com/HypothesisWorks/hypothesis/pull/4522.\n        if (condition := self.__condition) is not None:\n            return condition\n\n        if len(self.flat_conditions) == 1:\n            # Avoid an extra indirection in the common case of only one condition.\n            condition = self.flat_conditions[0]\n        elif len(self.flat_conditions) == 0:\n            # Possible, if unlikely, due to filter predicate rewriting\n            condition = lambda _: True  # type: ignore # covariant type param\n        else:\n            condition = lambda x: all(  # type: ignore # covariant type param\n                cond(x) for cond in self.flat_conditions\n            )\n        self.__condition = condition\n        return condition\n\n    def do_draw(self, data: ConjectureData) -> Ex:\n        result = self.do_filtered_draw(data)\n        if result is not filter_not_satisfied:\n            return cast(Ex, result)\n\n        data.mark_invalid(f\"Aborted test because unable to satisfy {self!r}\")\n\n    def do_filtered_draw(self, data: ConjectureData) -> Ex | UniqueIdentifier:\n        for i in range(3):\n            data.start_span(FILTERED_SEARCH_STRATEGY_DO_DRAW_LABEL)\n            value = data.draw(self.filtered_strategy)\n            if self.condition(value):\n                data.stop_span()\n                return value\n            else:\n                data.stop_span(discard=True)\n                if i == 0:\n                    data.events[f\"Retried draw from {self!r} to satisfy filter\"] = \"\"\n\n        return filter_not_satisfied\n\n    @property\n    def branches(self) -> Sequence[SearchStrategy[Ex]]:\n        return [\n            FilteredStrategy(strategy=strategy, conditions=self.flat_conditions)\n            for strategy in self.filtered_strategy.branches\n        ]\n\n\n@check_function\ndef check_strategy(arg: object, name: str = \"\") -> None:\n    assert isinstance(name, str)\n    if not isinstance(arg, SearchStrategy):\n        hint = \"\"\n        if isinstance(arg, (list, tuple)):\n            hint = \", such as st.sampled_from({}),\".format(name or \"...\")\n        if name:\n            name += \"=\"\n        raise InvalidArgument(\n            f\"Expected a SearchStrategy{hint} but got {name}{arg!r} \"\n            f\"(type={type(arg).__name__})\"\n        )\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/strings.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport copy\nimport re\nimport warnings\nfrom collections.abc import Collection\nfrom functools import cache, lru_cache, partial\nfrom typing import cast\n\nfrom hypothesis.errors import HypothesisWarning, InvalidArgument\nfrom hypothesis.internal import charmap\nfrom hypothesis.internal.charmap import Categories\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.conjecture.providers import COLLECTION_DEFAULT_MAX_SIZE\nfrom hypothesis.internal.filtering import max_len, min_len\nfrom hypothesis.internal.intervalsets import IntervalSet\nfrom hypothesis.internal.reflection import get_pretty_function_description\nfrom hypothesis.strategies._internal.collections import ListStrategy\nfrom hypothesis.strategies._internal.lazy import unwrap_strategies\nfrom hypothesis.strategies._internal.strategies import (\n    OneOfStrategy,\n    SampledFromStrategy,\n    SearchStrategy,\n)\nfrom hypothesis.vendor.pretty import pretty\n\n\n# Cache size is limited by sys.maxunicode, but passing None makes it slightly faster.\n@cache\n# this is part of our forward-facing validation, so we do *not* tell mypyc that c\n# should be a str, because we don't want it to validate it before we can.\ndef _check_is_single_character(c: object) -> str:\n    # In order to mitigate the performance cost of this check, we use a shared cache,\n    # even at the cost of showing the culprit strategy in the error message.\n    if not isinstance(c, str):\n        type_ = get_pretty_function_description(type(c))\n        raise InvalidArgument(f\"Got non-string {c!r} (type {type_})\")\n    if len(c) != 1:\n        raise InvalidArgument(f\"Got {c!r} (length {len(c)} != 1)\")\n    return c\n\n\nclass OneCharStringStrategy(SearchStrategy[str]):\n    \"\"\"A strategy which generates single character strings of text type.\"\"\"\n\n    def __init__(self, intervals: IntervalSet, force_repr: str | None = None) -> None:\n        super().__init__()\n        assert isinstance(intervals, IntervalSet)\n        self.intervals = intervals\n        self._force_repr = force_repr\n\n    @classmethod\n    def from_characters_args(\n        cls,\n        *,\n        codec: str | None = None,\n        min_codepoint: int | None = None,\n        max_codepoint: int | None = None,\n        categories: Categories | None = None,\n        exclude_characters: Collection[str] = \"\",\n        include_characters: Collection[str] = \"\",\n    ) -> \"OneCharStringStrategy\":\n        assert set(categories or ()).issubset(charmap.categories())\n        intervals = charmap.query(\n            min_codepoint=min_codepoint,\n            max_codepoint=max_codepoint,\n            categories=categories,\n            exclude_characters=exclude_characters,\n            include_characters=include_characters,\n        )\n        if codec is not None:\n            intervals &= charmap.intervals_from_codec(codec)\n\n        _arg_repr = \", \".join(\n            f\"{k}={v!r}\"\n            for k, v in [\n                (\"codec\", codec),\n                (\"min_codepoint\", min_codepoint),\n                (\"max_codepoint\", max_codepoint),\n                (\"categories\", categories),\n                (\"exclude_characters\", exclude_characters),\n                (\"include_characters\", include_characters),\n            ]\n            if v not in (None, \"\")\n            and not (\n                k == \"categories\"\n                # v has to be `categories` here. Help mypy along to infer that.\n                and set(cast(Categories, v)) == set(charmap.categories()) - {\"Cs\"}\n            )\n        )\n        if not intervals:\n            raise InvalidArgument(\n                \"No characters are allowed to be generated by this \"\n                f\"combination of arguments: {_arg_repr}\"\n            )\n        return cls(intervals, force_repr=f\"characters({_arg_repr})\")\n\n    @classmethod\n    def from_alphabet(cls, alphabet: str | SearchStrategy) -> \"OneCharStringStrategy\":\n        if isinstance(alphabet, str):\n            return cls.from_characters_args(categories=(), include_characters=alphabet)\n\n        assert isinstance(alphabet, SearchStrategy)\n        char_strategy = unwrap_strategies(alphabet)\n        if isinstance(char_strategy, cls):\n            return char_strategy\n        elif isinstance(char_strategy, SampledFromStrategy):\n            for c in char_strategy.elements:\n                _check_is_single_character(c)\n            return cls.from_characters_args(\n                categories=(),\n                include_characters=char_strategy.elements,\n            )\n        elif isinstance(char_strategy, OneOfStrategy):\n            intervals = IntervalSet()\n            for s in char_strategy.element_strategies:\n                intervals = intervals.union(cls.from_alphabet(s).intervals)\n            return cls(intervals, force_repr=repr(alphabet))\n        raise InvalidArgument(\n            f\"{alphabet=} must be a sampled_from() or characters() strategy\"\n        )\n\n    def __repr__(self) -> str:\n        return self._force_repr or f\"OneCharStringStrategy({self.intervals!r})\"\n\n    def do_draw(self, data: ConjectureData) -> str:\n        return data.draw_string(self.intervals, min_size=1, max_size=1)\n\n\n_nonempty_names = (\n    \"capitalize\",\n    \"expandtabs\",\n    \"join\",\n    \"lower\",\n    \"rsplit\",\n    \"split\",\n    \"splitlines\",\n    \"swapcase\",\n    \"title\",\n    \"upper\",\n)\n_nonempty_and_content_names = (\n    \"islower\",\n    \"isupper\",\n    \"isalnum\",\n    \"isalpha\",\n    \"isascii\",\n    \"isdigit\",\n    \"isspace\",\n    \"istitle\",\n    \"lstrip\",\n    \"rstrip\",\n    \"strip\",\n)\n\n\nclass TextStrategy(ListStrategy[str]):\n    def do_draw(self, data):\n        # if our element strategy is OneCharStringStrategy, we can skip the\n        # ListStrategy draw and jump right to data.draw_string.\n        # Doing so for user-provided element strategies is not correct in\n        # general, as they may define a different distribution than data.draw_string.\n        elems = unwrap_strategies(self.element_strategy)\n        if isinstance(elems, OneCharStringStrategy):\n            return data.draw_string(\n                elems.intervals,\n                min_size=self.min_size,\n                max_size=(\n                    COLLECTION_DEFAULT_MAX_SIZE\n                    if self.max_size == float(\"inf\")\n                    else self.max_size\n                ),\n            )\n        return \"\".join(super().do_draw(data))\n\n    def __repr__(self) -> str:\n        args = []\n        if repr(self.element_strategy) != \"characters()\":\n            args.append(repr(self.element_strategy))\n        if self.min_size:\n            args.append(f\"min_size={self.min_size}\")\n        if self.max_size < float(\"inf\"):\n            args.append(f\"max_size={self.max_size}\")\n        return f\"text({', '.join(args)})\"\n\n    # See https://docs.python.org/3/library/stdtypes.html#string-methods\n    # These methods always return Truthy values for any nonempty string.\n    _nonempty_filters = (\n        *ListStrategy._nonempty_filters,\n        str,\n        str.casefold,\n        str.encode,\n        *(getattr(str, n) for n in _nonempty_names),\n    )\n    _nonempty_and_content_filters = (\n        str.isdecimal,\n        str.isnumeric,\n        *(getattr(str, n) for n in _nonempty_and_content_names),\n    )\n\n    def filter(self, condition):\n        elems = unwrap_strategies(self.element_strategy)\n        if (\n            condition is str.isidentifier\n            and self.max_size >= 1\n            and isinstance(elems, OneCharStringStrategy)\n        ):\n            from hypothesis.strategies import builds, nothing\n\n            id_start, id_continue = _identifier_characters()\n            if not (elems.intervals & id_start):\n                return nothing()\n            return builds(\n                \"{}{}\".format,\n                OneCharStringStrategy(elems.intervals & id_start),\n                TextStrategy(\n                    OneCharStringStrategy(elems.intervals & id_continue),\n                    min_size=max(0, self.min_size - 1),\n                    max_size=self.max_size - 1,\n                ),\n                # Filter to ensure that NFKC normalization keeps working in future\n            ).filter(str.isidentifier)\n        if (new := _string_filter_rewrite(self, str, condition)) is not None:\n            return new\n        return super().filter(condition)\n\n\ndef _string_filter_rewrite(self, kind, condition):\n    if condition in (kind.lower, kind.title, kind.upper):\n        k = kind.__name__\n        warnings.warn(\n            f\"You applied {k}.{condition.__name__} as a filter, but this allows \"\n            f\"all nonempty strings!  Did you mean {k}.is{condition.__name__}?\",\n            HypothesisWarning,\n            stacklevel=2,\n        )\n\n    if (\n        (\n            kind is bytes\n            or isinstance(\n                unwrap_strategies(self.element_strategy), OneCharStringStrategy\n            )\n        )\n        and isinstance(pattern := getattr(condition, \"__self__\", None), re.Pattern)\n        and isinstance(pattern.pattern, kind)\n    ):\n        from hypothesis.strategies._internal.regex import regex_strategy\n\n        if condition.__name__ == \"match\":\n            # Replace with an easier-to-handle equivalent condition\n            caret, close = (\"^(?:\", \")\") if kind is str else (b\"^(?:\", b\")\")\n            pattern = re.compile(caret + pattern.pattern + close, flags=pattern.flags)\n            condition = pattern.search\n\n        if condition.__name__ in (\"search\", \"findall\", \"fullmatch\"):\n            s = regex_strategy(\n                pattern,\n                fullmatch=condition.__name__ == \"fullmatch\",\n                alphabet=self.element_strategy if kind is str else None,\n            )\n            if self.min_size > 0:\n                s = s.filter(partial(min_len, self.min_size))\n            if self.max_size < 1e999:\n                s = s.filter(partial(max_len, self.max_size))\n            return s\n        elif condition.__name__ in (\"finditer\", \"scanner\"):\n            # PyPy implements `finditer` as an alias to their `scanner` method\n            warnings.warn(\n                f\"You applied {pretty(condition)} as a filter, but this allows \"\n                f\"any string at all!  Did you mean .findall ?\",\n                HypothesisWarning,\n                stacklevel=3,\n            )\n            return self\n        elif condition.__name__ == \"split\":\n            warnings.warn(\n                f\"You applied {pretty(condition)} as a filter, but this allows \"\n                f\"any nonempty string!  Did you mean .search ?\",\n                HypothesisWarning,\n                stacklevel=3,\n            )\n            return self.filter(bool)\n\n    # We use ListStrategy filter logic for the conditions that *only* imply\n    # the string is nonempty.  Here, we increment the min_size but still apply\n    # the filter for conditions that imply nonempty *and specific contents*.\n    if condition in self._nonempty_and_content_filters and self.max_size >= 1:\n        self = copy.copy(self)\n        self.min_size = max(1, self.min_size)\n        return ListStrategy.filter(self, condition)\n\n    return None\n\n\n# Excerpted from https://www.unicode.org/Public/15.0.0/ucd/PropList.txt\n# Python updates it's Unicode version between minor releases, but fortunately\n# these properties do not change between the Unicode versions in question.\n_PROPLIST = \"\"\"\n# ================================================\n\n1885..1886    ; Other_ID_Start # Mn   [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA\n2118          ; Other_ID_Start # Sm       SCRIPT CAPITAL P\n212E          ; Other_ID_Start # So       ESTIMATED SYMBOL\n309B..309C    ; Other_ID_Start # Sk   [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK\n\n# Total code points: 6\n\n# ================================================\n\n00B7          ; Other_ID_Continue # Po       MIDDLE DOT\n0387          ; Other_ID_Continue # Po       GREEK ANO TELEIA\n1369..1371    ; Other_ID_Continue # No   [9] ETHIOPIC DIGIT ONE..ETHIOPIC DIGIT NINE\n19DA          ; Other_ID_Continue # No       NEW TAI LUE THAM DIGIT ONE\n\n# Total code points: 12\n\"\"\"\n\n\n@lru_cache\ndef _identifier_characters() -> tuple[IntervalSet, IntervalSet]:\n    \"\"\"See https://docs.python.org/3/reference/lexical_analysis.html#identifiers\"\"\"\n    # Start by computing the set of special characters\n    chars = {\"Other_ID_Start\": \"\", \"Other_ID_Continue\": \"\"}\n    for line in _PROPLIST.splitlines():\n        if m := re.match(r\"([0-9A-F.]+) +; (\\w+) # \", line):\n            codes, prop = m.groups()\n            span = range(int(codes[:4], base=16), int(codes[-4:], base=16) + 1)\n            chars[prop] += \"\".join(chr(x) for x in span)\n\n    # Then get the basic set by Unicode category and known extras\n    id_start = charmap.query(\n        categories=(\"Lu\", \"Ll\", \"Lt\", \"Lm\", \"Lo\", \"Nl\"),\n        include_characters=\"_\" + chars[\"Other_ID_Start\"],\n    )\n    id_start -= IntervalSet.from_string(\n        # Magic value: the characters which NFKC-normalize to be invalid identifiers.\n        # Conveniently they're all in `id_start`, so we only need to do this once.\n        \"\\u037a\\u0e33\\u0eb3\\u2e2f\\u309b\\u309c\\ufc5e\\ufc5f\\ufc60\\ufc61\\ufc62\\ufc63\"\n        \"\\ufdfa\\ufdfb\\ufe70\\ufe72\\ufe74\\ufe76\\ufe78\\ufe7a\\ufe7c\\ufe7e\\uff9e\\uff9f\"\n    )\n    id_continue = id_start | charmap.query(\n        categories=(\"Mn\", \"Mc\", \"Nd\", \"Pc\"),\n        include_characters=chars[\"Other_ID_Continue\"],\n    )\n    return id_start, id_continue\n\n\nclass BytesStrategy(SearchStrategy):\n    def __init__(self, min_size: int, max_size: int | None):\n        super().__init__()\n        self.min_size = min_size\n        self.max_size = (\n            max_size if max_size is not None else COLLECTION_DEFAULT_MAX_SIZE\n        )\n\n    def do_draw(self, data: ConjectureData) -> bytes:\n        return data.draw_bytes(self.min_size, self.max_size)\n\n    _nonempty_filters = (\n        *ListStrategy._nonempty_filters,\n        bytes,\n        *(getattr(bytes, n) for n in _nonempty_names),\n    )\n    _nonempty_and_content_filters = (\n        *(getattr(bytes, n) for n in _nonempty_and_content_names),\n    )\n\n    def filter(self, condition):\n        if (new := _string_filter_rewrite(self, bytes, condition)) is not None:\n            return new\n        return ListStrategy.filter(self, condition)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/types.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport builtins\nimport collections\nimport collections.abc\nimport datetime\nimport decimal\nimport fractions\nimport functools\nimport inspect\nimport io\nimport ipaddress\nimport numbers\nimport operator\nimport os\nimport random\nimport re\nimport sys\nimport typing\nimport uuid\nimport warnings\nimport zoneinfo\nfrom collections.abc import Iterator\nfrom functools import partial\nfrom pathlib import PurePath\nfrom types import FunctionType\nfrom typing import TYPE_CHECKING, Any, NewType, get_args, get_origin\n\nfrom hypothesis import strategies as st\nfrom hypothesis.errors import (\n    HypothesisException,\n    HypothesisWarning,\n    InvalidArgument,\n    ResolutionFailed,\n)\nfrom hypothesis.internal.compat import PYPY, BaseExceptionGroup, ExceptionGroup\nfrom hypothesis.internal.conjecture.utils import many as conjecture_utils_many\nfrom hypothesis.internal.filtering import max_len, min_len\nfrom hypothesis.internal.reflection import get_pretty_function_description\nfrom hypothesis.strategies._internal.ipaddress import (\n    SPECIAL_IPv4_RANGES,\n    SPECIAL_IPv6_RANGES,\n    ip_addresses,\n)\nfrom hypothesis.strategies._internal.lazy import unwrap_strategies\nfrom hypothesis.strategies._internal.strategies import OneOfStrategy\n\nif TYPE_CHECKING:\n    import annotated_types as at\n\nGenericAlias: typing.Any\nUnionType: typing.Any\ntry:\n    # The type of PEP-604 unions (`int | str`), added in Python 3.10\n    from types import GenericAlias, UnionType\nexcept ImportError:\n    GenericAlias = ()\n    UnionType = ()\n\ntry:\n    import typing_extensions\nexcept ImportError:\n    typing_extensions = None  # type: ignore\n\ntry:\n    from typing import _AnnotatedAlias  # type: ignore\nexcept ImportError:\n    try:\n        from typing_extensions import _AnnotatedAlias\n    except ImportError:\n        _AnnotatedAlias = ()\n\nConcatenateTypes: tuple = ()\ntry:\n    ConcatenateTypes += (typing.Concatenate,)\nexcept AttributeError:  # pragma: no cover\n    pass  # Is missing for `python<3.10`\ntry:\n    ConcatenateTypes += (typing_extensions.Concatenate,)\nexcept AttributeError:  # pragma: no cover\n    pass  # `typing_extensions` might not be installed\n\nParamSpecTypes: tuple = ()\ntry:\n    ParamSpecTypes += (typing.ParamSpec,)\nexcept AttributeError:  # pragma: no cover\n    pass  # Is missing for `python<3.10`\ntry:\n    ParamSpecTypes += (typing_extensions.ParamSpec,)\nexcept AttributeError:  # pragma: no cover\n    pass  # `typing_extensions` might not be installed\n\nTypeGuardTypes: tuple = ()\ntry:\n    TypeGuardTypes += (typing.TypeGuard,)\nexcept AttributeError:  # pragma: no cover\n    pass  # Is missing for `python<3.10`\ntry:\n    TypeGuardTypes += (typing.TypeIs,)\nexcept AttributeError:  # pragma: no cover\n    pass  # Is missing for `python<3.13`\ntry:\n    TypeGuardTypes += (typing_extensions.TypeGuard, typing_extensions.TypeIs)\nexcept AttributeError:  # pragma: no cover\n    pass  # `typing_extensions` might not be installed\n\n\nRequiredTypes: tuple = ()\ntry:\n    RequiredTypes += (typing.Required,)\nexcept AttributeError:  # pragma: no cover\n    pass  # Is missing for `python<3.11`\ntry:\n    RequiredTypes += (typing_extensions.Required,)\nexcept AttributeError:  # pragma: no cover\n    pass  # `typing_extensions` might not be installed\n\n\nNotRequiredTypes: tuple = ()\ntry:\n    NotRequiredTypes += (typing.NotRequired,)\nexcept AttributeError:  # pragma: no cover\n    pass  # Is missing for `python<3.11`\ntry:\n    NotRequiredTypes += (typing_extensions.NotRequired,)\nexcept AttributeError:  # pragma: no cover\n    pass  # `typing_extensions` might not be installed\n\n\nReadOnlyTypes: tuple = ()\ntry:\n    ReadOnlyTypes += (typing.ReadOnly,)\nexcept AttributeError:  # pragma: no cover\n    pass  # Is missing for `python<3.13`\ntry:\n    ReadOnlyTypes += (typing_extensions.ReadOnly,)\nexcept AttributeError:  # pragma: no cover\n    pass  # `typing_extensions` might not be installed\n\n\nLiteralStringTypes: tuple = ()\ntry:\n    LiteralStringTypes += (typing.LiteralString,)\nexcept AttributeError:  # pragma: no cover\n    pass  # Is missing for `python<3.11`\ntry:\n    LiteralStringTypes += (typing_extensions.LiteralString,)\nexcept AttributeError:  # pragma: no cover\n    pass  # `typing_extensions` might not be installed\n\n\n# We need this function to use `get_origin` on 3.8 for types added later:\n# in typing-extensions, so we prefer this function over regular `get_origin`\n# when unwrapping `TypedDict`'s annotations.\ntry:\n    extended_get_origin = typing_extensions.get_origin\nexcept AttributeError:  # pragma: no cover\n    # `typing_extensions` might not be installed, in this case - fallback:\n    extended_get_origin = get_origin  # type: ignore\n\n\n# Used on `TypeVar` objects with no default:\nNoDefaults = (\n    getattr(typing, \"NoDefault\", object()),\n    getattr(typing_extensions, \"NoDefault\", object()),\n)\n\n# We use this variable to be sure that we are working with a type from `typing`:\ntyping_root_type = (typing._Final, typing._GenericAlias)  # type: ignore\n\n# We use this to disallow all non-runtime types from being registered and resolved.\n# By \"non-runtime\" we mean: types that do not really exist in python's\n# and are just added for more fancy type annotations.\n# `Final` is a great example: it just indicates that this value can't be reassigned.\nNON_RUNTIME_TYPES = (\n    typing.Any,\n    typing.Annotated,\n    *ConcatenateTypes,\n    *ParamSpecTypes,\n    *TypeGuardTypes,\n)\nfor name in (\n    \"ClassVar\",\n    \"Final\",\n    \"NoReturn\",\n    \"Self\",\n    \"Required\",\n    \"NotRequired\",\n    \"ReadOnly\",\n    \"Never\",\n    \"TypeAlias\",\n    \"TypeVarTuple\",\n    \"Unpack\",\n):\n    try:\n        NON_RUNTIME_TYPES += (getattr(typing, name),)\n    except AttributeError:  # pragma: no cover\n        pass\n    try:\n        NON_RUNTIME_TYPES += (getattr(typing_extensions, name),)\n    except AttributeError:  # pragma: no cover\n        pass  # typing_extensions might not be installed\n\n\ndef type_sorting_key(t):\n    \"\"\"Minimise to None, then non-container types, then container types.\"\"\"\n    if t is None or t is type(None):\n        return (-1, repr(t))\n    t = get_origin(t) or t\n    is_container = int(try_issubclass(t, collections.abc.Container))\n    return (is_container, repr(t))\n\n\ndef _compatible_args(args, superclass_args):\n    \"\"\"Check that the args of two generic types are compatible for try_issubclass.\"\"\"\n    assert superclass_args is not None\n    if args is None:\n        return True\n    return len(args) == len(superclass_args) and all(\n        # \"a==b or either is a typevar\" is a hacky approximation, but it's\n        # good enough for all the cases that I've seen so far and has the\n        # substantial virtue of (relative) simplicity.\n        a == b or isinstance(a, typing.TypeVar) or isinstance(b, typing.TypeVar)\n        for a, b in zip(args, superclass_args, strict=True)\n    )\n\n\ndef try_issubclass(thing, superclass):\n    try:\n        # In this case we're looking at two distinct classes - which might be generics.\n        # That brings in some complications:\n        if issubclass(get_origin(thing) or thing, get_origin(superclass) or superclass):\n            superclass_args = get_args(superclass)\n            if not superclass_args:\n                # The superclass is not generic, so we're definitely a subclass.\n                return True\n            # Sadly this is just some really fiddly logic to handle all the cases\n            # of user-defined generic types, types inheriting from parametrised\n            # generics, and so on.  If you need to change this code, read PEP-560\n            # and Hypothesis issue #2951 closely first, and good luck.  The tests\n            # will help you, I hope - good luck.\n            for orig_base in getattr(thing, \"__orig_bases__\", None) or [None]:\n                args = getattr(orig_base, \"__args__\", None)\n                if _compatible_args(args, superclass_args):\n                    return True\n        return False\n    except (AttributeError, TypeError):\n        # Some types can't be the subject or object of an instance or subclass check\n        return False\n\n\ndef _evaluate_type_alias_type(thing, *, typevars):  # pragma: no cover # 3.12+\n    if isinstance(thing, typing.TypeVar):\n        if thing not in typevars:\n            raise ValueError(\n                f\"Cannot look up value for unbound type var {thing}. \"\n                f\"Bound typevars: {typevars}\"\n            )\n        return typevars[thing]\n\n    origin = get_origin(thing)\n    if origin is None:\n        # not a parametrized type, so nothing to substitute.\n        return thing\n\n    args = get_args(thing)\n    # we had an origin, so we must have an args\n    # note: I'm only mostly confident this is true and there may be a subtle\n    # violator.\n    assert args\n\n    concrete_args = tuple(\n        _evaluate_type_alias_type(arg, typevars=typevars) for arg in args\n    )\n    if isinstance(origin, typing.TypeAliasType):\n        for param in origin.__type_params__:\n            # there's no principled reason not to support these, they're just\n            # annoying to implement.\n            if isinstance(param, typing.TypeVarTuple):\n                raise HypothesisException(\n                    f\"Hypothesis does not yet support resolution for TypeVarTuple \"\n                    f\"{param} (in origin: {origin!r}). Please open an issue if \"\n                    \"you would like to see support for this.\"\n                )\n            if isinstance(param, typing.ParamSpec):\n                raise HypothesisException(\n                    f\"Hypothesis does not yet support resolution for ParamSpec \"\n                    f\"{param} (in origin: {origin!r}). Please open an issue if you \"\n                    \"would like to see support for this.\"\n                )\n        # this zip is non-strict to allow for e.g.\n        # `type A[T1, T2] = list[T1]; st.from_type(A[int]).example()`,\n        # which leaves T2 free but is still acceptable as it never references\n        # it.\n        #\n        # We disallow referencing a free / unbound type var by erroring\n        # elsewhere in this function.\n        typevars |= dict(zip(origin.__type_params__, concrete_args, strict=False))\n        return _evaluate_type_alias_type(origin.__value__, typevars=typevars)\n\n    return origin[concrete_args]\n\n\ndef evaluate_type_alias_type(thing):  # pragma: no cover # covered on 3.12+\n    # this function takes a GenericAlias whose origin is a TypeAliasType,\n    # which corresponds to `type A[T] = list[T]; thing = A[int]`, and returns\n    # the fully-instantiated underlying type.\n    assert isinstance(thing, GenericAlias)\n    assert is_a_type_alias_type(get_origin(thing))\n    return _evaluate_type_alias_type(thing, typevars={})\n\n\ndef is_a_type_alias_type(thing):  # pragma: no cover # covered by 3.12+ tests\n    # TypeAliasType is new in python 3.12, through the type statement. If we're\n    # before python 3.12 then this can't possibly by a TypeAliasType.\n    #\n    # https://docs.python.org/3/reference/simple_stmts.html#type\n    # https://docs.python.org/3/library/typing.html#typing.TypeAliasType\n    if sys.version_info < (3, 12):\n        return False\n    return isinstance(thing, typing.TypeAliasType)\n\n\ndef is_a_union(thing: object) -> bool:\n    \"\"\"Return True if thing is a typing.Union or types.UnionType (in py310).\"\"\"\n    return isinstance(thing, UnionType) or get_origin(thing) is typing.Union\n\n\ndef is_a_type(thing: object) -> bool:\n    \"\"\"\n    Return True if thing is a type or a typing-like thing (union, generic type, etc).\n    \"\"\"\n    return (\n        isinstance(thing, type)\n        or is_generic_type(thing)\n        or isinstance(thing, NewType)\n        or is_a_type_alias_type(thing)\n        # union and forwardref checks necessary from 3.14+. Before 3.14, they\n        # were covered by is_generic_type(thing).\n        or is_a_union(thing)\n        or isinstance(thing, typing.ForwardRef)\n    )\n\n\ndef is_typing_literal(thing: object) -> bool:\n    return get_origin(thing) in (\n        typing.Literal,\n        getattr(typing_extensions, \"Literal\", object()),\n    )\n\n\ndef is_annotated_type(thing: object) -> bool:\n    return (\n        isinstance(thing, _AnnotatedAlias)\n        and getattr(thing, \"__args__\", None) is not None\n    )\n\n\ndef get_constraints_filter_map():\n    if at := sys.modules.get(\"annotated_types\"):\n        return {\n            # Due to the order of operator.gt/ge/lt/le arguments, order is inversed:\n            at.Gt: lambda constraint: partial(operator.lt, constraint.gt),\n            at.Ge: lambda constraint: partial(operator.le, constraint.ge),\n            at.Lt: lambda constraint: partial(operator.gt, constraint.lt),\n            at.Le: lambda constraint: partial(operator.ge, constraint.le),\n            at.MinLen: lambda constraint: partial(min_len, constraint.min_length),\n            at.MaxLen: lambda constraint: partial(max_len, constraint.max_length),\n            at.Predicate: lambda constraint: constraint.func,\n        }\n    return {}  # pragma: no cover\n\n\ndef _get_constraints(args: tuple[Any, ...]) -> Iterator[\"at.BaseMetadata\"]:\n    at = sys.modules.get(\"annotated_types\")\n    for arg in args:\n        if at and isinstance(arg, at.BaseMetadata):\n            yield arg\n        elif getattr(arg, \"__is_annotated_types_grouped_metadata__\", False):\n            for subarg in arg:\n                if getattr(subarg, \"__is_annotated_types_grouped_metadata__\", False):\n                    yield from _get_constraints(tuple(subarg))\n                else:\n                    yield subarg\n        elif at and isinstance(arg, slice) and arg.step in (1, None):\n            yield from at.Len(arg.start or 0, arg.stop)\n\n\ndef _flat_annotated_repr_parts(annotated_type):\n    # Helper to get a good error message in find_annotated_strategy() below.\n    type_reps = [\n        get_pretty_function_description(a)\n        for a in annotated_type.__args__\n        if not isinstance(a, typing.TypeVar)\n    ]\n    metadata_reps = []\n    for m in getattr(annotated_type, \"__metadata__\", ()):\n        if is_annotated_type(m):\n            ts, ms = _flat_annotated_repr_parts(m)\n            type_reps.extend(ts)\n            metadata_reps.extend(ms)\n        else:\n            metadata_reps.append(get_pretty_function_description(m))\n    return type_reps, metadata_reps\n\n\ndef find_annotated_strategy(annotated_type):\n    metadata = getattr(annotated_type, \"__metadata__\", ())\n\n    if any(is_annotated_type(arg) for arg in metadata):\n        # Annotated[Annotated[T], ...] is perfectly acceptable, but it's all to easy\n        # to instead write Annotated[T1, Annotated[T2, ...]] - and nobody else checks\n        # for that at runtime.  Once you add generics this can be seriously confusing,\n        # so we go to some trouble to give a helpful error message.\n        # For details: https://github.com/HypothesisWorks/hypothesis/issues/3891\n        ty_rep = repr(annotated_type).replace(\"typing.Annotated\", \"Annotated\")\n        ts, ms = _flat_annotated_repr_parts(annotated_type)\n        bits = \", \".join([\" | \".join(dict.fromkeys(ts or \"?\")), *dict.fromkeys(ms)])\n        raise ResolutionFailed(\n            f\"`{ty_rep}` is invalid because nesting Annotated is only allowed for \"\n            f\"the first (type) argument, not for later (metadata) arguments.  \"\n            f\"Did you mean `Annotated[{bits}]`?\"\n        )\n    for arg in reversed(metadata):\n        if isinstance(arg, st.SearchStrategy):\n            return arg\n\n    filter_conditions = []\n    unsupported = []\n    constraints_map = get_constraints_filter_map()\n    for constraint in _get_constraints(metadata):\n        if isinstance(constraint, st.SearchStrategy):\n            return constraint\n        if convert := constraints_map.get(type(constraint)):\n            filter_conditions.append(convert(constraint))\n        else:\n            unsupported.append(constraint)\n    if unsupported:\n        msg = f\"Ignoring unsupported {', '.join(map(repr, unsupported))}\"\n        warnings.warn(msg, HypothesisWarning, stacklevel=2)\n\n    base_strategy = st.from_type(annotated_type.__origin__)\n    for filter_condition in filter_conditions:\n        base_strategy = base_strategy.filter(filter_condition)\n\n    return base_strategy\n\n\ndef has_type_arguments(type_):\n    \"\"\"Decides whethere or not this type has applied type arguments.\"\"\"\n    args = getattr(type_, \"__args__\", None)\n    if args and isinstance(type_, (typing._GenericAlias, GenericAlias)):\n        # There are some cases when declared types do already have type arguments\n        # Like `Sequence`, that is `_GenericAlias(abc.Sequence[T])[T]`\n        parameters = getattr(type_, \"__parameters__\", None)\n        if parameters:  # So, we need to know if type args are just \"aliases\"\n            return args != parameters\n    return bool(args)\n\n\ndef is_generic_type(type_):\n    \"\"\"Decides whether a given type is generic or not.\"\"\"\n    # The ugly truth is that `MyClass`, `MyClass[T]`, and `MyClass[int]` are very different.\n    # We check for `MyClass[T]` and `MyClass[int]` with the first condition,\n    # while the second condition is for `MyClass`.\n    return isinstance(type_, (*typing_root_type, GenericAlias)) or (\n        isinstance(type_, type)\n        and (typing.Generic in type_.__mro__ or hasattr(type_, \"__class_getitem__\"))\n    )\n\n\n__EVAL_TYPE_TAKES_TYPE_PARAMS = (\n    \"type_params\" in inspect.signature(typing._eval_type).parameters  # type: ignore\n)\n\n\ndef _try_import_forward_ref(thing, typ, *, type_params):  # pragma: no cover\n    \"\"\"\n    Tries to import a real bound or default type from ``ForwardRef`` in ``TypeVar``.\n\n    This function is very \"magical\" to say the least, please don't use it.\n    This function fully covered, but is excluded from coverage\n    because we can only cover each path in a separate python version.\n    \"\"\"\n    try:\n        kw = {\"globalns\": vars(sys.modules[thing.__module__]), \"localns\": None}\n        if __EVAL_TYPE_TAKES_TYPE_PARAMS:\n            kw[\"type_params\"] = type_params\n        return typing._eval_type(typ, **kw)\n    except (KeyError, AttributeError, NameError):\n        # We fallback to `ForwardRef` instance, you can register it as a type as well:\n        # >>> from typing import ForwardRef\n        # >>> from hypothesis import strategies as st\n        # >>> st.register_type_strategy(ForwardRef('YourType'), your_strategy)\n        return typ\n\n\ndef from_typing_type(thing):\n    # We start with Final, Literal, and Annotated, since they don't support `isinstance`.\n    #\n    # We then explicitly error on non-Generic types, which don't carry enough\n    # information to sensibly resolve to strategies at runtime.\n    # Finally, we run a variation of the subclass lookup in `st.from_type`\n    # among generic types in the lookup.\n    if get_origin(thing) == typing.Final:\n        return st.one_of([st.from_type(t) for t in thing.__args__])\n    if is_typing_literal(thing):\n        args_dfs_stack = list(thing.__args__)\n        literals = []\n        while args_dfs_stack:\n            arg = args_dfs_stack.pop()\n            if is_typing_literal(arg):  # pragma: no cover\n                # Python 3.10+ flattens for us when constructing Literal objects\n                args_dfs_stack.extend(reversed(arg.__args__))\n            else:\n                literals.append(arg)\n        return st.sampled_from(literals)\n    if is_annotated_type(thing):\n        return find_annotated_strategy(thing)\n\n    # Some \"generic\" classes are not generic *in* anything - for example both\n    # Hashable and Sized have `__args__ == ()`\n    origin = get_origin(thing) or thing\n    if (\n        origin in vars(collections.abc).values()\n        and len(getattr(thing, \"__args__\", None) or []) == 0\n    ):\n        return st.from_type(origin)\n\n    # Parametrised generic types have their __origin__ attribute set to the\n    # un-parametrised version, which we need to use in the subclass checks.\n    # i.e.:     typing.List[int].__origin__ == list\n    mapping = {\n        k: v\n        for k, v in _global_type_lookup.items()\n        if is_generic_type(k) and try_issubclass(k, thing)\n    }\n\n    # Discard any type which is not it's own origin, where the origin is also in the\n    # mapping.  On old Python versions this could be due to redefinition of types\n    # between collections.abc and typing, but the logic seems reasonable to keep in\n    # case of similar situations now that's been fixed.\n    for t in sorted(mapping, key=type_sorting_key):\n        origin = get_origin(t)\n        if origin is not t and origin in mapping:\n            mapping.pop(t)\n\n    # Drop some unusual cases for simplicity, including tuples or its\n    # subclasses (e.g. namedtuple)\n    if len(mapping) > 1:\n        _Environ = getattr(os, \"_Environ\", None)\n        mapping.pop(_Environ, None)\n\n    tuple_types = [\n        t\n        for t in mapping\n        if (isinstance(t, type) and issubclass(t, tuple)) or get_origin(t) is tuple\n    ]\n    if len(mapping) > len(tuple_types):\n        for tuple_type in tuple_types:\n            mapping.pop(tuple_type)\n\n    if {dict, set}.intersection(mapping):\n        # ItemsView can cause test_lookup.py::test_specialised_collection_types\n        # to fail, due to weird isinstance behaviour around the elements.\n        mapping.pop(collections.abc.ItemsView, None)\n        mapping.pop(typing.ItemsView, None)\n    if collections.deque in mapping and len(mapping) > 1:\n        # Resolving generic sequences to include a deque is more trouble for e.g.\n        # the ghostwriter than it's worth, via undefined names in the repr.\n        mapping.pop(collections.deque)\n\n    if (\n        memoryview in mapping\n        and getattr(thing, \"__args__\", None)\n        and not hasattr(thing.__args__[0], \"__buffer__\")\n    ):  # pragma: no cover  # covered by 3.14+\n        # Both memoryview and list are direct subclasses of Sequence. If we ask for\n        # st.from_type(Sequence[A]), we will get both list[A] and memoryview[A].\n        # But unless A implements the buffer protocol with __buffer__, resolving\n        # memoryview[A] will error.\n        #\n        # Since the user didn't explicitly ask for memoryview, there's no reason\n        # to expect them to have implemented __buffer__. Remove memoryview in this\n        # case, before it can fail at resolution-time.\n        #\n        # Note: I intentionally did not add a `and len(mapping) > 1` condition here.\n        # If memoryview[A] is the only resolution for a strategy, but A is not a\n        # buffer protocol, our options are to (1) pop memoryview and raise\n        # ResolutionFailed, or (2) to keep memoryview in the mapping and error in\n        # resolve_memoryview. A failure in test_resolving_standard_contextmanager_as_generic\n        # (because memoryview is a context manager in 3.14) convinced me the former\n        # was less confusing to users.\n        mapping.pop(memoryview)\n\n    elem_type = (getattr(thing, \"__args__\", None) or [\"not int\"])[0]\n    union_elems = elem_type.__args__ if is_a_union(elem_type) else ()\n    allows_integer_elements = any(\n        isinstance(T, type) and try_issubclass(int, get_origin(T) or T)\n        for T in [*union_elems, elem_type]\n    )\n\n    if len(mapping) > 1:\n        # issubclass treats bytestring as a kind of sequence, which it is,\n        # but treating it as such breaks everything else when it is presumed\n        # to be a generic sequence or container that could hold any item.\n        # Except for sequences of integers, or unions which include integer!\n        # See https://github.com/HypothesisWorks/hypothesis/issues/2257\n        #\n        # This block drops bytes from the types that can be generated\n        # if there is more than one allowed type, and the element type is\n        # not either `int` or a Union with `int` as one of its elements.\n        if not allows_integer_elements:\n            mapping.pop(bytes, None)\n            if sys.version_info[:2] <= (3, 13):\n                mapping.pop(collections.abc.ByteString, None)\n    elif (\n        (not mapping)\n        and isinstance(thing, typing.ForwardRef)\n        and thing.__forward_arg__ in vars(builtins)\n    ):\n        return st.from_type(getattr(builtins, thing.__forward_arg__))\n\n    def is_maximal(t):\n        # For each k in the mapping, we use it if it's the most general type\n        # available, and exclude any more specific types. So if both\n        # Sequence and Collection are available, we use the most general Collection\n        # type.\n        #\n        # k being \"the most general\" is equivalent to saying that k is maximal\n        # in the partial ordering of types. Note that since the ordering is\n        # partial there may be multiple maximal elements. (This distinguishes\n        # maximal from maximum).\n        return sum(try_issubclass(t, T) for T in mapping) == 1\n\n    strategies = [\n        (t, s if isinstance(s, st.SearchStrategy) else s(thing))\n        for t, s in mapping.items()\n        if is_maximal(t)\n    ]\n    strategies = [(t, s) for t, s in strategies if s != NotImplemented]\n\n    # 3.14+ removes typing.ByteString. typing.ByteString was the only reason we\n    # previously generated bytes for Sequence[int]. There is no equivalent\n    # for typing.ByteString in 3.14+, but we would still like to generate bytes\n    # for Sequence[int] and its supertypes. Special case that here.\n    if (\n        sys.version_info[:2] >= (3, 14)\n        and allows_integer_elements\n        # For the same reason as the is_maximal check above, we only include\n        # this ByteString special case if it is not overridden by a more general\n        # available type.\n        #\n        # collections.abc.ByteString was a direct subclass of Sequence, so we\n        # use that as the standin type when checking. Note we compare to a count\n        # of 0, instead of 1, since in is_maximal `k` is already in `mapping`,\n        # and we expect `try_issubclass(k, k) == True`.\n        and try_issubclass(collections.abc.Sequence, thing)\n        and sum(try_issubclass(collections.abc.Sequence, T) for T in mapping) == 0\n    ):  # pragma: no cover  # covered on 3.14+\n        strategies.append((collections.abc.Sequence, st.binary()))\n\n    # Sort strategies according to our type-sorting heuristic for stable output\n    strategies = [\n        s for _k, s in sorted(strategies, key=lambda kv: type_sorting_key(kv[0]))\n    ]\n\n    empty = \", \".join(repr(s) for s in strategies if s.is_empty)\n    if empty or not strategies:\n        raise ResolutionFailed(\n            f\"Could not resolve {empty or thing} to a strategy; \"\n            \"consider using register_type_strategy\"\n        )\n    return st.one_of(strategies)\n\n\ndef can_cast(type, value):\n    \"\"\"Determine if value can be cast to type.\"\"\"\n    try:\n        type(value)\n        return True\n    except Exception:\n        return False\n\n\ndef _networks(bits):\n    return st.tuples(st.integers(0, 2**bits - 1), st.integers(-bits, 0).map(abs))\n\n\nutc_offsets = st.builds(\n    datetime.timedelta, minutes=st.integers(0, 59), hours=st.integers(-23, 23)\n)\n\n# These builtin and standard-library types have Hypothesis strategies,\n# seem likely to appear in type annotations, or are otherwise notable.\n#\n# The strategies below must cover all possible values from the type, because\n# many users treat them as comprehensive and one of Hypothesis' design goals\n# is to avoid testing less than expected.\n#\n# As a general rule, we try to limit this to scalars because from_type()\n# would have to decide on arbitrary collection elements, and we'd rather\n# not (with typing module generic types and some builtins as exceptions).\n#\n# Strategy Callables may return NotImplemented, which should be treated in the\n# same way as if the type was not registered.\n#\n# Note that NotImplemented cannot be typed in Python 3.8 because there's no type\n# exposed for it, and NotImplemented itself is typed as Any so that it can be\n# returned without being listed in a function signature:\n# https://github.com/python/mypy/issues/6710#issuecomment-485580032\nif sys.version_info < (3, 12):\n    _RegistryKeyT: typing.TypeAlias = type\nelse:  # pragma: no cover\n    _RegistryKeyT: typing.TypeAlias = type | typing.TypeAliasType\n\n_global_type_lookup: dict[\n    _RegistryKeyT, st.SearchStrategy | typing.Callable[[type], st.SearchStrategy]\n] = {\n    type(None): st.none(),\n    bool: st.booleans(),\n    int: st.integers(),\n    float: st.floats(),\n    complex: st.complex_numbers(),\n    fractions.Fraction: st.fractions(),\n    decimal.Decimal: st.decimals(),\n    str: st.text(),\n    bytes: st.binary(),\n    datetime.datetime: st.datetimes(),\n    datetime.date: st.dates(),\n    datetime.time: st.times(),\n    datetime.timedelta: st.timedeltas(),\n    datetime.timezone: st.builds(datetime.timezone, offset=utc_offsets)\n    | st.builds(datetime.timezone, offset=utc_offsets, name=st.text(st.characters())),\n    uuid.UUID: st.uuids(),\n    tuple: st.builds(tuple),\n    list: st.builds(list),\n    set: st.builds(set),\n    collections.abc.MutableSet: st.builds(set),\n    frozenset: st.builds(frozenset),\n    dict: st.builds(dict),\n    FunctionType: st.functions(),\n    type(Ellipsis): st.just(Ellipsis),\n    type(NotImplemented): st.just(NotImplemented),\n    bytearray: st.binary().map(bytearray),\n    numbers.Real: st.floats(),\n    numbers.Rational: st.fractions(),\n    numbers.Number: st.complex_numbers(),\n    numbers.Integral: st.integers(),\n    numbers.Complex: st.complex_numbers(),\n    slice: st.builds(\n        slice,\n        st.none() | st.integers(),\n        st.none() | st.integers(),\n        st.none() | st.integers(),\n    ),\n    range: st.one_of(\n        st.builds(range, st.integers(min_value=0)),\n        st.builds(range, st.integers(), st.integers()),\n        st.builds(range, st.integers(), st.integers(), st.integers().filter(bool)),\n    ),\n    ipaddress.IPv4Address: ip_addresses(v=4),\n    ipaddress.IPv6Address: ip_addresses(v=6),\n    ipaddress.IPv4Interface: _networks(32).map(ipaddress.IPv4Interface),\n    ipaddress.IPv6Interface: _networks(128).map(ipaddress.IPv6Interface),\n    ipaddress.IPv4Network: st.one_of(\n        _networks(32).map(lambda x: ipaddress.IPv4Network(x, strict=False)),\n        st.sampled_from(SPECIAL_IPv4_RANGES).map(ipaddress.IPv4Network),\n    ),\n    ipaddress.IPv6Network: st.one_of(\n        _networks(128).map(lambda x: ipaddress.IPv6Network(x, strict=False)),\n        st.sampled_from(SPECIAL_IPv6_RANGES).map(ipaddress.IPv6Network),\n    ),\n    os.PathLike: st.builds(PurePath, st.text()),\n    UnicodeDecodeError: st.builds(\n        UnicodeDecodeError,\n        st.just(\"unknown encoding\"),\n        st.just(b\"\"),\n        st.just(0),\n        st.just(0),\n        st.just(\"reason\"),\n    ),\n    UnicodeEncodeError: st.builds(\n        UnicodeEncodeError,\n        st.just(\"unknown encoding\"),\n        st.text(),\n        st.just(0),\n        st.just(0),\n        st.just(\"reason\"),\n    ),\n    UnicodeTranslateError: st.builds(\n        UnicodeTranslateError, st.text(), st.just(0), st.just(0), st.just(\"reason\")\n    ),\n    BaseExceptionGroup: st.builds(\n        BaseExceptionGroup,\n        st.text(),\n        st.lists(st.from_type(BaseException), min_size=1, max_size=5),\n    ),\n    ExceptionGroup: st.builds(\n        ExceptionGroup,\n        st.text(),\n        st.lists(st.from_type(Exception), min_size=1, max_size=5),\n    ),\n    enumerate: st.builds(enumerate, st.just(())),\n    filter: st.builds(filter, st.just(lambda _: None), st.just(())),\n    map: st.builds(map, st.just(lambda _: None), st.just(())),\n    reversed: st.builds(reversed, st.just(())),\n    zip: st.builds(zip),  # avoids warnings on PyPy 7.3.14+\n    property: st.builds(property, st.just(lambda _: None)),\n    classmethod: st.builds(classmethod, st.just(lambda self: self)),\n    staticmethod: st.builds(staticmethod, st.just(lambda self: self)),\n    super: st.builds(super, st.from_type(type)),\n    re.Match: st.text().map(lambda c: re.match(\".\", c, flags=re.DOTALL)).filter(bool),\n    re.Pattern: st.builds(re.compile, st.sampled_from([\"\", b\"\"])),\n    random.Random: st.randoms(),\n    zoneinfo.ZoneInfo: st.timezones(),\n    # Pull requests with more types welcome!\n}\nif PYPY:\n    _global_type_lookup[builtins.sequenceiterator] = st.builds(iter, st.tuples())  # type: ignore\n\n\n_fallback_type_strategy = st.sampled_from(\n    sorted(_global_type_lookup, key=type_sorting_key)\n)\n# subclass of MutableMapping, and so we resolve to a union which\n# includes this... but we don't actually ever want to build one.\n_global_type_lookup[os._Environ] = st.just(os.environ)\n\nif sys.version_info[:2] < (3, 14):\n    # Note: while ByteString notionally also represents the bytearray and\n    # memoryview types, it is a subclass of Hashable and those types are not.\n    # We therefore only generate the bytes type. type-ignored due to deprecation.\n    _global_type_lookup[typing.ByteString] = st.binary()  # type: ignore\n    _global_type_lookup[collections.abc.ByteString] = st.binary()  # type: ignore\n\n    _global_type_lookup[memoryview] = st.binary().map(memoryview)\n\n\n_global_type_lookup.update(\n    {\n        # TODO: SupportsAbs and SupportsRound should be covariant, ie have functions.\n        typing.SupportsAbs: st.one_of(\n            st.booleans(),\n            st.integers(),\n            st.floats(),\n            st.complex_numbers(),\n            st.fractions(),\n            st.decimals(),\n            st.timedeltas(),\n        ),\n        typing.SupportsRound: st.one_of(\n            st.booleans(), st.integers(), st.floats(), st.decimals(), st.fractions()\n        ),\n        typing.SupportsComplex: st.one_of(\n            st.booleans(),\n            st.integers(),\n            st.floats(),\n            st.complex_numbers(),\n            st.decimals(),\n            st.fractions(),\n        ),\n        typing.SupportsFloat: st.one_of(\n            st.booleans(),\n            st.integers(),\n            st.floats(),\n            st.decimals(),\n            st.fractions(),\n            # with floats its far more annoying to capture all\n            # the magic in a regex. so we just stringify some floats\n            st.floats().map(str),\n        ),\n        typing.SupportsInt: st.one_of(\n            st.booleans(),\n            st.integers(),\n            st.floats(),\n            st.uuids(),\n            st.decimals(),\n            # this generates strings that should able to be parsed into integers\n            st.from_regex(r\"\\A-?\\d+\\Z\").filter(functools.partial(can_cast, int)),\n        ),\n        typing.SupportsIndex: st.integers() | st.booleans(),\n        typing.SupportsBytes: st.one_of(\n            st.booleans(),\n            st.binary(),\n            st.integers(0, 255),\n            # As with Reversible, we tuplize this for compatibility with Hashable.\n            st.lists(st.integers(0, 255)).map(tuple),\n        ),\n        typing.BinaryIO: st.builds(io.BytesIO, st.binary()),\n        typing.TextIO: st.builds(io.StringIO, st.text()),\n    }\n)\n\n\n# The \"extra\" lookups define a callable that either resolves to a strategy for\n# this narrowly extra-specific type, or returns None to proceed with normal\n# type resolution. The callable will only be called if the module is\n# installed. To avoid the performance hit of importing anything here, we defer\n# it until the method is called the first time, at which point we replace the\n# entry in the lookup table with the direct call.\ndef _from_numpy_type(thing: type) -> st.SearchStrategy | None:\n    from hypothesis.extra.numpy import _from_type\n\n    _global_extra_lookup[\"numpy\"] = _from_type\n    return _from_type(thing)\n\n\n_global_extra_lookup: dict[str, typing.Callable[[type], st.SearchStrategy | None]] = {\n    \"numpy\": _from_numpy_type,\n}\n\n\ndef register(type_, fallback=None, *, module=typing):\n    if isinstance(type_, str):\n        # Use the name of generic types which are not available on all\n        # versions, and the function just won't be added to the registry;\n        # also works when module=None because typing_extensions isn't\n        # installed (nocover because it _is_ in our coverage tests).\n        type_ = getattr(module, type_, None)\n        if type_ is None:  # pragma: no cover\n            return lambda f: f\n\n    def inner(func):\n        nonlocal type_\n        if fallback is None:\n            _global_type_lookup[type_] = func\n            return func\n\n        @functools.wraps(func)\n        def really_inner(thing):\n            if getattr(thing, \"__args__\", None) is None:\n                return fallback\n            return func(thing)\n\n        _global_type_lookup[type_] = really_inner\n        _global_type_lookup[get_origin(type_) or type_] = really_inner\n        return really_inner\n\n    return inner\n\n\n@register(type)\n@register(\"Type\")\n@register(\"Type\", module=typing_extensions)\ndef resolve_Type(thing):\n    if getattr(thing, \"__args__\", None) is None or get_args(thing) == ():\n        return _fallback_type_strategy\n    args = (thing.__args__[0],)\n    if is_a_union(args[0]):\n        args = args[0].__args__\n    # Duplicate check from from_type here - only paying when needed.\n    args = list(args)\n    for i, a in enumerate(args):\n        if type(a) in (typing.ForwardRef, str):\n            try:\n                args[i] = getattr(builtins, getattr(a, \"__forward_arg__\", a))\n            except AttributeError:\n                raise ResolutionFailed(\n                    f\"Cannot find the type referenced by {thing} - try using \"\n                    f\"st.register_type_strategy({thing}, st.from_type(...))\"\n                ) from None\n    return st.sampled_from(sorted(args, key=type_sorting_key))\n\n\n@register(\"List\", st.builds(list))\ndef resolve_List(thing):\n    return st.lists(st.from_type(thing.__args__[0]))\n\n\n@register(\"Tuple\", st.builds(tuple))\ndef resolve_Tuple(thing):\n    elem_types = getattr(thing, \"__args__\", None) or ()\n    if len(elem_types) == 2 and elem_types[-1] is Ellipsis:\n        return st.lists(st.from_type(elem_types[0])).map(tuple)\n    elif len(elem_types) == 1 and elem_types[0] == ():  # pragma: no cover\n        # Empty tuple; see issue #1583.\n        # Only possible on 3.10. `from typing import Tuple; Tuple[()].__args__`\n        # is ((),) on 3.10, and () on 3.11+.\n        return st.tuples()\n    return st.tuples(*map(st.from_type, elem_types))\n\n\ndef _can_hash(val):\n    try:\n        hash(val)\n        return True\n    except Exception:\n        return False\n\n\n# Some types are subclasses of typing.Hashable, because they define a __hash__\n# method, but have non-hashable instances such as `Decimal(\"snan\")` or may contain\n# such instances (e.g. `FrozenSet[Decimal]`).  We therefore keep this whitelist of\n# types which are always hashable, and apply the `_can_hash` filter to all others.\n# Our goal is not completeness, it's to get a small performance boost for the most\n# common cases, and a short whitelist is basically free to maintain.\nALWAYS_HASHABLE_TYPES = {type(None), bool, int, float, complex, str, bytes}\n\n\ndef _from_hashable_type(type_):\n    if type_ in ALWAYS_HASHABLE_TYPES:\n        return st.from_type(type_)\n    else:\n        return st.from_type(type_).filter(_can_hash)\n\n\n@register(\"Set\", st.builds(set))\n@register(typing.MutableSet, st.builds(set))\ndef resolve_Set(thing):\n    return st.sets(_from_hashable_type(thing.__args__[0]))\n\n\n@register(\"FrozenSet\", st.builds(frozenset))\ndef resolve_FrozenSet(thing):\n    return st.frozensets(_from_hashable_type(thing.__args__[0]))\n\n\n@register(\"Dict\", st.builds(dict))\ndef resolve_Dict(thing):\n    # If thing is a Collection instance, we need to fill in the values\n    keys, vals, *_ = thing.__args__ * 2\n    return st.dictionaries(\n        _from_hashable_type(keys),\n        st.none() if vals is None else st.from_type(vals),\n    )\n\n\n@register(\"DefaultDict\", st.builds(collections.defaultdict))\n@register(\"DefaultDict\", st.builds(collections.defaultdict), module=typing_extensions)\ndef resolve_DefaultDict(thing):\n    return resolve_Dict(thing).map(lambda d: collections.defaultdict(None, d))\n\n\n@register(typing.ItemsView, st.builds(dict).map(dict.items))\ndef resolve_ItemsView(thing):\n    return resolve_Dict(thing).map(dict.items)\n\n\n@register(typing.KeysView, st.builds(dict).map(dict.keys))\ndef resolve_KeysView(thing):\n    return st.dictionaries(_from_hashable_type(thing.__args__[0]), st.none()).map(\n        dict.keys\n    )\n\n\n@register(typing.ValuesView, st.builds(dict).map(dict.values))\ndef resolve_ValuesView(thing):\n    return st.dictionaries(st.integers(), st.from_type(thing.__args__[0])).map(\n        dict.values\n    )\n\n\n@register(typing.Iterator, st.iterables(st.nothing()))\ndef resolve_Iterator(thing):\n    return st.iterables(st.from_type(thing.__args__[0]))\n\n\n@register(collections.Counter, st.builds(collections.Counter))\ndef resolve_Counter(thing):\n    return st.dictionaries(\n        keys=st.from_type(thing.__args__[0]),\n        values=st.integers(),\n    ).map(collections.Counter)\n\n\n@register(collections.deque, st.builds(collections.deque))\ndef resolve_deque(thing):\n    return st.lists(st.from_type(thing.__args__[0])).map(collections.deque)\n\n\n@register(collections.ChainMap, st.builds(dict).map(collections.ChainMap))\ndef resolve_ChainMap(thing):\n    return resolve_Dict(thing).map(collections.ChainMap)\n\n\n@register(collections.OrderedDict, st.builds(dict).map(collections.OrderedDict))\ndef resolve_OrderedDict(thing):\n    return resolve_Dict(thing).map(collections.OrderedDict)\n\n\n@register(typing.Pattern, st.builds(re.compile, st.sampled_from([\"\", b\"\"])))\ndef resolve_Pattern(thing):\n    if isinstance(thing.__args__[0], typing.TypeVar):  # pragma: no cover\n        # FIXME: this was covered on Python 3.8, but isn't on 3.10 - we should\n        # work out why not and write some extra tests to help avoid regressions.\n        return st.builds(re.compile, st.sampled_from([\"\", b\"\"]))\n    return st.just(re.compile(thing.__args__[0]()))\n\n\n@register(\n    typing.Match,\n    st.text().map(partial(re.match, \".\", flags=re.DOTALL)).filter(bool),\n)\ndef resolve_Match(thing):\n    if thing.__args__[0] == bytes:\n        return (\n            st.binary(min_size=1)\n            .map(lambda c: re.match(b\".\", c, flags=re.DOTALL))\n            .filter(bool)\n        )\n    return st.text().map(lambda c: re.match(\".\", c, flags=re.DOTALL)).filter(bool)\n\n\nclass GeneratorStrategy(st.SearchStrategy):\n    def __init__(self, yields, returns):\n        super().__init__()\n        assert isinstance(yields, st.SearchStrategy)\n        assert isinstance(returns, st.SearchStrategy)\n        self.yields = yields\n        self.returns = returns\n\n    def __repr__(self) -> str:\n        return f\"<generators yields={self.yields!r} returns={self.returns!r}>\"\n\n    def do_draw(self, data):\n        elements = conjecture_utils_many(data, min_size=0, max_size=100, average_size=5)\n        while elements.more():\n            yield data.draw(self.yields)\n        return data.draw(self.returns)\n\n\n@register(typing.Generator, GeneratorStrategy(st.none(), st.none()))\ndef resolve_Generator(thing):\n    yields, _, returns = thing.__args__\n    return GeneratorStrategy(st.from_type(yields), st.from_type(returns))\n\n\n@register(typing.Callable, st.functions())\ndef resolve_Callable(thing):\n    # Generated functions either accept no arguments, or arbitrary arguments.\n    # This is looser than ideal, but anything tighter would generally break\n    # use of keyword arguments and we'd rather not force positional-only.\n    if not thing.__args__:  # pragma: no cover  # varies by minor version\n        return st.functions()\n\n    *args_types, return_type = thing.__args__\n\n    # Note that a list can only appear in __args__ under Python 3.9 with the\n    # collections.abc version; see https://bugs.python.org/issue42195\n    if len(args_types) == 1 and isinstance(args_types[0], list):\n        args_types = tuple(args_types[0])  # pragma: no cover\n\n    pep612 = ConcatenateTypes + ParamSpecTypes\n    for arg in args_types:\n        # awkward dance because you can't use Concatenate in isistance or issubclass\n        if getattr(arg, \"__origin__\", arg) in pep612 or type(arg) in pep612:\n            raise InvalidArgument(\n                \"Hypothesis can't yet construct a strategy for instances of a \"\n                f\"Callable type parametrized by {arg!r}.  Consider using an \"\n                \"explicit strategy, or opening an issue.\"\n            )\n    if get_origin(return_type) in TypeGuardTypes:\n        raise InvalidArgument(\n            \"Hypothesis cannot yet construct a strategy for callables which \"\n            f\"are PEP-647 TypeGuards or PEP-742 TypeIs (got {return_type!r}).  \"\n            \"Consider using an explicit strategy, or opening an issue.\"\n        )\n\n    if get_origin(thing) is collections.abc.Callable and return_type is None:\n        return_type = type(None)\n\n    return st.functions(\n        like=(lambda *a, **k: None) if args_types else (lambda: None),\n        returns=st.from_type(return_type),\n    )\n\n\n@register(typing.TypeVar)\n@register(\"TypeVar\", module=typing_extensions)\ndef resolve_TypeVar(thing):\n    type_var_key = f\"typevar={thing!r}\"\n\n    bound = getattr(thing, \"__bound__\", None)\n    default = getattr(thing, \"__default__\", NoDefaults[0])\n    original_strategies = []\n\n    def resolve_strategies(typ):\n        if isinstance(typ, typing.ForwardRef):\n            # TODO: on Python 3.13 and later, we should work out what type_params\n            #       could be part of this type, and pass them in here.\n            typ = _try_import_forward_ref(thing, typ, type_params=())\n        strat = unwrap_strategies(st.from_type(typ))\n        if not isinstance(strat, OneOfStrategy):\n            original_strategies.append(strat)\n        else:\n            original_strategies.extend(strat.original_strategies)\n\n    if bound is not None:\n        resolve_strategies(bound)\n    if default not in NoDefaults:  # pragma: no cover\n        # Coverage requires 3.13 or `typing_extensions` package.\n        resolve_strategies(default)\n\n    if original_strategies:\n        # The bound / default was a union, or we resolved it as a union of subtypes,\n        # so we need to unpack the strategy to ensure consistency across uses.\n        # This incantation runs a sampled_from over the strategies inferred for\n        # each part of the union, wraps that in shared so that we only generate\n        # from one type per testcase, and flatmaps that back to instances.\n        return st.shared(\n            st.sampled_from(original_strategies), key=type_var_key\n        ).flatmap(lambda s: s)\n\n    builtin_scalar_types = [type(None), bool, int, float, str, bytes]\n    return st.shared(\n        st.sampled_from(\n            # Constraints may be None or () on various Python versions.\n            getattr(thing, \"__constraints__\", None)\n            or builtin_scalar_types,\n        ),\n        key=type_var_key,\n    ).flatmap(st.from_type)\n\n\nif sys.version_info[:2] >= (3, 14):\n    # memoryview is newly generic in 3.14. see\n    # https://github.com/python/cpython/issues/126012\n    # and https://docs.python.org/3/library/stdtypes.html#memoryview\n\n    @register(memoryview, st.binary().map(memoryview))\n    def resolve_memoryview(thing):\n        return st.from_type(thing.__args__[0]).map(memoryview)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/strategies/_internal/utils.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport dataclasses\nimport sys\nfrom collections.abc import Callable\nfrom functools import partial\nfrom typing import Literal, TypeAlias, TypeVar\nfrom weakref import WeakValueDictionary\n\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.cache import LRUReusedCache\nfrom hypothesis.internal.floats import clamp, float_to_int\nfrom hypothesis.internal.reflection import proxies\nfrom hypothesis.vendor.pretty import pretty\n\nT = TypeVar(\"T\")\nValueKey: TypeAlias = tuple[type, object]\n# (fn, args, kwargs)\nStrategyCacheKey: TypeAlias = tuple[\n    object, tuple[ValueKey, ...], frozenset[tuple[str, ValueKey]]\n]\n\n_all_strategies: WeakValueDictionary[str, Callable] = WeakValueDictionary()\n# note: LRUReusedCache is already thread-local internally\n_STRATEGY_CACHE = LRUReusedCache[StrategyCacheKey, object](1024)\n\n\ndef _value_key(value: object) -> ValueKey:\n    if isinstance(value, float):\n        return (float, float_to_int(value))\n    return (type(value), value)\n\n\ndef clear_strategy_cache() -> None:\n    _STRATEGY_CACHE.clear()\n\n\ndef cacheable(fn: T) -> T:\n    from hypothesis.control import _current_build_context\n    from hypothesis.strategies._internal.strategies import SearchStrategy\n\n    @proxies(fn)\n    def cached_strategy(*args, **kwargs):\n        context = _current_build_context.value\n        if context is not None and context.data.provider.avoid_realization:\n            return fn(*args, **kwargs)\n\n        try:\n            kwargs_cache_key = {(k, _value_key(v)) for k, v in kwargs.items()}\n        except TypeError:\n            return fn(*args, **kwargs)\n\n        cache_key = (\n            fn,\n            tuple(_value_key(v) for v in args),\n            frozenset(kwargs_cache_key),\n        )\n        try:\n            return _STRATEGY_CACHE[cache_key]\n        except KeyError:\n            pass\n        except TypeError:\n            return fn(*args, **kwargs)\n\n        result = fn(*args, **kwargs)\n        if not isinstance(result, SearchStrategy) or result.is_cacheable:\n            _STRATEGY_CACHE[cache_key] = result\n        return result\n\n    # note that calling this clears the full _STRATEGY_CACHE for all strategies,\n    # not just the cache for this strategy.\n    cached_strategy.__clear_cache = clear_strategy_cache  # type: ignore\n    return cached_strategy\n\n\ndef defines_strategy(\n    *,\n    force_reusable_values: bool = False,\n    eager: bool | Literal[\"try\"] = False,\n) -> Callable[[T], T]:\n    \"\"\"\n    Each standard strategy function provided to users by Hypothesis should be\n    decorated with @defines_strategy. This registers the strategy with _all_strategies,\n    which is used in our own test suite to check that e.g. we document all strategies\n    in sphinx.\n\n    If you're reading this and are the author of a third-party strategy library:\n    don't worry, third-party strategies don't need to be decorated with\n    @defines_strategy. This function is internal to Hypothesis and not intended\n    for outside use.\n\n    Parameters\n    ----------\n    force_reusable_values : bool\n        If ``True``, strategies returned from the strategy function will have\n        ``.has_reusable_values == True`` set, even if it uses maps/filters or\n        non-reusable strategies internally. This tells our numpy/pandas strategies\n        that they can implicitly use such strategies as background values.\n    eager : bool | \"try\"\n        If ``True``, strategies returned by the strategy function are returned\n        as-is, and not wrapped in LazyStrategy.\n\n        If \"try\", we first attempt to call the strategy function and return the\n        resulting strategy. If this throws an exception, we treat it the same as\n        ``eager = False``, by returning the strategy function wrapped in a\n        LazyStrategy.\n    \"\"\"\n\n    if eager is not False and force_reusable_values:  # pragma: no cover\n        # We could support eager + force_reusable_values with a suitable wrapper,\n        # but there are currently no callers that request this combination.\n        raise InvalidArgument(\n            f\"Passing both eager={eager} and force_reusable_values=True is \"\n            \"currently not supported\"\n        )\n\n    def decorator(strategy_definition):\n        _all_strategies[strategy_definition.__name__] = strategy_definition\n\n        if eager is True:\n            return strategy_definition\n\n        @proxies(strategy_definition)\n        def accept(*args, **kwargs):\n            from hypothesis.strategies._internal.lazy import LazyStrategy\n\n            if eager == \"try\":\n                # Why not try this unconditionally?  Because we'd end up with very\n                # deep nesting of recursive strategies - better to be lazy unless we\n                # *know* that eager evaluation is the right choice.\n                try:\n                    return strategy_definition(*args, **kwargs)\n                except Exception:\n                    # If invoking the strategy definition raises an exception,\n                    # wrap that up in a LazyStrategy so it happens again later.\n                    pass\n            result = LazyStrategy(strategy_definition, args, kwargs)\n            if force_reusable_values:\n                # Setting `force_has_reusable_values` here causes the recursive\n                # property code to set `.has_reusable_values == True`.\n                result.force_has_reusable_values = True\n                assert result.has_reusable_values\n            return result\n\n        accept.is_hypothesis_strategy_function = True\n        return accept\n\n    return decorator\n\n\ndef _to_jsonable(obj: object, *, avoid_realization: bool, seen: set[int]) -> object:\n    if isinstance(obj, (str, int, float, bool, type(None))):\n        # We convert integers of 2**63 to floats, to avoid crashing external\n        # utilities with a 64 bit integer cap (notable, sqlite). See\n        # https://github.com/HypothesisWorks/hypothesis/pull/3797#discussion_r1413425110\n        # and https://github.com/simonw/sqlite-utils/issues/605.\n        if isinstance(obj, int) and not isinstance(obj, bool) and abs(obj) >= 2**63:\n            # Silently clamp very large ints to max_float, to avoid OverflowError when\n            # casting to float.  (but avoid adding more constraints to symbolic values)\n            if avoid_realization:\n                return \"<symbolic>\"\n            obj = clamp(-sys.float_info.max, obj, sys.float_info.max)\n            return float(obj)\n        return obj\n    if avoid_realization:\n        return \"<symbolic>\"\n\n    obj_id = id(obj)\n    if obj_id in seen:\n        return pretty(obj, cycle=True)\n\n    recur = partial(\n        _to_jsonable, avoid_realization=avoid_realization, seen=seen | {obj_id}\n    )\n    if isinstance(obj, (list, tuple, set, frozenset)):\n        if isinstance(obj, tuple) and hasattr(obj, \"_asdict\"):\n            return recur(obj._asdict())  # treat namedtuples as dicts\n        return [recur(x) for x in obj]\n    if isinstance(obj, dict):\n        return {\n            k if isinstance(k, str) else pretty(k): recur(v) for k, v in obj.items()\n        }\n\n    # Hey, might as well try calling a .to_json() method - it works for Pandas!\n    # We try this before the below general-purpose handlers to give folks a\n    # chance to control this behavior on their custom classes.\n    try:\n        return recur(obj.to_json())  # type: ignore\n    except Exception:\n        pass\n\n    # Special handling for dataclasses, attrs, and pydantic classes\n    if dataclasses.is_dataclass(obj) and not isinstance(obj, type):\n        # Avoid dataclasses.asdict here to ensure that inner to_json overrides\n        # can get called as well\n        return {\n            field.name: recur(getattr(obj, field.name))\n            for field in dataclasses.fields(obj)\n        }\n    if (attr := sys.modules.get(\"attr\")) is not None and attr.has(type(obj)):\n        return recur(attr.asdict(obj, recurse=False))\n    if (pyd := sys.modules.get(\"pydantic\")) and isinstance(obj, pyd.BaseModel):\n        return recur(obj.model_dump())\n\n    # If all else fails, we'll just pretty-print as a string.\n    return pretty(obj)\n\n\ndef to_jsonable(obj: object, *, avoid_realization: bool) -> object:\n    \"\"\"Recursively convert an object to json-encodable form.\n\n    This is not intended to round-trip, but rather provide an analysis-ready\n    format for observability.  To avoid side affects, we pretty-print all but\n    known types.\n    \"\"\"\n    return _to_jsonable(obj, avoid_realization=avoid_realization, seen=set())\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/utils/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"hypothesis.utils is a package for things that you can consider part of the\nsemi-public Hypothesis API but aren't really the core point.\"\"\"\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/utils/conventions.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\nclass UniqueIdentifier:\n    \"\"\"A factory for sentinel objects with nice reprs.\"\"\"\n\n    def __init__(self, identifier: str) -> None:\n        self.identifier = identifier\n\n    def __repr__(self) -> str:\n        return self.identifier\n\n\ninfer = ...\nnot_set = UniqueIdentifier(\"not_set\")\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/utils/deprecation.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport datetime\nimport warnings\n\nfrom hypothesis.errors import HypothesisDeprecationWarning\n\n\ndef note_deprecation(\n    message: str, *, since: str, has_codemod: bool, stacklevel: int = 0\n) -> None:\n    if since != \"RELEASEDAY\":\n        date = datetime.date.fromisoformat(since)\n        assert datetime.date(2021, 1, 1) <= date\n    if has_codemod:\n        message += (\n            \"\\n    The `hypothesis codemod` command-line tool can automatically \"\n            \"refactor your code to fix this warning.\"\n        )\n    warnings.warn(HypothesisDeprecationWarning(message), stacklevel=2 + stacklevel)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/utils/dynamicvariables.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport threading\nfrom collections.abc import Generator\nfrom contextlib import contextmanager\nfrom typing import Generic, TypeVar\n\nT = TypeVar(\"T\")\n\n\nclass DynamicVariable(Generic[T]):\n    def __init__(self, default: T) -> None:\n        self.default = default\n        self.data = threading.local()\n\n    @property\n    def value(self) -> T:\n        return getattr(self.data, \"value\", self.default)\n\n    @value.setter\n    def value(self, value: T) -> None:\n        self.data.value = value\n\n    @contextmanager\n    def with_value(self, value: T) -> Generator[None, None, None]:\n        old_value = self.value\n        try:\n            self.data.value = value\n            yield\n        finally:\n            self.data.value = old_value\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/utils/terminal.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nfrom typing import Literal\n\n\ndef guess_background_color() -> Literal[\"light\", \"dark\", \"unknown\"]:\n    \"\"\"Returns one of \"dark\", \"light\", or \"unknown\".\n\n    This is basically just guessing, but better than always guessing \"dark\"!\n    See also https://stackoverflow.com/questions/2507337/ and\n    https://unix.stackexchange.com/questions/245378/\n    \"\"\"\n    django_colors = os.getenv(\"DJANGO_COLORS\", \"\")\n    for theme in (\"light\", \"dark\"):\n        if theme in django_colors.split(\";\"):\n            return theme\n    # Guessing based on the $COLORFGBG environment variable\n    try:\n        fg, *_, bg = os.getenv(\"COLORFGBG\", \"\").split(\";\")\n    except Exception:\n        pass\n    else:\n        # 0=black, 7=light-grey, 15=white ; we don't interpret other colors\n        if fg in (\"7\", \"15\") and bg == \"0\":\n            return \"dark\"\n        elif fg == \"0\" and bg in (\"7\", \"15\"):\n            return \"light\"\n    # TODO: Guessing based on the xterm control sequence\n    return \"unknown\"\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/utils/threading.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport threading\nfrom collections.abc import Callable\nfrom typing import Any\n\n\nclass ThreadLocal:\n    \"\"\"\n    Manages thread-local state. ThreadLocal forwards getattr and setattr to a\n    threading.local() instance. The passed kwargs defines the available attributes\n    on the threadlocal and their default values.\n\n    The only supported names to geattr and setattr are the keys of the passed kwargs.\n    \"\"\"\n\n    def __init__(self, **kwargs: Callable) -> None:\n        for name, value in kwargs.items():\n            if not callable(value):\n                raise TypeError(f\"Attribute {name} must be a callable. Got {value}\")\n\n        self.__initialized = False\n        self.__kwargs = kwargs\n        self.__threadlocal = threading.local()\n        self.__initialized = True\n\n    def __getattr__(self, name: str) -> Any:\n        if name not in self.__kwargs:\n            raise AttributeError(f\"No attribute {name}\")\n\n        if not hasattr(self.__threadlocal, name):\n            default = self.__kwargs[name]()\n            setattr(self.__threadlocal, name, default)\n\n        return getattr(self.__threadlocal, name)\n\n    def __setattr__(self, name: str, value: Any) -> None:\n        # disable attribute-forwarding while initializing\n        if \"_ThreadLocal__initialized\" not in self.__dict__ or not self.__initialized:\n            super().__setattr__(name, value)\n        else:\n            if name not in self.__kwargs:\n                raise AttributeError(f\"No attribute {name}\")\n            setattr(self.__threadlocal, name, value)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/vendor/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/vendor/pretty.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\nPython advanced pretty printer.  This pretty printer is intended to\nreplace the old `pprint` python module which does not allow developers\nto provide their own pretty print callbacks.\nThis module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.\nExample Usage\n-------------\nTo get a string of the output use `pretty`::\n    from pretty import pretty\n    string = pretty(complex_object)\nExtending\n---------\nThe pretty library allows developers to add pretty printing rules for their\nown objects.  This process is straightforward.  All you have to do is to\nadd a `_repr_pretty_` method to your object and call the methods on the\npretty printer passed::\n    class MyObject(object):\n        def _repr_pretty_(self, p, cycle):\n            ...\nHere is an example implementation of a `_repr_pretty_` method for a list\nsubclass::\n    class MyList(list):\n        def _repr_pretty_(self, p, cycle):\n            if cycle:\n                p.text('MyList(...)')\n            else:\n                with p.group(8, 'MyList([', '])'):\n                    for idx, item in enumerate(self):\n                        if idx:\n                            p.text(',')\n                            p.breakable()\n                        p.pretty(item)\nThe `cycle` parameter is `True` if pretty detected a cycle.  You *have* to\nreact to that or the result is an infinite loop.  `p.text()` just adds\nnon breaking text to the output, `p.breakable()` either adds a whitespace\nor breaks here.  If you pass it an argument it's used instead of the\ndefault space.  `p.pretty` prettyprints another object using the pretty print\nmethod.\nThe first parameter to the `group` function specifies the extra indentation\nof the next line.  In this example the next item will either be on the same\nline (if the items are short enough) or aligned with the right edge of the\nopening bracket of `MyList`.\nIf you just want to indent something you can use the group function\nwithout open / close parameters.  You can also use this code::\n    with p.indent(2):\n        ...\nInheritance diagram:\n.. inheritance-diagram:: IPython.lib.pretty\n   :parts: 3\n:copyright: 2007 by Armin Ronacher.\n            Portions (c) 2009 by Robert Kern.\n:license: BSD License.\n\"\"\"\n\nimport ast\nimport datetime\nimport re\nimport struct\nimport sys\nimport types\nimport warnings\nfrom collections import Counter, OrderedDict, defaultdict, deque\nfrom collections.abc import Callable, Generator, Iterable, Sequence\nfrom contextlib import contextmanager, suppress\nfrom enum import Enum, Flag\nfrom functools import partial\nfrom io import StringIO, TextIOBase\nfrom math import copysign, isnan\nfrom typing import TYPE_CHECKING, Any, Optional, TypeAlias, TypeVar\n\nif TYPE_CHECKING:\n    from hypothesis.control import BuildContext\n\nT = TypeVar(\"T\")\nPrettyPrintFunction: TypeAlias = Callable[[Any, \"RepresentationPrinter\", bool], None]\nArgLabelsT: TypeAlias = dict[str, tuple[int, int]]\n\n__all__ = [\n    \"IDKey\",\n    \"RepresentationPrinter\",\n    \"_fixeddict_pprinter\",\n    \"_tuple_pprinter\",\n    \"pretty\",\n]\n\n\ndef _safe_getattr(obj: object, attr: str, default: Any | None = None) -> Any:\n    \"\"\"Safe version of getattr.\n\n    Same as getattr, but will return ``default`` on any Exception,\n    rather than raising.\n\n    \"\"\"\n    try:\n        return getattr(obj, attr, default)\n    except Exception:\n        return default\n\n\ndef pretty(obj: object, *, cycle: bool = False) -> str:\n    \"\"\"Pretty print the object's representation.\"\"\"\n    printer = RepresentationPrinter()\n    printer.pretty(obj, cycle=cycle)\n    return printer.getvalue()\n\n\nclass IDKey:\n    def __init__(self, value: object):\n        self.value = value\n\n    def __hash__(self) -> int:\n        return hash((type(self), id(self.value)))\n\n    def __eq__(self, __o: object) -> bool:\n        return isinstance(__o, type(self)) and id(self.value) == id(__o.value)\n\n\nclass RepresentationPrinter:\n    \"\"\"Special pretty printer that has a `pretty` method that calls the pretty\n    printer for a python object.\n\n    This class stores processing data on `self` so you must *never* use\n    this class in a threaded environment.  Always lock it or\n    reinstantiate it.\n\n    \"\"\"\n\n    def __init__(\n        self,\n        output: TextIOBase | None = None,\n        *,\n        context: Optional[\"BuildContext\"] = None,\n    ) -> None:\n        \"\"\"Optionally pass the output stream and the current build context.\n\n        We use the context to represent objects constructed by strategies by showing\n        *how* they were constructed, and add annotations showing which parts of the\n        minimal failing example can vary without changing the test result.\n        \"\"\"\n        self.broken: bool = False\n        self.output: TextIOBase = StringIO() if output is None else output\n        self.max_width: int = 79\n        self.max_seq_length: int = 1000\n        self.output_width: int = 0\n        self.buffer_width: int = 0\n        self.buffer: deque[Breakable | Text] = deque()\n\n        root_group = Group(0)\n        self.group_stack = [root_group]\n        self.group_queue = GroupQueue(root_group)\n        self.indentation: int = 0\n\n        self.stack: list[int] = []\n        self.singleton_pprinters: dict[int, PrettyPrintFunction] = {}\n        self.type_pprinters: dict[type, PrettyPrintFunction] = {}\n        self.deferred_pprinters: dict[tuple[str, str], PrettyPrintFunction] = {}\n        # If IPython has been imported, load up their pretty-printer registry\n        if \"IPython.lib.pretty\" in sys.modules:\n            ipp = sys.modules[\"IPython.lib.pretty\"]\n            self.singleton_pprinters.update(ipp._singleton_pprinters)\n            self.type_pprinters.update(ipp._type_pprinters)\n            self.deferred_pprinters.update(ipp._deferred_type_pprinters)\n        # If there's overlap between our pprinters and IPython's, we'll use ours.\n        self.singleton_pprinters.update(_singleton_pprinters)\n        self.type_pprinters.update(_type_pprinters)\n        self.deferred_pprinters.update(_deferred_type_pprinters)\n\n        # for which-parts-matter, we track a mapping from the (start_idx, end_idx)\n        # of slices into the minimal failing example; this is per-interesting_origin\n        # but we report each separately so that's someone else's problem here.\n        # Invocations of self.repr_call() can report the slice for each argument,\n        # which will then be used to look up the relevant comment if any.\n        self.known_object_printers: dict[IDKey, list[PrettyPrintFunction]]\n        self.slice_comments: dict[tuple[int, int], str]\n        if context is None:\n            self.known_object_printers = defaultdict(list)\n            self.slice_comments = {}\n        else:\n            self.known_object_printers = context.known_object_printers\n            self.slice_comments = context.data.slice_comments\n        assert all(isinstance(k, IDKey) for k in self.known_object_printers)\n        # Track which slices we've already printed comments for, to avoid\n        # duplicating comments when nested objects share the same slice range.\n        self._commented_slices: set[tuple[int, int]] = set()\n\n    def pretty(self, obj: object, *, cycle: bool = False) -> None:\n        \"\"\"Pretty print the given object.\"\"\"\n        obj_id = id(obj)\n        cycle = cycle or obj_id in self.stack\n        self.stack.append(obj_id)\n        try:\n            with self.group():\n                obj_class = _safe_getattr(obj, \"__class__\", None) or type(obj)\n                # First try to find registered singleton printers for the type.\n                try:\n                    printer = self.singleton_pprinters[obj_id]\n                except (TypeError, KeyError):\n                    pass\n                else:\n                    return printer(obj, self, cycle)\n\n                # Look for the _repr_pretty_ method which allows users\n                # to define custom pretty printing.\n                # Some objects automatically create any requested\n                # attribute. Try to ignore most of them by checking for\n                # callability.\n                pretty_method = _safe_getattr(obj, \"_repr_pretty_\", None)\n                if callable(pretty_method):\n                    return pretty_method(self, cycle)\n\n                # Check for object-specific printers which show how this\n                # object was constructed (a Hypothesis special feature).\n                # This must come before type_pprinters so that sub-argument\n                # comments are shown for tuples/dicts/etc.\n                printers = self.known_object_printers[IDKey(obj)]\n                if len(printers) == 1:\n                    return printers[0](obj, self, cycle)\n                if printers:\n                    # Multiple registered functions for the same object (due to\n                    # caching, small ints, etc). Use the first if all produce\n                    # the same string; otherwise pretend none were registered.\n                    strs = set()\n                    for f in printers:\n                        p = RepresentationPrinter()\n                        f(obj, p, cycle)\n                        strs.add(p.getvalue())\n                    if len(strs) == 1:\n                        return printers[0](obj, self, cycle)\n\n                # Next walk the mro and check for either:\n                #   1) a registered printer\n                #   2) a _repr_pretty_ method\n                for cls in obj_class.__mro__:\n                    if cls in self.type_pprinters:\n                        # printer registered in self.type_pprinters\n                        return self.type_pprinters[cls](obj, self, cycle)\n                    else:\n                        # Check if the given class is specified in the deferred type\n                        # registry; move it to the regular type registry if so.\n                        key = (\n                            _safe_getattr(cls, \"__module__\", None),\n                            _safe_getattr(cls, \"__name__\", None),\n                        )\n                        if key in self.deferred_pprinters:\n                            # Move the printer over to the regular registry.\n                            printer = self.deferred_pprinters.pop(key)\n                            self.type_pprinters[cls] = printer\n                            return printer(obj, self, cycle)\n                        else:\n                            if hasattr(cls, \"__attrs_attrs__\"):  # pragma: no cover\n                                return pprint_fields(\n                                    obj,\n                                    self,\n                                    cycle,\n                                    [at.name for at in cls.__attrs_attrs__ if at.init],\n                                )\n                            if hasattr(cls, \"__dataclass_fields__\"):\n                                return pprint_fields(\n                                    obj,\n                                    self,\n                                    cycle,\n                                    [\n                                        k\n                                        for k, v in cls.__dataclass_fields__.items()\n                                        if v.init\n                                    ],\n                                )\n\n                # A user-provided repr. Find newlines and replace them with p.break_()\n                return _repr_pprint(obj, self, cycle)\n        finally:\n            self.stack.pop()\n\n    def _break_outer_groups(self) -> None:\n        while self.max_width < self.output_width + self.buffer_width:\n            group = self.group_queue.deq()\n            if not group:\n                return\n            while group.breakables:\n                x = self.buffer.popleft()\n                self.output_width = x.output(self.output, self.output_width)\n                self.buffer_width -= x.width\n            while self.buffer and isinstance(self.buffer[0], Text):\n                x = self.buffer.popleft()\n                self.output_width = x.output(self.output, self.output_width)\n                self.buffer_width -= x.width\n\n    def text(self, obj: str) -> None:\n        \"\"\"Add literal text to the output.\"\"\"\n        width = len(obj)\n        if self.buffer:\n            text = self.buffer[-1]\n            if not isinstance(text, Text):\n                text = Text()\n                self.buffer.append(text)\n            text.add(obj, width)\n            self.buffer_width += width\n            self._break_outer_groups()\n        else:\n            self.output.write(obj)\n            self.output_width += width\n\n    def breakable(self, sep: str = \" \") -> None:\n        \"\"\"Add a breakable separator to the output.\n\n        This does not mean that it will automatically break here.  If no\n        breaking on this position takes place the `sep` is inserted\n        which default to one space.\n\n        \"\"\"\n        width = len(sep)\n        group = self.group_stack[-1]\n        if group.want_break:\n            self.flush()\n            self.output.write(\"\\n\" + \" \" * self.indentation)\n            self.output_width = self.indentation\n            self.buffer_width = 0\n        else:\n            self.buffer.append(Breakable(sep, width, self))\n            self.buffer_width += width\n            self._break_outer_groups()\n\n    def break_(self) -> None:\n        \"\"\"Explicitly insert a newline into the output, maintaining correct\n        indentation.\"\"\"\n        self.flush()\n        self.output.write(\"\\n\" + \" \" * self.indentation)\n        self.output_width = self.indentation\n        self.buffer_width = 0\n\n    @contextmanager\n    def indent(self, indent: int) -> Generator[None, None, None]:\n        \"\"\"`with`-statement support for indenting/dedenting.\"\"\"\n        self.indentation += indent\n        try:\n            yield\n        finally:\n            self.indentation -= indent\n\n    @contextmanager\n    def group(\n        self, indent: int = 0, open: str = \"\", close: str = \"\"\n    ) -> Generator[None, None, None]:\n        \"\"\"Context manager for an indented group.\n\n            with p.group(1, '{', '}'):\n\n        The first parameter specifies the indentation for the next line\n        (usually the width of the opening text), the second and third the\n        opening and closing delimiters.\n        \"\"\"\n        self.begin_group(indent=indent, open=open)\n        try:\n            yield\n        finally:\n            self.end_group(dedent=indent, close=close)\n\n    def begin_group(self, indent: int = 0, open: str = \"\") -> None:\n        \"\"\"Use the `with group(...) context manager instead.\n\n        The begin_group() and end_group() methods are for IPython compatibility only;\n        see https://github.com/HypothesisWorks/hypothesis/issues/3721 for details.\n        \"\"\"\n        if open:\n            self.text(open)\n        group = Group(self.group_stack[-1].depth + 1)\n        self.group_stack.append(group)\n        self.group_queue.enq(group)\n        self.indentation += indent\n\n    def end_group(self, dedent: int = 0, close: str = \"\") -> None:\n        \"\"\"See begin_group().\"\"\"\n        self.indentation -= dedent\n        group = self.group_stack.pop()\n        if not group.breakables:\n            self.group_queue.remove(group)\n        if close:\n            self.text(close)\n\n    def _enumerate(self, seq: Iterable[T]) -> Generator[tuple[int, T], None, None]:\n        \"\"\"Like enumerate, but with an upper limit on the number of items.\"\"\"\n        for idx, x in enumerate(seq):\n            if self.max_seq_length and idx >= self.max_seq_length:\n                self.text(\",\")\n                self.breakable()\n                self.text(\"...\")\n                return\n            yield idx, x\n\n    def flush(self) -> None:\n        \"\"\"Flush data that is left in the buffer.\"\"\"\n        for data in self.buffer:\n            self.output_width += data.output(self.output, self.output_width)\n        self.buffer.clear()\n        self.buffer_width = 0\n\n    def getvalue(self) -> str:\n        assert isinstance(self.output, StringIO)\n        self.flush()\n        return self.output.getvalue()\n\n    def maybe_repr_known_object_as_call(\n        self,\n        obj: object,\n        cycle: bool,\n        name: str,\n        args: Sequence[object],\n        kwargs: dict[str, object],\n        arg_labels: ArgLabelsT | None = None,\n    ) -> None:\n        # pprint this object as a call, _unless_ the call would be invalid syntax\n        # and the repr would be valid and there are not comments on arguments.\n        if cycle:\n            return self.text(\"<...>\")\n        # Look up comments from slice_comments if we have arg_labels\n        comments = {}\n        if arg_labels is not None:\n            for key, sr in arg_labels.items():\n                if sr in self.slice_comments:\n                    comments[key] = self.slice_comments[sr]\n        # If there are comments, we must use our call-style repr regardless of syntax\n        if not comments:\n            with suppress(Exception):\n                # Check whether the repr is valid syntax:\n                ast.parse(repr(obj))\n                # Given that the repr is valid syntax, check the call:\n                p = RepresentationPrinter()\n                p.stack = self.stack.copy()\n                p.known_object_printers = self.known_object_printers\n                p.repr_call(name, args, kwargs)\n                # If the call is not valid syntax, use the repr\n                try:\n                    ast.parse(p.getvalue())\n                except Exception:\n                    return _repr_pprint(obj, self, cycle)\n        return self.repr_call(name, args, kwargs, arg_slices=arg_labels)\n\n    def repr_call(\n        self,\n        func_name: str,\n        args: Sequence[object],\n        kwargs: dict[str, object],\n        *,\n        force_split: bool | None = None,\n        arg_slices: ArgLabelsT | None = None,\n        leading_comment: str | None = None,\n        avoid_realization: bool = False,\n    ) -> None:\n        \"\"\"Helper function to represent a function call.\n\n        - func_name, args, and kwargs should all be pretty obvious.\n        - If split_lines, we'll force one-argument-per-line; otherwise we'll place\n          calls that fit on a single line (and split otherwise).\n        - arg_slices is a mapping from pos-idx or keyword to (start_idx, end_idx)\n          of the Conjecture buffer, by which we can look up comments to add.\n        \"\"\"\n        assert isinstance(func_name, str)\n        if func_name.startswith((\"lambda:\", \"lambda \")):\n            func_name = f\"({func_name})\"\n        self.text(func_name)\n        # Build list of (label, value) pairs. Labels are \"arg[i]\" for positional\n        # args, or the keyword name. Skip slices already commented at a higher level.\n        all_args = [(f\"arg[{i}]\", v) for i, v in enumerate(args)]\n        all_args += list(kwargs.items())\n        arg_slices = arg_slices or {}\n        comments: dict[str, tuple[str, tuple[int, int]]] = {}\n        for label, sr in arg_slices.items():\n            if sr in self.slice_comments and sr not in self._commented_slices:\n                comments[label] = (self.slice_comments[sr], sr)\n\n        if leading_comment or any(k in comments for k, _ in all_args):\n            # We have to split one arg per line in order to leave comments on them.\n            force_split = True\n        if force_split is None:\n            # We're OK with printing this call on a single line, but will it fit?\n            # If not, we'd rather fall back to one-argument-per-line instead.\n            p = RepresentationPrinter()\n            p.stack = self.stack.copy()\n            p.known_object_printers = self.known_object_printers\n            p.repr_call(\"_\" * self.output_width, args, kwargs, force_split=False)\n            s = p.getvalue()\n            force_split = \"\\n\" in s\n\n        with self.group(indent=4, open=\"(\", close=\"\"):\n            for i, (label, v) in enumerate(all_args):\n                if force_split:\n                    if i == 0 and leading_comment:\n                        self.break_()\n                        self.text(leading_comment)\n                    self.break_()\n                else:\n                    assert leading_comment is None  # only passed by top-level report\n                    self.breakable(\" \" if i else \"\")\n                if not label.startswith(\"arg[\"):\n                    self.text(f\"{label}=\")\n                # Mark slice as commented BEFORE printing value, so nested printers skip it\n                entry = comments.get(label)\n                if entry:\n                    self._commented_slices.add(entry[1])\n                if avoid_realization:\n                    self.text(\"<symbolic>\")\n                else:\n                    self.pretty(v)\n                if force_split or i + 1 < len(all_args):\n                    self.text(\",\")\n                if entry:\n                    self.text(f\"  # {entry[0]}\")\n        if all_args and force_split:\n            self.break_()\n        self.text(\")\")  # after dedent\n\n\nclass Printable:\n    def output(self, stream: TextIOBase, output_width: int) -> int:  # pragma: no cover\n        raise NotImplementedError\n\n\nclass Text(Printable):\n    def __init__(self) -> None:\n        self.objs: list[str] = []\n        self.width: int = 0\n\n    def output(self, stream: TextIOBase, output_width: int) -> int:\n        for obj in self.objs:\n            stream.write(obj)\n        return output_width + self.width\n\n    def add(self, obj: str, width: int) -> None:\n        self.objs.append(obj)\n        self.width += width\n\n\nclass Breakable(Printable):\n    def __init__(self, seq: str, width: int, pretty: RepresentationPrinter) -> None:\n        self.obj = seq\n        self.width = width\n        self.pretty = pretty\n        self.indentation = pretty.indentation\n        self.group = pretty.group_stack[-1]\n        self.group.breakables.append(self)\n\n    def output(self, stream: TextIOBase, output_width: int) -> int:\n        self.group.breakables.popleft()\n        if self.group.want_break:\n            stream.write(\"\\n\" + \" \" * self.indentation)\n            return self.indentation\n        if not self.group.breakables:\n            self.pretty.group_queue.remove(self.group)\n        stream.write(self.obj)\n        return output_width + self.width\n\n\nclass Group(Printable):\n    def __init__(self, depth: int) -> None:\n        self.depth = depth\n        self.breakables: deque[Breakable] = deque()\n        self.want_break: bool = False\n\n\nclass GroupQueue:\n    def __init__(self, *groups: Group) -> None:\n        self.queue: list[list[Group]] = []\n        for group in groups:\n            self.enq(group)\n\n    def enq(self, group: Group) -> None:\n        depth = group.depth\n        while depth > len(self.queue) - 1:\n            self.queue.append([])\n        self.queue[depth].append(group)\n\n    def deq(self) -> Group | None:\n        for stack in self.queue:\n            for idx, group in enumerate(reversed(stack)):\n                if group.breakables:\n                    del stack[idx]\n                    group.want_break = True\n                    return group\n            for group in stack:\n                group.want_break = True\n            del stack[:]\n        return None\n\n    def remove(self, group: Group) -> None:\n        try:\n            self.queue[group.depth].remove(group)\n        except ValueError:\n            pass\n\n\ndef _seq_pprinter_factory(start: str, end: str, basetype: type) -> PrettyPrintFunction:\n    \"\"\"Factory that returns a pprint function useful for sequences.\n\n    Used by the default pprint for tuples, dicts, and lists.\n    \"\"\"\n\n    def inner(\n        obj: tuple[object] | list[object], p: RepresentationPrinter, cycle: bool\n    ) -> None:\n        typ = type(obj)\n        if (\n            basetype is not None\n            and typ is not basetype\n            and typ.__repr__ != basetype.__repr__  # type: ignore[comparison-overlap]\n        ):\n            # If the subclass provides its own repr, use it instead.\n            return p.text(typ.__repr__(obj))\n\n        if cycle:\n            return p.text(start + \"...\" + end)\n        step = len(start)\n        with p.group(step, start, end):\n            for idx, x in p._enumerate(obj):\n                if idx:\n                    p.text(\",\")\n                    p.breakable()\n                p.pretty(x)\n            if len(obj) == 1 and type(obj) is tuple:\n                # Special case for 1-item tuples.\n                p.text(\",\")\n\n    return inner\n\n\ndef get_class_name(cls: type[object]) -> str:\n    class_name = _safe_getattr(cls, \"__qualname__\", cls.__name__)\n    assert isinstance(class_name, str)\n    return class_name\n\n\ndef _set_pprinter_factory(\n    start: str, end: str, basetype: type[object]\n) -> PrettyPrintFunction:\n    \"\"\"Factory that returns a pprint function useful for sets and\n    frozensets.\"\"\"\n\n    def inner(\n        obj: set[Any] | frozenset[Any],\n        p: RepresentationPrinter,\n        cycle: bool,\n    ) -> None:\n        typ = type(obj)\n        if (\n            basetype is not None\n            and typ is not basetype\n            and typ.__repr__ != basetype.__repr__\n        ):\n            # If the subclass provides its own repr, use it instead.\n            return p.text(typ.__repr__(obj))\n\n        if cycle:\n            return p.text(start + \"...\" + end)\n        if not obj:\n            # Special case.\n            p.text(get_class_name(basetype) + \"()\")\n        else:\n            step = len(start)\n            with p.group(step, start, end):\n                # Like dictionary keys, try to sort the items if there aren't too many\n                items: Iterable[object] = obj\n                if not (p.max_seq_length and len(obj) >= p.max_seq_length):\n                    try:\n                        items = sorted(obj)\n                    except Exception:\n                        # Sometimes the items don't sort.\n                        pass\n                for idx, x in p._enumerate(items):\n                    if idx:\n                        p.text(\",\")\n                        p.breakable()\n                    p.pretty(x)\n\n    return inner\n\n\ndef _dict_pprinter_factory(\n    start: str, end: str, basetype: type[object] | None = None\n) -> PrettyPrintFunction:\n    \"\"\"Factory that returns a pprint function used by the default pprint of\n    dicts and dict proxies.\"\"\"\n\n    def inner(obj: dict[object, object], p: RepresentationPrinter, cycle: bool) -> None:\n        typ = type(obj)\n        if (\n            basetype is not None\n            and typ is not basetype\n            and typ.__repr__ != basetype.__repr__\n        ):\n            # If the subclass provides its own repr, use it instead.\n            return p.text(typ.__repr__(obj))\n\n        if cycle:\n            return p.text(\"{...}\")\n        with (\n            p.group(1, start, end),\n            # If the dict contains both \"\" and b\"\" (empty string and empty bytes), we\n            # ignore the BytesWarning raised by `python -bb` mode.  We can't use\n            # `.items()` because it might be a non-`dict` type of mapping.\n            warnings.catch_warnings(),\n        ):\n            warnings.simplefilter(\"ignore\", BytesWarning)\n            for idx, key in p._enumerate(obj):\n                if idx:\n                    p.text(\",\")\n                    p.breakable()\n                p.pretty(key)\n                p.text(\": \")\n                p.pretty(obj[key])\n\n    inner.__name__ = f\"_dict_pprinter_factory({start!r}, {end!r}, {basetype!r})\"\n    return inner\n\n\ndef _super_pprint(obj: Any, p: RepresentationPrinter, cycle: bool) -> None:\n    \"\"\"The pprint for the super type.\"\"\"\n    with p.group(8, \"<super: \", \">\"):\n        p.pretty(obj.__thisclass__)\n        p.text(\",\")\n        p.breakable()\n        p.pretty(obj.__self__)\n\n\ndef _re_pattern_pprint(obj: re.Pattern, p: RepresentationPrinter, cycle: bool) -> None:\n    \"\"\"The pprint function for regular expression patterns.\"\"\"\n    p.text(\"re.compile(\")\n    pattern = repr(obj.pattern)\n    if pattern[:1] in \"uU\":  # pragma: no cover\n        pattern = pattern[1:]\n        prefix = \"ur\"\n    else:\n        prefix = \"r\"\n    pattern = prefix + pattern.replace(\"\\\\\\\\\", \"\\\\\")\n    p.text(pattern)\n    if obj.flags:\n        p.text(\",\")\n        p.breakable()\n        done_one = False\n        for flag in (\n            \"TEMPLATE\",\n            \"IGNORECASE\",\n            \"LOCALE\",\n            \"MULTILINE\",\n            \"DOTALL\",\n            \"UNICODE\",\n            \"VERBOSE\",\n            \"DEBUG\",\n        ):\n            if obj.flags & getattr(re, flag, 0):\n                if done_one:\n                    p.text(\"|\")\n                p.text(\"re.\" + flag)\n                done_one = True\n    p.text(\")\")\n\n\ndef _type_pprint(obj: type[object], p: RepresentationPrinter, cycle: bool) -> None:\n    \"\"\"The pprint for classes and types.\"\"\"\n    # Heap allocated types might not have the module attribute,\n    # and others may set it to None.\n\n    # Checks for a __repr__ override in the metaclass\n    # != rather than is not because pypy compatibility\n    if type(obj).__repr__ != type.__repr__:  # type: ignore[comparison-overlap]\n        _repr_pprint(obj, p, cycle)\n        return\n\n    mod = _safe_getattr(obj, \"__module__\", None)\n    try:\n        name = obj.__qualname__\n    except Exception:  # pragma: no cover\n        name = obj.__name__\n        if not isinstance(name, str):\n            name = \"<unknown type>\"\n\n    if mod in (None, \"__builtin__\", \"builtins\", \"exceptions\"):\n        p.text(name)\n    else:\n        p.text(mod + \".\" + name)\n\n\ndef _repr_pprint(obj: object, p: RepresentationPrinter, cycle: bool) -> None:\n    \"\"\"A pprint that just redirects to the normal repr function.\"\"\"\n    # Find newlines and replace them with p.break_()\n    output = repr(obj)\n    for idx, output_line in enumerate(output.splitlines()):\n        if idx:\n            p.break_()\n        p.text(output_line)\n\n\ndef pprint_fields(\n    obj: object, p: RepresentationPrinter, cycle: bool, fields: Iterable[str]\n) -> None:\n    name = get_class_name(obj.__class__)\n    if cycle:\n        return p.text(f\"{name}(...)\")\n    with p.group(1, name + \"(\", \")\"):\n        for idx, field in enumerate(fields):\n            if idx:\n                p.text(\",\")\n                p.breakable()\n            p.text(field)\n            p.text(\"=\")\n            p.pretty(getattr(obj, field))\n\n\ndef _get_slice_comment(\n    p: RepresentationPrinter,\n    arg_labels: ArgLabelsT,\n    key: Any,\n) -> tuple[str, tuple[int, int]] | None:\n    \"\"\"Look up a comment for a slice, if not already printed at a higher level.\"\"\"\n    if (sr := arg_labels.get(key)) and sr in p.slice_comments:\n        if sr not in p._commented_slices:\n            return (p.slice_comments[sr], sr)\n    return None\n\n\ndef _tuple_pprinter(arg_labels: ArgLabelsT) -> PrettyPrintFunction:\n    \"\"\"Pretty printer for tuples that shows sub-argument comments.\"\"\"\n\n    def inner(obj: tuple, p: RepresentationPrinter, cycle: bool) -> None:\n        if cycle:\n            return p.text(\"(...)\")\n\n        get = lambda i: _get_slice_comment(p, arg_labels, f\"arg[{i}]\")\n        has_comments = any(get(i) for i in range(len(obj)))\n\n        with p.group(indent=4, open=\"(\", close=\"\"):\n            for idx, x in p._enumerate(obj):\n                p.break_() if has_comments else (p.breakable() if idx else None)\n                p.pretty(x)\n                if has_comments or idx + 1 < len(obj) or len(obj) == 1:\n                    p.text(\",\")\n                if entry := get(idx):\n                    p._commented_slices.add(entry[1])\n                    p.text(f\"  # {entry[0]}\")\n        if has_comments and obj:\n            p.break_()\n        p.text(\")\")\n\n    return inner\n\n\ndef _fixeddict_pprinter(\n    arg_labels: ArgLabelsT,\n    mapping: dict[Any, Any],\n) -> PrettyPrintFunction:\n    \"\"\"Pretty printer for fixed_dictionaries that shows sub-argument comments.\"\"\"\n\n    def inner(obj: dict, p: RepresentationPrinter, cycle: bool) -> None:\n        if cycle:\n            return p.text(\"{...}\")\n\n        get = lambda k: _get_slice_comment(p, arg_labels, k)\n        # Preserve mapping key order, then any optional keys (deduped)\n        keys = list(dict.fromkeys(k for k in [*mapping, *obj] if k in obj))\n        has_comments = any(get(k) for k in keys)\n\n        with p.group(indent=4, open=\"{\", close=\"\"):\n            for idx, key in p._enumerate(keys):\n                p.break_() if has_comments else (p.breakable() if idx else None)\n                p.pretty(key)\n                p.text(\": \")\n                p.pretty(obj[key])\n                if has_comments or idx + 1 < len(keys):\n                    p.text(\",\")\n                if entry := get(key):\n                    p._commented_slices.add(entry[1])\n                    p.text(f\"  # {entry[0]}\")\n        if has_comments and obj:\n            p.break_()\n        p.text(\"}\")\n\n    return inner\n\n\ndef _function_pprint(\n    obj: types.FunctionType | types.BuiltinFunctionType | types.MethodType,\n    p: RepresentationPrinter,\n    cycle: bool,\n) -> None:\n    \"\"\"Base pprint for all functions and builtin functions.\"\"\"\n    from hypothesis.internal.reflection import get_pretty_function_description\n\n    p.text(get_pretty_function_description(obj))\n\n\ndef _exception_pprint(\n    obj: BaseException, p: RepresentationPrinter, cycle: bool\n) -> None:\n    \"\"\"Base pprint for all exceptions.\"\"\"\n    name = getattr(obj.__class__, \"__qualname__\", obj.__class__.__name__)\n    if obj.__class__.__module__ not in (\"exceptions\", \"builtins\"):\n        name = f\"{obj.__class__.__module__}.{name}\"\n    step = len(name) + 1\n    with p.group(step, name + \"(\", \")\"):\n        for idx, arg in enumerate(getattr(obj, \"args\", ())):\n            if idx:\n                p.text(\",\")\n                p.breakable()\n            p.pretty(arg)\n\n\ndef _repr_integer(obj: int, p: RepresentationPrinter, cycle: bool) -> None:\n    if abs(obj) < 1_000_000_000:\n        p.text(repr(obj))\n    elif abs(obj) < 10**640:\n        # add underscores for integers over ten decimal digits\n        p.text(f\"{obj:#_d}\")\n    else:\n        # for very very large integers, use hex because power-of-two bases are cheaper\n        # https://docs.python.org/3/library/stdtypes.html#integer-string-conversion-length-limitation\n        p.text(f\"{obj:#_x}\")\n\n\ndef _repr_float_counting_nans(\n    obj: float, p: RepresentationPrinter, cycle: bool\n) -> None:\n    if isnan(obj):\n        if struct.pack(\"!d\", abs(obj)) != struct.pack(\"!d\", float(\"nan\")):\n            show = hex(*struct.unpack(\"Q\", struct.pack(\"d\", obj)))\n            return p.text(f\"struct.unpack('d', struct.pack('Q', {show}))[0]\")\n        elif copysign(1.0, obj) == -1.0:\n            return p.text(\"-nan\")\n    p.text(repr(obj))\n\n\n#: printers for builtin types\n_type_pprinters: dict[type, PrettyPrintFunction] = {\n    int: _repr_integer,\n    float: _repr_float_counting_nans,\n    str: _repr_pprint,\n    tuple: _seq_pprinter_factory(\"(\", \")\", tuple),\n    list: _seq_pprinter_factory(\"[\", \"]\", list),\n    dict: _dict_pprinter_factory(\"{\", \"}\", dict),\n    set: _set_pprinter_factory(\"{\", \"}\", set),\n    frozenset: _set_pprinter_factory(\"frozenset({\", \"})\", frozenset),\n    super: _super_pprint,\n    re.Pattern: _re_pattern_pprint,\n    type: _type_pprint,\n    types.FunctionType: _function_pprint,\n    types.BuiltinFunctionType: _function_pprint,\n    types.MethodType: _function_pprint,\n    datetime.datetime: _repr_pprint,\n    datetime.timedelta: _repr_pprint,\n    BaseException: _exception_pprint,\n    slice: _repr_pprint,\n    range: _repr_pprint,\n    bytes: _repr_pprint,\n}\n\n#: printers for types specified by name\n_deferred_type_pprinters: dict[tuple[str, str], PrettyPrintFunction] = {}\n\n\ndef for_type_by_name(\n    type_module: str, type_name: str, func: PrettyPrintFunction\n) -> PrettyPrintFunction | None:\n    \"\"\"Add a pretty printer for a type specified by the module and name of a\n    type rather than the type object itself.\"\"\"\n    key = (type_module, type_name)\n    oldfunc = _deferred_type_pprinters.get(key)\n    _deferred_type_pprinters[key] = func\n    return oldfunc\n\n\n#: printers for the default singletons\n_singleton_pprinters: dict[int, PrettyPrintFunction] = dict.fromkeys(\n    map(id, [None, True, False, Ellipsis, NotImplemented]), _repr_pprint\n)\n\n\ndef _defaultdict_pprint(\n    obj: defaultdict[object, object], p: RepresentationPrinter, cycle: bool\n) -> None:\n    name = obj.__class__.__name__\n    with p.group(len(name) + 1, name + \"(\", \")\"):\n        if cycle:\n            p.text(\"...\")\n        else:\n            p.pretty(obj.default_factory)\n            p.text(\",\")\n            p.breakable()\n            p.pretty(dict(obj))\n\n\ndef _ordereddict_pprint(\n    obj: OrderedDict[object, object], p: RepresentationPrinter, cycle: bool\n) -> None:\n    name = obj.__class__.__name__\n    with p.group(len(name) + 1, name + \"(\", \")\"):\n        if cycle:\n            p.text(\"...\")\n        elif obj:\n            p.pretty(list(obj.items()))\n\n\ndef _deque_pprint(obj: deque[object], p: RepresentationPrinter, cycle: bool) -> None:\n    name = obj.__class__.__name__\n    with p.group(len(name) + 1, name + \"(\", \")\"):\n        if cycle:\n            p.text(\"...\")\n        else:\n            p.pretty(list(obj))\n\n\ndef _counter_pprint(\n    obj: Counter[object], p: RepresentationPrinter, cycle: bool\n) -> None:\n    name = obj.__class__.__name__\n    with p.group(len(name) + 1, name + \"(\", \")\"):\n        if cycle:\n            p.text(\"...\")\n        elif obj:\n            p.pretty(dict(obj))\n\n\ndef _repr_dataframe(\n    obj: object, p: RepresentationPrinter, cycle: bool\n) -> None:  # pragma: no cover\n    with p.indent(4):\n        p.break_()\n        _repr_pprint(obj, p, cycle)\n    p.break_()\n\n\ndef _repr_enum(obj: Enum, p: RepresentationPrinter, cycle: bool) -> None:\n    tname = get_class_name(type(obj))\n    if isinstance(obj, Flag):\n        p.text(\n            \" | \".join(f\"{tname}.{x.name}\" for x in type(obj) if x & obj == x)\n            or f\"{tname}({obj.value!r})\"  # if no matching members\n        )\n    else:\n        p.text(f\"{tname}.{obj.name}\")\n\n\nclass _ReprDots:\n    def __repr__(self) -> str:\n        return \"...\"\n\n\ndef _repr_partial(obj: partial[Any], p: RepresentationPrinter, cycle: bool) -> None:\n    args, kw = obj.args, obj.keywords\n    if cycle:\n        args, kw = (_ReprDots(),), {}\n    p.repr_call(pretty(type(obj)), (obj.func, *args), kw)\n\n\nfor_type_by_name(\"collections\", \"defaultdict\", _defaultdict_pprint)\nfor_type_by_name(\"collections\", \"OrderedDict\", _ordereddict_pprint)\nfor_type_by_name(\"ordereddict\", \"OrderedDict\", _ordereddict_pprint)\nfor_type_by_name(\"collections\", \"deque\", _deque_pprint)\nfor_type_by_name(\"collections\", \"Counter\", _counter_pprint)\nfor_type_by_name(\"pandas.core.frame\", \"DataFrame\", _repr_dataframe)\nfor_type_by_name(\"enum\", \"Enum\", _repr_enum)\nfor_type_by_name(\"functools\", \"partial\", _repr_partial)\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/vendor/tlds-alpha-by-domain.txt",
    "content": "# Version 2026021400, Last Updated Sat Feb 14 07:07:01 2026 UTC\nAAA\nAARP\nABB\nABBOTT\nABBVIE\nABC\nABLE\nABOGADO\nABUDHABI\nAC\nACADEMY\nACCENTURE\nACCOUNTANT\nACCOUNTANTS\nACO\nACTOR\nAD\nADS\nADULT\nAE\nAEG\nAERO\nAETNA\nAF\nAFL\nAFRICA\nAG\nAGAKHAN\nAGENCY\nAI\nAIG\nAIRBUS\nAIRFORCE\nAIRTEL\nAKDN\nAL\nALIBABA\nALIPAY\nALLFINANZ\nALLSTATE\nALLY\nALSACE\nALSTOM\nAM\nAMAZON\nAMERICANEXPRESS\nAMERICANFAMILY\nAMEX\nAMFAM\nAMICA\nAMSTERDAM\nANALYTICS\nANDROID\nANQUAN\nANZ\nAO\nAOL\nAPARTMENTS\nAPP\nAPPLE\nAQ\nAQUARELLE\nAR\nARAB\nARAMCO\nARCHI\nARMY\nARPA\nART\nARTE\nAS\nASDA\nASIA\nASSOCIATES\nAT\nATHLETA\nATTORNEY\nAU\nAUCTION\nAUDI\nAUDIBLE\nAUDIO\nAUSPOST\nAUTHOR\nAUTO\nAUTOS\nAW\nAWS\nAX\nAXA\nAZ\nAZURE\nBA\nBABY\nBAIDU\nBANAMEX\nBAND\nBANK\nBAR\nBARCELONA\nBARCLAYCARD\nBARCLAYS\nBAREFOOT\nBARGAINS\nBASEBALL\nBASKETBALL\nBAUHAUS\nBAYERN\nBB\nBBC\nBBT\nBBVA\nBCG\nBCN\nBD\nBE\nBEATS\nBEAUTY\nBEER\nBERLIN\nBEST\nBESTBUY\nBET\nBF\nBG\nBH\nBHARTI\nBI\nBIBLE\nBID\nBIKE\nBING\nBINGO\nBIO\nBIZ\nBJ\nBLACK\nBLACKFRIDAY\nBLOCKBUSTER\nBLOG\nBLOOMBERG\nBLUE\nBM\nBMS\nBMW\nBN\nBNPPARIBAS\nBO\nBOATS\nBOEHRINGER\nBOFA\nBOM\nBOND\nBOO\nBOOK\nBOOKING\nBOSCH\nBOSTIK\nBOSTON\nBOT\nBOUTIQUE\nBOX\nBR\nBRADESCO\nBRIDGESTONE\nBROADWAY\nBROKER\nBROTHER\nBRUSSELS\nBS\nBT\nBUILD\nBUILDERS\nBUSINESS\nBUY\nBUZZ\nBV\nBW\nBY\nBZ\nBZH\nCA\nCAB\nCAFE\nCAL\nCALL\nCALVINKLEIN\nCAM\nCAMERA\nCAMP\nCANON\nCAPETOWN\nCAPITAL\nCAPITALONE\nCAR\nCARAVAN\nCARDS\nCARE\nCAREER\nCAREERS\nCARS\nCASA\nCASE\nCASH\nCASINO\nCAT\nCATERING\nCATHOLIC\nCBA\nCBN\nCBRE\nCC\nCD\nCENTER\nCEO\nCERN\nCF\nCFA\nCFD\nCG\nCH\nCHANEL\nCHANNEL\nCHARITY\nCHASE\nCHAT\nCHEAP\nCHINTAI\nCHRISTMAS\nCHROME\nCHURCH\nCI\nCIPRIANI\nCIRCLE\nCISCO\nCITADEL\nCITI\nCITIC\nCITY\nCK\nCL\nCLAIMS\nCLEANING\nCLICK\nCLINIC\nCLINIQUE\nCLOTHING\nCLOUD\nCLUB\nCLUBMED\nCM\nCN\nCO\nCOACH\nCODES\nCOFFEE\nCOLLEGE\nCOLOGNE\nCOM\nCOMMBANK\nCOMMUNITY\nCOMPANY\nCOMPARE\nCOMPUTER\nCOMSEC\nCONDOS\nCONSTRUCTION\nCONSULTING\nCONTACT\nCONTRACTORS\nCOOKING\nCOOL\nCOOP\nCORSICA\nCOUNTRY\nCOUPON\nCOUPONS\nCOURSES\nCPA\nCR\nCREDIT\nCREDITCARD\nCREDITUNION\nCRICKET\nCROWN\nCRS\nCRUISE\nCRUISES\nCU\nCUISINELLA\nCV\nCW\nCX\nCY\nCYMRU\nCYOU\nCZ\nDAD\nDANCE\nDATA\nDATE\nDATING\nDATSUN\nDAY\nDCLK\nDDS\nDE\nDEAL\nDEALER\nDEALS\nDEGREE\nDELIVERY\nDELL\nDELOITTE\nDELTA\nDEMOCRAT\nDENTAL\nDENTIST\nDESI\nDESIGN\nDEV\nDHL\nDIAMONDS\nDIET\nDIGITAL\nDIRECT\nDIRECTORY\nDISCOUNT\nDISCOVER\nDISH\nDIY\nDJ\nDK\nDM\nDNP\nDO\nDOCS\nDOCTOR\nDOG\nDOMAINS\nDOT\nDOWNLOAD\nDRIVE\nDTV\nDUBAI\nDUPONT\nDURBAN\nDVAG\nDVR\nDZ\nEARTH\nEAT\nEC\nECO\nEDEKA\nEDU\nEDUCATION\nEE\nEG\nEMAIL\nEMERCK\nENERGY\nENGINEER\nENGINEERING\nENTERPRISES\nEPSON\nEQUIPMENT\nER\nERICSSON\nERNI\nES\nESQ\nESTATE\nET\nEU\nEUROVISION\nEUS\nEVENTS\nEXCHANGE\nEXPERT\nEXPOSED\nEXPRESS\nEXTRASPACE\nFAGE\nFAIL\nFAIRWINDS\nFAITH\nFAMILY\nFAN\nFANS\nFARM\nFARMERS\nFASHION\nFAST\nFEDEX\nFEEDBACK\nFERRARI\nFERRERO\nFI\nFIDELITY\nFIDO\nFILM\nFINAL\nFINANCE\nFINANCIAL\nFIRE\nFIRESTONE\nFIRMDALE\nFISH\nFISHING\nFIT\nFITNESS\nFJ\nFK\nFLICKR\nFLIGHTS\nFLIR\nFLORIST\nFLOWERS\nFLY\nFM\nFO\nFOO\nFOOD\nFOOTBALL\nFORD\nFOREX\nFORSALE\nFORUM\nFOUNDATION\nFOX\nFR\nFREE\nFRESENIUS\nFRL\nFROGANS\nFRONTIER\nFTR\nFUJITSU\nFUN\nFUND\nFURNITURE\nFUTBOL\nFYI\nGA\nGAL\nGALLERY\nGALLO\nGALLUP\nGAME\nGAMES\nGAP\nGARDEN\nGAY\nGB\nGBIZ\nGD\nGDN\nGE\nGEA\nGENT\nGENTING\nGEORGE\nGF\nGG\nGGEE\nGH\nGI\nGIFT\nGIFTS\nGIVES\nGIVING\nGL\nGLASS\nGLE\nGLOBAL\nGLOBO\nGM\nGMAIL\nGMBH\nGMO\nGMX\nGN\nGODADDY\nGOLD\nGOLDPOINT\nGOLF\nGOODYEAR\nGOOG\nGOOGLE\nGOP\nGOT\nGOV\nGP\nGQ\nGR\nGRAINGER\nGRAPHICS\nGRATIS\nGREEN\nGRIPE\nGROCERY\nGROUP\nGS\nGT\nGU\nGUCCI\nGUGE\nGUIDE\nGUITARS\nGURU\nGW\nGY\nHAIR\nHAMBURG\nHANGOUT\nHAUS\nHBO\nHDFC\nHDFCBANK\nHEALTH\nHEALTHCARE\nHELP\nHELSINKI\nHERE\nHERMES\nHIPHOP\nHISAMITSU\nHITACHI\nHIV\nHK\nHKT\nHM\nHN\nHOCKEY\nHOLDINGS\nHOLIDAY\nHOMEDEPOT\nHOMEGOODS\nHOMES\nHOMESENSE\nHONDA\nHORSE\nHOSPITAL\nHOST\nHOSTING\nHOT\nHOTELS\nHOTMAIL\nHOUSE\nHOW\nHR\nHSBC\nHT\nHU\nHUGHES\nHYATT\nHYUNDAI\nIBM\nICBC\nICE\nICU\nID\nIE\nIEEE\nIFM\nIKANO\nIL\nIM\nIMAMAT\nIMDB\nIMMO\nIMMOBILIEN\nIN\nINC\nINDUSTRIES\nINFINITI\nINFO\nING\nINK\nINSTITUTE\nINSURANCE\nINSURE\nINT\nINTERNATIONAL\nINTUIT\nINVESTMENTS\nIO\nIPIRANGA\nIQ\nIR\nIRISH\nIS\nISMAILI\nIST\nISTANBUL\nIT\nITAU\nITV\nJAGUAR\nJAVA\nJCB\nJE\nJEEP\nJETZT\nJEWELRY\nJIO\nJLL\nJM\nJMP\nJNJ\nJO\nJOBS\nJOBURG\nJOT\nJOY\nJP\nJPMORGAN\nJPRS\nJUEGOS\nJUNIPER\nKAUFEN\nKDDI\nKE\nKERRYHOTELS\nKERRYPROPERTIES\nKFH\nKG\nKH\nKI\nKIA\nKIDS\nKIM\nKINDLE\nKITCHEN\nKIWI\nKM\nKN\nKOELN\nKOMATSU\nKOSHER\nKP\nKPMG\nKPN\nKR\nKRD\nKRED\nKUOKGROUP\nKW\nKY\nKYOTO\nKZ\nLA\nLACAIXA\nLAMBORGHINI\nLAMER\nLAND\nLANDROVER\nLANXESS\nLASALLE\nLAT\nLATINO\nLATROBE\nLAW\nLAWYER\nLB\nLC\nLDS\nLEASE\nLECLERC\nLEFRAK\nLEGAL\nLEGO\nLEXUS\nLGBT\nLI\nLIDL\nLIFE\nLIFEINSURANCE\nLIFESTYLE\nLIGHTING\nLIKE\nLILLY\nLIMITED\nLIMO\nLINCOLN\nLINK\nLIVE\nLIVING\nLK\nLLC\nLLP\nLOAN\nLOANS\nLOCKER\nLOCUS\nLOL\nLONDON\nLOTTE\nLOTTO\nLOVE\nLPL\nLPLFINANCIAL\nLR\nLS\nLT\nLTD\nLTDA\nLU\nLUNDBECK\nLUXE\nLUXURY\nLV\nLY\nMA\nMADRID\nMAIF\nMAISON\nMAKEUP\nMAN\nMANAGEMENT\nMANGO\nMAP\nMARKET\nMARKETING\nMARKETS\nMARRIOTT\nMARSHALLS\nMATTEL\nMBA\nMC\nMCKINSEY\nMD\nME\nMED\nMEDIA\nMEET\nMELBOURNE\nMEME\nMEMORIAL\nMEN\nMENU\nMERCKMSD\nMG\nMH\nMIAMI\nMICROSOFT\nMIL\nMINI\nMINT\nMIT\nMITSUBISHI\nMK\nML\nMLB\nMLS\nMM\nMMA\nMN\nMO\nMOBI\nMOBILE\nMODA\nMOE\nMOI\nMOM\nMONASH\nMONEY\nMONSTER\nMORMON\nMORTGAGE\nMOSCOW\nMOTO\nMOTORCYCLES\nMOV\nMOVIE\nMP\nMQ\nMR\nMS\nMSD\nMT\nMTN\nMTR\nMU\nMUSEUM\nMUSIC\nMV\nMW\nMX\nMY\nMZ\nNA\nNAB\nNAGOYA\nNAME\nNAVY\nNBA\nNC\nNE\nNEC\nNET\nNETBANK\nNETFLIX\nNETWORK\nNEUSTAR\nNEW\nNEWS\nNEXT\nNEXTDIRECT\nNEXUS\nNF\nNFL\nNG\nNGO\nNHK\nNI\nNICO\nNIKE\nNIKON\nNINJA\nNISSAN\nNISSAY\nNL\nNO\nNOKIA\nNORTON\nNOW\nNOWRUZ\nNOWTV\nNP\nNR\nNRA\nNRW\nNTT\nNU\nNYC\nNZ\nOBI\nOBSERVER\nOFFICE\nOKINAWA\nOLAYAN\nOLAYANGROUP\nOLLO\nOM\nOMEGA\nONE\nONG\nONL\nONLINE\nOOO\nOPEN\nORACLE\nORANGE\nORG\nORGANIC\nORIGINS\nOSAKA\nOTSUKA\nOTT\nOVH\nPA\nPAGE\nPANASONIC\nPARIS\nPARS\nPARTNERS\nPARTS\nPARTY\nPAY\nPCCW\nPE\nPET\nPF\nPFIZER\nPG\nPH\nPHARMACY\nPHD\nPHILIPS\nPHONE\nPHOTO\nPHOTOGRAPHY\nPHOTOS\nPHYSIO\nPICS\nPICTET\nPICTURES\nPID\nPIN\nPING\nPINK\nPIONEER\nPIZZA\nPK\nPL\nPLACE\nPLAY\nPLAYSTATION\nPLUMBING\nPLUS\nPM\nPN\nPNC\nPOHL\nPOKER\nPOLITIE\nPORN\nPOST\nPR\nPRAXI\nPRESS\nPRIME\nPRO\nPROD\nPRODUCTIONS\nPROF\nPROGRESSIVE\nPROMO\nPROPERTIES\nPROPERTY\nPROTECTION\nPRU\nPRUDENTIAL\nPS\nPT\nPUB\nPW\nPWC\nPY\nQA\nQPON\nQUEBEC\nQUEST\nRACING\nRADIO\nRE\nREAD\nREALESTATE\nREALTOR\nREALTY\nRECIPES\nRED\nREDUMBRELLA\nREHAB\nREISE\nREISEN\nREIT\nRELIANCE\nREN\nRENT\nRENTALS\nREPAIR\nREPORT\nREPUBLICAN\nREST\nRESTAURANT\nREVIEW\nREVIEWS\nREXROTH\nRICH\nRICHARDLI\nRICOH\nRIL\nRIO\nRIP\nRO\nROCKS\nRODEO\nROGERS\nROOM\nRS\nRSVP\nRU\nRUGBY\nRUHR\nRUN\nRW\nRWE\nRYUKYU\nSA\nSAARLAND\nSAFE\nSAFETY\nSAKURA\nSALE\nSALON\nSAMSCLUB\nSAMSUNG\nSANDVIK\nSANDVIKCOROMANT\nSANOFI\nSAP\nSARL\nSAS\nSAVE\nSAXO\nSB\nSBI\nSBS\nSC\nSCB\nSCHAEFFLER\nSCHMIDT\nSCHOLARSHIPS\nSCHOOL\nSCHULE\nSCHWARZ\nSCIENCE\nSCOT\nSD\nSE\nSEARCH\nSEAT\nSECURE\nSECURITY\nSEEK\nSELECT\nSENER\nSERVICES\nSEVEN\nSEW\nSEX\nSEXY\nSFR\nSG\nSH\nSHANGRILA\nSHARP\nSHELL\nSHIA\nSHIKSHA\nSHOES\nSHOP\nSHOPPING\nSHOUJI\nSHOW\nSI\nSILK\nSINA\nSINGLES\nSITE\nSJ\nSK\nSKI\nSKIN\nSKY\nSKYPE\nSL\nSLING\nSM\nSMART\nSMILE\nSN\nSNCF\nSO\nSOCCER\nSOCIAL\nSOFTBANK\nSOFTWARE\nSOHU\nSOLAR\nSOLUTIONS\nSONG\nSONY\nSOY\nSPA\nSPACE\nSPORT\nSPOT\nSR\nSRL\nSS\nST\nSTADA\nSTAPLES\nSTAR\nSTATEBANK\nSTATEFARM\nSTC\nSTCGROUP\nSTOCKHOLM\nSTORAGE\nSTORE\nSTREAM\nSTUDIO\nSTUDY\nSTYLE\nSU\nSUCKS\nSUPPLIES\nSUPPLY\nSUPPORT\nSURF\nSURGERY\nSUZUKI\nSV\nSWATCH\nSWISS\nSX\nSY\nSYDNEY\nSYSTEMS\nSZ\nTAB\nTAIPEI\nTALK\nTAOBAO\nTARGET\nTATAMOTORS\nTATAR\nTATTOO\nTAX\nTAXI\nTC\nTCI\nTD\nTDK\nTEAM\nTECH\nTECHNOLOGY\nTEL\nTEMASEK\nTENNIS\nTEVA\nTF\nTG\nTH\nTHD\nTHEATER\nTHEATRE\nTIAA\nTICKETS\nTIENDA\nTIPS\nTIRES\nTIROL\nTJ\nTJMAXX\nTJX\nTK\nTKMAXX\nTL\nTM\nTMALL\nTN\nTO\nTODAY\nTOKYO\nTOOLS\nTOP\nTORAY\nTOSHIBA\nTOTAL\nTOURS\nTOWN\nTOYOTA\nTOYS\nTR\nTRADE\nTRADING\nTRAINING\nTRAVEL\nTRAVELERS\nTRAVELERSINSURANCE\nTRUST\nTRV\nTT\nTUBE\nTUI\nTUNES\nTUSHU\nTV\nTVS\nTW\nTZ\nUA\nUBANK\nUBS\nUG\nUK\nUNICOM\nUNIVERSITY\nUNO\nUOL\nUPS\nUS\nUY\nUZ\nVA\nVACATIONS\nVANA\nVANGUARD\nVC\nVE\nVEGAS\nVENTURES\nVERISIGN\nVERSICHERUNG\nVET\nVG\nVI\nVIAJES\nVIDEO\nVIG\nVIKING\nVILLAS\nVIN\nVIP\nVIRGIN\nVISA\nVISION\nVIVA\nVIVO\nVLAANDEREN\nVN\nVODKA\nVOLVO\nVOTE\nVOTING\nVOTO\nVOYAGE\nVU\nWALES\nWALMART\nWALTER\nWANG\nWANGGOU\nWATCH\nWATCHES\nWEATHER\nWEATHERCHANNEL\nWEBCAM\nWEBER\nWEBSITE\nWED\nWEDDING\nWEIBO\nWEIR\nWF\nWHOSWHO\nWIEN\nWIKI\nWILLIAMHILL\nWIN\nWINDOWS\nWINE\nWINNERS\nWME\nWOODSIDE\nWORK\nWORKS\nWORLD\nWOW\nWS\nWTC\nWTF\nXBOX\nXEROX\nXIHUAN\nXIN\nXN--11B4C3D\nXN--1CK2E1B\nXN--1QQW23A\nXN--2SCRJ9C\nXN--30RR7Y\nXN--3BST00M\nXN--3DS443G\nXN--3E0B707E\nXN--3HCRJ9C\nXN--3PXU8K\nXN--42C2D9A\nXN--45BR5CYL\nXN--45BRJ9C\nXN--45Q11C\nXN--4DBRK0CE\nXN--4GBRIM\nXN--54B7FTA0CC\nXN--55QW42G\nXN--55QX5D\nXN--5SU34J936BGSG\nXN--5TZM5G\nXN--6FRZ82G\nXN--6QQ986B3XL\nXN--80ADXHKS\nXN--80AO21A\nXN--80AQECDR1A\nXN--80ASEHDB\nXN--80ASWG\nXN--8Y0A063A\nXN--90A3AC\nXN--90AE\nXN--90AIS\nXN--9DBQ2A\nXN--9ET52U\nXN--9KRT00A\nXN--B4W605FERD\nXN--BCK1B9A5DRE4C\nXN--C1AVG\nXN--C2BR7G\nXN--CCK2B3B\nXN--CCKWCXETD\nXN--CG4BKI\nXN--CLCHC0EA0B2G2A9GCD\nXN--CZR694B\nXN--CZRS0T\nXN--CZRU2D\nXN--D1ACJ3B\nXN--D1ALF\nXN--E1A4C\nXN--ECKVDTC9D\nXN--EFVY88H\nXN--FCT429K\nXN--FHBEI\nXN--FIQ228C5HS\nXN--FIQ64B\nXN--FIQS8S\nXN--FIQZ9S\nXN--FJQ720A\nXN--FLW351E\nXN--FPCRJ9C3D\nXN--FZC2C9E2C\nXN--FZYS8D69UVGM\nXN--G2XX48C\nXN--GCKR3F0F\nXN--GECRJ9C\nXN--GK3AT1E\nXN--H2BREG3EVE\nXN--H2BRJ9C\nXN--H2BRJ9C8C\nXN--HXT814E\nXN--I1B6B1A6A2E\nXN--IMR513N\nXN--IO0A7I\nXN--J1AEF\nXN--J1AMH\nXN--J6W193G\nXN--JLQ480N2RG\nXN--JVR189M\nXN--KCRX77D1X4A\nXN--KPRW13D\nXN--KPRY57D\nXN--KPUT3I\nXN--L1ACC\nXN--LGBBAT1AD8J\nXN--MGB9AWBF\nXN--MGBA3A3EJT\nXN--MGBA3A4F16A\nXN--MGBA7C0BBN0A\nXN--MGBAAM7A8H\nXN--MGBAB2BD\nXN--MGBAH1A3HJKRD\nXN--MGBAI9AZGQP6J\nXN--MGBAYH7GPA\nXN--MGBBH1A\nXN--MGBBH1A71E\nXN--MGBC0A9AZCG\nXN--MGBCA7DZDO\nXN--MGBCPQ6GPA1A\nXN--MGBERP4A5D4AR\nXN--MGBGU82A\nXN--MGBI4ECEXP\nXN--MGBPL2FH\nXN--MGBT3DHD\nXN--MGBTX2B\nXN--MGBX4CD0AB\nXN--MIX891F\nXN--MK1BU44C\nXN--MXTQ1M\nXN--NGBC5AZD\nXN--NGBE9E0A\nXN--NGBRX\nXN--NODE\nXN--NQV7F\nXN--NQV7FS00EMA\nXN--NYQY26A\nXN--O3CW4H\nXN--OGBPF8FL\nXN--OTU796D\nXN--P1ACF\nXN--P1AI\nXN--PGBS0DH\nXN--PSSY2U\nXN--Q7CE6A\nXN--Q9JYB4C\nXN--QCKA1PMC\nXN--QXA6A\nXN--QXAM\nXN--RHQV96G\nXN--ROVU88B\nXN--RVC1E0AM3E\nXN--S9BRJ9C\nXN--SES554G\nXN--T60B56A\nXN--TCKWE\nXN--TIQ49XQYJ\nXN--UNUP4Y\nXN--VERMGENSBERATER-CTB\nXN--VERMGENSBERATUNG-PWB\nXN--VHQUV\nXN--VUQ861B\nXN--W4R85EL8FHU5DNRA\nXN--W4RS40L\nXN--WGBH1C\nXN--WGBL6A\nXN--XHQ521B\nXN--XKC2AL3HYE2A\nXN--XKC2DL3A5EE0H\nXN--Y9A3AQ\nXN--YFRO4I67O\nXN--YGBI2AMMX\nXN--ZFR164B\nXXX\nXYZ\nYACHTS\nYAHOO\nYAMAXUN\nYANDEX\nYE\nYODOBASHI\nYOGA\nYOKOHAMA\nYOU\nYOUTUBE\nYT\nYUN\nZA\nZAPPOS\nZARA\nZERO\nZIP\nZM\nZONE\nZUERICH\nZW\n"
  },
  {
    "path": "hypothesis-python/src/hypothesis/version.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n__version_info__ = (6, 151, 9)\n__version__ = \".\".join(map(str, __version_info__))\n"
  },
  {
    "path": "hypothesis-python/tests/README.md",
    "content": "# Don't Panic\n\nThe Hypothesis test suite is large, but we've written these notes to help you out.  It's aimed at contributors (new and old!) who know they need to add tests *somewhere*, but aren't sure where - or maybe need some hints on what kinds of tests might be useful.  Others might just be interested in how a testing library tests itself!\n\n## The very short version\n\n- To improve code coverage (eg because `./build.sh check-coverage` or CI is failing), go to `cover/`\n- For longer / system / integration tests, look in `nocover/`\n- For tests that require an optional dependency, look in the directory named for that dependency.\n\n> [!NOTE]\n> If you get stuck, just ask a maintainer to help out by mentioning them on GitHub. We'd love to help - and also get feedback on how this document could be better!\n\n## Some scenarios\n\n#### I'm adding or changing a strategy\n\nCheck for a file specific to that strategy (eg `test_uuids.py` for the `uuids()` strategy).  Write tests for all invalid argument handling in `test_direct_strategies.py`.  Strategies with optional dependencies should go in `hypothesis.extras`, and the tests in their own module (ie not in `cover`).  When you think you might be done, push and let our CI system point out any failing tests or non-covered code!\n\n#### I've made some internal changes\n\nThat's not very specific - you should probably refer to the test-finding tips in the next section.  Remember that `tests/cover` is reasonably quick unit-test style tests - you should consider writing more intensive integration tests too, but put them in `tests/nocover` with the others.\n\n## Finding particular tests\n\nWith the sheer size and variety in this directory finding a specific thing can be tricky.  Tips:\n\n- Check for filenames that are relevant to your contribution.\n- Use `git grep` to search for keywords, e.g. the name of a strategy you've changed.\n- Deliberately break something related to your code, and see which tests fail.\n- Ask a maintainer!  Sometimes the structure is just arbitrary, and other tactics don't work - but we *want* to help!\n\n## About each group of tests\n\nStill here?  Here's a note on what to expect in each directory.\n\n* `common/`\n  * Useful shared testing code, including test setup and a few helper functions in `utils.py`.  Also read up on [pytest](https://docs.pytest.org/en/latest/contents.html>) features such as `mark.parametrize`, `mark.skipif`, and `raises` for other functions that are often useful when writing tests.\n* `conjecture/`\n   * As for `cover/`, but specific to `hypothesis.internal.conjecture`.\n* `cover/`\n  * The home of enough tests to get 100% branch coverage, as quickly as possible without compromising on test power.  This can be an intimidating target, but it's entirely achievable and the maintainers are (still) here to help.\n  * This directory alone has around two-thirds of the tests for Hypothesis (~8k of ~12k lines of code).  If you're adding or fixing tests, chances are therefore good that they're in here!\n* `datetime/`\n  * Tests which depend on the `pytz` or `dateutil` packages for timezones.\n* `django/`\n  * Tests for the Django extra.  Includes a toy application, to give us lots of models to generate.\n* `lark/`\n  * Tests for the Lark extra for context-free grammars, which depend on the `lark` package.\n* `nocover/`\n  * More expensive and longer-running tests, typically used to test trickier interactions or check for regressions in expensive bugs.  Lots of tests about how values shrink, databases, compatibility, etc.\n  * New tests that are not required for full coverage of code branches or behaviour should also go in `nocover`, to keep `cover` reasonably fast.\n* `numpy/`\n  * Tests for the Numpy extra.\n* `pandas/`\n  * Tests for the Pandas extra.\n* `pytest/`\n  * Hypothesis has excellent integration with `pytest`, though we are careful to support other test runners such as unittest.  This is where we test that our pytest integration is working properly.\n* `quality/`\n  * Tests that various hard-to-find examples do in fact get found by Hypothesis, as well as some stuff about example shrinking.  Mostly intended for tests of the form \"Hypothesis finds an example of this condition\" + assertions about which example it finds.\n"
  },
  {
    "path": "hypothesis-python/tests/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/array_api/README.md",
    "content": "This folder contains tests for `hypothesis.extra.array_api`.\n\n## Mocked array module\n\nA mock of the Array API namespace exists as `mock_xp` in `extra.array_api`. This\nwraps NumPy-proper to conform it to the *draft* spec, where `array_api_strict`\nmight not. This is not a fully compliant wrapper, but conforms enough for the\npurposes of testing.\n\n## Running against different array modules\n\nYou can test other array modules which adopt the Array API via the\n`HYPOTHESIS_TEST_ARRAY_API` environment variable. There are two recognized\noptions:\n\n* `\"default\"`: uses the mock.\n* `\"all\"`: uses all array modules found via entry points, _and_ the mock.\n\nIf neither of these, the test suite will then try resolve the variable like so:\n\n1. If the variable matches a name of an available entry point, load said entry point.\n2. If the variables matches a valid import path, import said path.\n\nFor example, to specify NumPy's Array API implementation[^1], you could use its\nentry point (**1.**),\n\n    HYPOTHESIS_TEST_ARRAY_API=numpy pytest tests/array_api\n\nor use the import path (**2.**),\n\n    HYPOTHESIS_TEST_ARRAY_API=numpy.array_api pytest tests/array_api\n\nThe former method is more ergonomic, but as entry points are optional for\nadopting the Array API, you will need to use the latter method for libraries\nthat opt-out.\n\n## Running against different API versions\n\nYou can specify the `api_version` to use when testing array modules via the \n`HYPOTHESIS_TEST_ARRAY_API_VERSION` environment variable. There is one\nrecognized option:\n\n* `\"default\"`: infers the latest API version for each array module.\n\nOtherwise the test suite will use the variable as the `api_version` argument for\n`make_strategies_namespace()`.\n\nIn the future we intend to support running tests against multiple API versioned\nnamespaces, likely with an additional recognized option that infers all\nsupported versions.\n\n[^1]: Note NumPy will likely remove `numpy.array_api` in the future ([NEP 56](https://github.com/numpy/numpy/pull/25542))\nin favour of the third-party [`array-api-strict`](https://github.com/data-apis/array-api-strict) library."
  },
  {
    "path": "hypothesis-python/tests/array_api/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/array_api/common.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom importlib.metadata import EntryPoint, entry_points  # type: ignore\nfrom typing import Literal\n\nimport pytest\n\nfrom hypothesis.extra.array_api import (\n    COMPLEX_NAMES,\n    REAL_NAMES,\n    RELEASED_VERSIONS,\n    NominalVersion,\n)\nfrom hypothesis.internal.floats import next_up\n\n__all__ = [\n    \"MIN_VER_FOR_COMPLEX\",\n    \"dtype_name_params\",\n    \"flushes_to_zero\",\n    \"installed_array_modules\",\n]\n\n\nMIN_VER_FOR_COMPLEX: NominalVersion = \"2022.12\"\nif len(RELEASED_VERSIONS) > 1:\n    assert MIN_VER_FOR_COMPLEX == RELEASED_VERSIONS[1]\n\n\ndef installed_array_modules() -> dict[str, EntryPoint]:\n    \"\"\"Returns a dictionary of array module names paired to their entry points\n\n    A convenience wrapper for importlib.metadata.entry_points(). It has the\n    added benefit of working with both the original dict interface and the new\n    select interface, so this can be used warning-free in all modern Python\n    versions.\n    \"\"\"\n    return {ep.name: ep for ep in entry_points(group=\"array_api\")}\n\n\ndef flushes_to_zero(xp, width: Literal[32, 64]) -> bool:\n    \"\"\"Infer whether build of array module has its float dtype of the specified\n    width flush subnormals to zero\n\n    We do this per-width because compilers might FTZ for one dtype but allow\n    subnormals in the other.\n    \"\"\"\n    if width not in [32, 64]:\n        raise ValueError(f\"{width=}, but should be either 32 or 64\")\n    dtype = getattr(xp, f\"float{width}\")\n    return bool(xp.asarray(next_up(0.0, width=width), dtype=dtype) == 0)\n\n\ndtype_name_params = [\"bool\", *REAL_NAMES]\nfor name in COMPLEX_NAMES:\n    param = pytest.param(name, marks=pytest.mark.xp_min_version(MIN_VER_FOR_COMPLEX))\n    dtype_name_params.append(param)\n"
  },
  {
    "path": "hypothesis-python/tests/array_api/conftest.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport warnings\nfrom importlib import import_module\nfrom os import getenv\nfrom types import ModuleType, SimpleNamespace\n\nimport pytest\n\nfrom hypothesis.errors import HypothesisWarning, InvalidArgument\nfrom hypothesis.extra.array_api import (\n    NOMINAL_VERSIONS,\n    NominalVersion,\n    make_strategies_namespace,\n    mock_xp,\n)\n\nfrom tests.array_api.common import installed_array_modules\n\n# See README.md in regards to the env variables\ntest_xp_option = getenv(\"HYPOTHESIS_TEST_ARRAY_API\", \"default\")\n\ntest_version_option = getenv(\"HYPOTHESIS_TEST_ARRAY_API_VERSION\", \"default\")\nif test_version_option != \"default\" and test_version_option not in NOMINAL_VERSIONS:\n    raise ValueError(\n        f\"HYPOTHESIS_TEST_ARRAY_API_VERSION='{test_version_option}' is not \"\n        f\"'default' or a valid api_version {NOMINAL_VERSIONS}.\"\n    )\nwith warnings.catch_warnings():\n    warnings.filterwarnings(\"ignore\", category=HypothesisWarning)\n    mock_version = \"draft\" if test_version_option == \"default\" else test_version_option\n    mock_xps = make_strategies_namespace(mock_xp, api_version=mock_version)\napi_version = None if test_version_option == \"default\" else test_version_option\n\n\nclass InvalidArgumentWarning(UserWarning):\n    \"\"\"Custom warning so we can bypass our global capturing\"\"\"\n\n\nname_to_entry_point = installed_array_modules()\nxp_and_xps_pairs: list[tuple[ModuleType, SimpleNamespace]] = []\nwith warnings.catch_warnings():\n    # We ignore all warnings here as many array modules warn on import. Ideally\n    # we would just ignore ImportWarning, but no one seems to use it!\n    warnings.simplefilter(\"ignore\")\n    warnings.simplefilter(\"default\", category=InvalidArgumentWarning)\n    # We go through the steps described in README.md to define `xp_xps_pairs`,\n    # which contains the array module(s) to be run against the test suite, along\n    # with their respective strategy namespaces.\n    if test_xp_option == \"default\":\n        xp_and_xps_pairs = [(mock_xp, mock_xps)]\n    elif test_xp_option == \"all\":\n        if len(name_to_entry_point) == 0:\n            raise ValueError(\n                \"HYPOTHESIS_TEST_ARRAY_API='all', but no entry points where found\"\n            )\n        xp_and_xps_pairs = [(mock_xp, mock_xps)]\n        for ep in name_to_entry_point.values():\n            xp = ep.load()\n            try:\n                xps = make_strategies_namespace(xp, api_version=api_version)\n            except InvalidArgument as e:\n                warnings.warn(str(e), InvalidArgumentWarning, stacklevel=1)\n            else:\n                xp_and_xps_pairs.append((xp, xps))\n    elif test_xp_option in name_to_entry_point:\n        ep = name_to_entry_point[test_xp_option]\n        xp = ep.load()\n        xps = make_strategies_namespace(xp, api_version=api_version)\n        xp_and_xps_pairs = [(xp, xps)]\n    else:\n        try:\n            xp = import_module(test_xp_option)\n        except ImportError as e:\n            raise ValueError(\n                f\"HYPOTHESIS_TEST_ARRAY_API='{test_xp_option}' is not a valid \"\n                \"option ('default' or 'all'), name of an available entry point, \"\n                \"or a valid import path.\"\n            ) from e\n        else:\n            xps = make_strategies_namespace(xp, api_version=api_version)\n            xp_and_xps_pairs = [(xp, xps)]\n\n\ndef pytest_generate_tests(metafunc):\n    xp_params = []\n    xp_and_xps_params = []\n    for xp, xps in xp_and_xps_pairs:\n        xp_params.append(pytest.param(xp, id=xp.__name__))\n        xp_and_xps_params.append(\n            pytest.param(xp, xps, id=f\"{xp.__name__}-{xps.api_version}\")\n        )\n    if \"xp\" in metafunc.fixturenames:\n        if \"xps\" in metafunc.fixturenames:\n            metafunc.parametrize(\"xp, xps\", xp_and_xps_params)\n        else:\n            metafunc.parametrize(\"xp\", xp_params)\n\n\ndef pytest_collection_modifyitems(config, items):\n    for item in items:\n        if \"xps\" in item.fixturenames:\n            markers = [m for m in item.own_markers if m.name == \"xp_min_version\"]\n            if markers:\n                assert len(markers) == 1  # sanity check\n                min_version: NominalVersion = markers[0].args[0]\n                xps_version: NominalVersion = item.callspec.params[\"xps\"].api_version\n                if xps_version < min_version:\n                    item.add_marker(\n                        pytest.mark.skip(reason=f\"requires api_version=>{min_version}\")\n                    )\n"
  },
  {
    "path": "hypothesis-python/tests/array_api/test_argument_validation.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra.array_api import NominalVersion, make_strategies_namespace\n\nfrom tests.array_api.common import MIN_VER_FOR_COMPLEX\nfrom tests.common.debug import check_can_generate_examples\n\n\ndef e(name, *, _min_version: NominalVersion | None = None, **kwargs):\n    kw = \", \".join(f\"{k}={v!r}\" for k, v in kwargs.items())\n    id_ = f\"{name}({kw})\"\n    if _min_version is None:\n        marks = ()\n    else:\n        marks = pytest.mark.xp_min_version(_min_version)\n    return pytest.param(name, kwargs, id=id_, marks=marks)\n\n\n@pytest.mark.parametrize(\n    (\"strat_name\", \"kwargs\"),\n    [\n        e(\"arrays\", dtype=1, shape=5),\n        e(\"arrays\", dtype=None, shape=5),\n        e(\"arrays\", dtype=\"int8\", shape=(0.5,)),\n        e(\"arrays\", dtype=\"int8\", shape=1, fill=3),\n        e(\"arrays\", dtype=\"int8\", shape=1, elements=\"not a strategy\"),\n        e(\"arrays\", dtype=\"int8\", shape=\"not a shape or strategy\"),\n        e(\"array_shapes\", min_side=2, max_side=1),\n        e(\"array_shapes\", min_dims=3, max_dims=2),\n        e(\"array_shapes\", min_dims=-1),\n        e(\"array_shapes\", min_side=-1),\n        e(\"array_shapes\", min_side=\"not an int\"),\n        e(\"array_shapes\", max_side=\"not an int\"),\n        e(\"array_shapes\", min_dims=\"not an int\"),\n        e(\"array_shapes\", max_dims=\"not an int\"),\n        e(\"from_dtype\", dtype=1),\n        e(\"from_dtype\", dtype=None),\n        e(\"from_dtype\", dtype=\"int8\", min_value=\"not an int\"),\n        e(\"from_dtype\", dtype=\"int8\", max_value=\"not an int\"),\n        e(\"from_dtype\", dtype=\"float32\", min_value=\"not a float\"),\n        e(\"from_dtype\", dtype=\"float32\", max_value=\"not a float\"),\n        e(\"from_dtype\", dtype=\"int8\", min_value=10, max_value=5),\n        e(\"from_dtype\", dtype=\"float32\", min_value=10, max_value=5),\n        e(\"from_dtype\", dtype=\"int8\", min_value=-999),\n        e(\"from_dtype\", dtype=\"int8\", max_value=-999),\n        e(\"from_dtype\", dtype=\"int8\", min_value=999),\n        e(\"from_dtype\", dtype=\"int8\", max_value=999),\n        e(\"from_dtype\", dtype=\"uint8\", min_value=-999),\n        e(\"from_dtype\", dtype=\"uint8\", max_value=-999),\n        e(\"from_dtype\", dtype=\"uint8\", min_value=999),\n        e(\"from_dtype\", dtype=\"uint8\", max_value=999),\n        e(\"from_dtype\", dtype=\"float32\", min_value=-4e38),\n        e(\"from_dtype\", dtype=\"float32\", max_value=-4e38),\n        e(\"from_dtype\", dtype=\"float32\", min_value=4e38),\n        e(\"from_dtype\", dtype=\"float32\", max_value=4e38),\n        e(\"integer_dtypes\", sizes=()),\n        e(\"integer_dtypes\", sizes=(3,)),\n        e(\"unsigned_integer_dtypes\", sizes=()),\n        e(\"unsigned_integer_dtypes\", sizes=(3,)),\n        e(\"floating_dtypes\", sizes=()),\n        e(\"floating_dtypes\", sizes=(3,)),\n        e(\"complex_dtypes\", _min_version=MIN_VER_FOR_COMPLEX, sizes=()),\n        e(\"complex_dtypes\", _min_version=MIN_VER_FOR_COMPLEX, sizes=(3,)),\n        e(\"valid_tuple_axes\", ndim=-1),\n        e(\"valid_tuple_axes\", ndim=2, min_size=-1),\n        e(\"valid_tuple_axes\", ndim=2, min_size=3, max_size=10),\n        e(\"valid_tuple_axes\", ndim=2, min_size=2, max_size=1),\n        e(\"valid_tuple_axes\", ndim=2.0, min_size=2, max_size=1),\n        e(\"valid_tuple_axes\", ndim=2, min_size=1.0, max_size=2),\n        e(\"valid_tuple_axes\", ndim=2, min_size=1, max_size=2.0),\n        e(\"valid_tuple_axes\", ndim=2, min_size=1, max_size=3),\n        e(\"broadcastable_shapes\", shape=\"a\"),\n        e(\"broadcastable_shapes\", shape=(2, 2), min_side=\"a\"),\n        e(\"broadcastable_shapes\", shape=(2, 2), min_dims=\"a\"),\n        e(\"broadcastable_shapes\", shape=(2, 2), max_side=\"a\"),\n        e(\"broadcastable_shapes\", shape=(2, 2), max_dims=\"a\"),\n        e(\"broadcastable_shapes\", shape=(2, 2), min_side=-1),\n        e(\"broadcastable_shapes\", shape=(2, 2), min_dims=-1),\n        e(\"broadcastable_shapes\", shape=(2, 2), min_side=1, max_side=0),\n        e(\"broadcastable_shapes\", shape=(2, 2), min_dims=1, max_dims=0),\n        e(\n            \"broadcastable_shapes\",  # max_side too small\n            shape=(5, 1),\n            min_dims=2,\n            max_dims=4,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\n            \"broadcastable_shapes\",  # min_side too large\n            shape=(0, 1),\n            min_dims=2,\n            max_dims=4,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\n            \"broadcastable_shapes\",  # default max_dims unsatisfiable\n            shape=(5, 3, 2, 1),\n            min_dims=3,\n            max_dims=None,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\n            \"broadcastable_shapes\",  # default max_dims unsatisfiable\n            shape=(0, 3, 2, 1),\n            min_dims=3,\n            max_dims=None,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\"mutually_broadcastable_shapes\", num_shapes=0),\n        e(\"mutually_broadcastable_shapes\", num_shapes=\"a\"),\n        e(\"mutually_broadcastable_shapes\", num_shapes=2, base_shape=\"a\"),\n        e(\n            \"mutually_broadcastable_shapes\",  # min_side is invalid type\n            num_shapes=2,\n            min_side=\"a\",\n        ),\n        e(\n            \"mutually_broadcastable_shapes\",  # min_dims is invalid type\n            num_shapes=2,\n            min_dims=\"a\",\n        ),\n        e(\n            \"mutually_broadcastable_shapes\",  # max_side is invalid type\n            num_shapes=2,\n            max_side=\"a\",\n        ),\n        e(\n            \"mutually_broadcastable_shapes\",  # max_side is invalid type\n            num_shapes=2,\n            max_dims=\"a\",\n        ),\n        e(\n            \"mutually_broadcastable_shapes\",  # min_side is out of domain\n            num_shapes=2,\n            min_side=-1,\n        ),\n        e(\n            \"mutually_broadcastable_shapes\",  # min_dims is out of domain\n            num_shapes=2,\n            min_dims=-1,\n        ),\n        e(\n            \"mutually_broadcastable_shapes\",  # max_side < min_side\n            num_shapes=2,\n            min_side=1,\n            max_side=0,\n        ),\n        e(\n            \"mutually_broadcastable_shapes\",  # max_dims < min_dims\n            num_shapes=2,\n            min_dims=1,\n            max_dims=0,\n        ),\n        e(\n            \"mutually_broadcastable_shapes\",  # max_side too small\n            num_shapes=2,\n            base_shape=(5, 1),\n            min_dims=2,\n            max_dims=4,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\n            \"mutually_broadcastable_shapes\",  # min_side too large\n            num_shapes=2,\n            base_shape=(0, 1),\n            min_dims=2,\n            max_dims=4,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\n            \"mutually_broadcastable_shapes\",  # user-specified max_dims unsatisfiable\n            num_shapes=1,\n            base_shape=(5, 3, 2, 1),\n            min_dims=3,\n            max_dims=4,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\n            \"mutually_broadcastable_shapes\",  # user-specified max_dims unsatisfiable\n            num_shapes=2,\n            base_shape=(0, 3, 2, 1),\n            min_dims=3,\n            max_dims=4,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\"indices\", shape=0),\n        e(\"indices\", shape=(\"1\", \"2\")),\n        e(\"indices\", shape=(0, -1)),\n        e(\"indices\", shape=(0, 0), allow_newaxis=None),\n        e(\"indices\", shape=(0, 0), allow_ellipsis=None),\n        e(\"indices\", shape=(0, 0), min_dims=-1),\n        e(\"indices\", shape=(0, 0), min_dims=1.0),\n        e(\"indices\", shape=(0, 0), max_dims=-1),\n        e(\"indices\", shape=(0, 0), max_dims=1.0),\n        e(\"indices\", shape=(0, 0), min_dims=2, max_dims=1),\n        e(\"indices\", shape=(3, 3, 3), min_dims=4),\n        e(\"indices\", shape=(3, 3, 3), max_dims=5),\n        e(\"indices\", shape=5, min_dims=0),\n        e(\"indices\", shape=(5,), min_dims=2),\n        e(\"indices\", shape=(5,), max_dims=2),\n    ],\n)\ndef test_raise_invalid_argument(xp, xps, strat_name, kwargs):\n    \"\"\"Strategies raise helpful error with invalid arguments.\"\"\"\n    strat_func = getattr(xps, strat_name)\n    strat = strat_func(**kwargs)\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(strat)\n\n\n@pytest.mark.parametrize(\"api_version\", [..., \"latest\", \"1970.01\", 42])\ndef test_make_strategies_namespace_raise_invalid_argument(xp, api_version):\n    \"\"\"Function raises helpful error with invalid arguments.\"\"\"\n    with pytest.raises(InvalidArgument):\n        make_strategies_namespace(xp, api_version=api_version)\n"
  },
  {
    "path": "hypothesis-python/tests/array_api/test_arrays.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra.array_api import COMPLEX_NAMES, REAL_NAMES\nfrom hypothesis.internal.floats import width_smallest_normals\n\nfrom tests.array_api.common import (\n    MIN_VER_FOR_COMPLEX,\n    dtype_name_params,\n    flushes_to_zero,\n)\nfrom tests.common.debug import (\n    assert_all_examples,\n    check_can_generate_examples,\n    find_any,\n    minimal,\n)\nfrom tests.common.utils import flaky\n\n\ndef skip_on_missing_unique_values(xp):\n    if not hasattr(xp, \"unique_values\"):\n        pytest.mark.skip(\"xp.unique_values() is not required to exist\")\n\n\ndef xfail_on_indistinct_nans(xp):\n    \"\"\"\n    xp.unique_value() should return distinct NaNs - if not, tests that (rightly)\n    assume such behaviour will likely fail. For example, NumPy 1.22 treats NaNs\n    as indistinct, so tests that use this function will be marked as xfail.\n    See https://mail.python.org/pipermail/numpy-discussion/2021-August/081995.html\n    \"\"\"\n    skip_on_missing_unique_values(xp)\n    two_nans = xp.asarray([float(\"nan\"), float(\"nan\")])\n    if xp.unique_values(two_nans).size != 2:\n        pytest.xfail(\"NaNs not distinct\")\n\n\n@pytest.mark.parametrize(\"dtype_name\", dtype_name_params)\ndef test_draw_arrays_from_dtype(xp, xps, dtype_name):\n    \"\"\"Draw arrays from dtypes.\"\"\"\n    dtype = getattr(xp, dtype_name)\n    assert_all_examples(xps.arrays(dtype, ()), lambda x: x.dtype == dtype)\n\n\n@pytest.mark.parametrize(\"dtype_name\", dtype_name_params)\ndef test_draw_arrays_from_scalar_names(xp, xps, dtype_name):\n    \"\"\"Draw arrays from dtype names.\"\"\"\n    dtype = getattr(xp, dtype_name)\n    assert_all_examples(xps.arrays(dtype_name, ()), lambda x: x.dtype == dtype)\n\n\n@given(data=st.data())\ndef test_draw_arrays_from_shapes(xp, xps, data):\n    \"\"\"Draw arrays from shapes.\"\"\"\n    shape = data.draw(xps.array_shapes())\n    x = data.draw(xps.arrays(xp.int8, shape))\n    assert x.ndim == len(shape)\n    assert x.shape == shape\n\n\n@given(data=st.data())\ndef test_draw_arrays_from_int_shapes(xp, xps, data):\n    \"\"\"Draw arrays from integers as shapes.\"\"\"\n    size = data.draw(st.integers(0, 10))\n    x = data.draw(xps.arrays(xp.int8, size))\n    assert x.shape == (size,)\n\n\n@pytest.mark.parametrize(\n    \"strat_name\",\n    [\n        \"scalar_dtypes\",\n        \"boolean_dtypes\",\n        \"integer_dtypes\",\n        \"unsigned_integer_dtypes\",\n        \"floating_dtypes\",\n        \"real_dtypes\",\n        pytest.param(\n            \"complex_dtypes\", marks=pytest.mark.xp_min_version(MIN_VER_FOR_COMPLEX)\n        ),\n    ],\n)\ndef test_draw_arrays_from_dtype_strategies(xp, xps, strat_name):\n    \"\"\"Draw arrays from dtype strategies.\"\"\"\n    strat_func = getattr(xps, strat_name)\n    strat = strat_func()\n    find_any(xps.arrays(strat, ()))\n\n\n@settings(deadline=None)\n@given(data=st.data())\ndef test_draw_arrays_from_dtype_name_strategies(xp, xps, data):\n    \"\"\"Draw arrays from dtype name strategies.\"\"\"\n    all_names = (\"bool\", *REAL_NAMES)\n    if xps.api_version > \"2021.12\":\n        all_names += COMPLEX_NAMES\n    sample_names = data.draw(\n        st.lists(st.sampled_from(all_names), min_size=1, unique=True)\n    )\n    find_any(xps.arrays(st.sampled_from(sample_names), ()))\n\n\ndef test_generate_arrays_from_shapes_strategy(xp, xps):\n    \"\"\"Generate arrays from shapes strategy.\"\"\"\n    find_any(xps.arrays(xp.int8, xps.array_shapes()))\n\n\ndef test_generate_arrays_from_integers_strategy_as_shape(xp, xps):\n    \"\"\"Generate arrays from integers strategy as shapes strategy.\"\"\"\n    find_any(xps.arrays(xp.int8, st.integers(0, 100)))\n\n\ndef test_generate_arrays_from_zero_dimensions(xp, xps):\n    \"\"\"Generate arrays from empty shape.\"\"\"\n    assert_all_examples(xps.arrays(xp.int8, ()), lambda x: x.shape == ())\n\n\n@given(data=st.data())\ndef test_generate_arrays_from_zero_sided_shapes(xp, xps, data):\n    \"\"\"Generate arrays from shapes with at least one 0-sized dimension.\"\"\"\n    shape = data.draw(xps.array_shapes(min_side=0).filter(lambda s: 0 in s))\n    arr = data.draw(xps.arrays(xp.int8, shape))\n    assert arr.shape == shape\n\n\ndef test_generate_arrays_from_unsigned_ints(xp, xps):\n    \"\"\"Generate arrays from unsigned integer dtype.\"\"\"\n    assert_all_examples(xps.arrays(xp.uint32, (5, 5)), lambda x: xp.all(x >= 0))\n    # Ensure we're not just picking non-negative signed integers\n    signed_max = xp.iinfo(xp.int32).max\n    find_any(xps.arrays(xp.uint32, (5, 5)), lambda x: xp.any(x > signed_max))\n\n\ndef test_generate_arrays_from_0d_arrays(xp, xps):\n    \"\"\"Generate arrays from 0d array elements.\"\"\"\n    assert_all_examples(\n        xps.arrays(\n            dtype=xp.uint8,\n            shape=(5, 5),\n            elements=xps.from_dtype(xp.uint8).map(\n                lambda e: xp.asarray(e, dtype=xp.uint8)\n            ),\n        ),\n        lambda x: x.shape == (5, 5),\n    )\n\n\ndef test_minimize_arrays_with_default_dtype_shape_strategies(xp, xps):\n    \"\"\"Strategy with default scalar_dtypes and array_shapes strategies minimize\n    to a boolean 1-dimensional array of size 1.\"\"\"\n    smallest = minimal(xps.arrays(xps.scalar_dtypes(), xps.array_shapes()))\n    assert smallest.shape == (1,)\n    assert smallest.dtype == xp.bool\n    assert not xp.any(smallest)\n\n\ndef test_minimize_arrays_with_0d_shape_strategy(xp, xps):\n    \"\"\"Strategy with shape strategy that can generate empty tuples minimizes to\n    0d arrays.\"\"\"\n    smallest = minimal(xps.arrays(xp.int8, xps.array_shapes(min_dims=0)))\n    assert smallest.shape == ()\n\n\n@pytest.mark.parametrize(\"dtype\", dtype_name_params[1:])\ndef test_minimizes_numeric_arrays(xp, xps, dtype):\n    \"\"\"Strategies with numeric dtypes minimize to zero-filled arrays.\"\"\"\n    smallest = minimal(xps.arrays(dtype, (2, 2)))\n    assert xp.all(smallest == 0)\n\n\ndef test_minimize_large_uint_arrays(xp, xps):\n    \"\"\"Strategy with uint dtype and largely sized shape minimizes to a good\n    example.\"\"\"\n    if not hasattr(xp, \"nonzero\"):\n        pytest.skip(\"optional API\")\n    smallest = minimal(xps.arrays(xp.uint8, 100), lambda x: xp.any(x) and not xp.all(x))\n    assert xp.all(xp.logical_or(smallest == 0, smallest == 1))\n    idx = xp.nonzero(smallest)[0]\n    assert idx.size in (1, smallest.size - 1)\n\n\n@pytest.mark.filterwarnings(\"ignore::RuntimeWarning\")\n@flaky(max_runs=50, min_passes=1)\ndef test_minimize_float_arrays(xp, xps):\n    \"\"\"Strategy with float dtype minimizes to a good example.\n\n    We filter runtime warnings and expect flaky array generation for\n    specifically NumPy - this behaviour may not be required when testing\n    with other array libraries.\n    \"\"\"\n    smallest = minimal(xps.arrays(xp.float32, 50), lambda x: xp.sum(x) >= 1.0)\n    # TODO_IR the shrinker gets stuck when the first failure is math.inf, because\n    # downcasting inf to a float32 overflows, triggering rejection sampling which\n    # is then immediately not a shrink (specifically it overruns the attempt data).\n    #\n    # this should be resolved by adding float widths to the ir.\n    assert xp.sum(smallest) in (1, 50) or all(math.isinf(v) for v in smallest)\n\n\ndef test_minimizes_to_fill(xp, xps):\n    \"\"\"Strategy with single fill value minimizes to arrays only containing said\n    fill value.\"\"\"\n    smallest = minimal(xps.arrays(xp.float32, 10, fill=st.just(3.0)))\n    assert xp.all(smallest == 3.0)\n\n\ndef test_generate_unique_arrays(xp, xps):\n    \"\"\"Generates unique arrays.\"\"\"\n    skip_on_missing_unique_values(xp)\n    assert_all_examples(\n        xps.arrays(xp.int8, st.integers(0, 20), unique=True),\n        lambda x: xp.unique_values(x).size == x.size,\n    )\n\n\ndef test_cannot_draw_unique_arrays_with_too_small_elements(xp, xps):\n    \"\"\"Unique strategy with elements strategy range smaller than its size raises\n    helpful error.\"\"\"\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(\n            xps.arrays(xp.int8, 10, elements=st.integers(0, 5), unique=True)\n        )\n\n\ndef test_cannot_fill_arrays_with_non_castable_value(xp, xps):\n    \"\"\"Strategy with fill not castable to dtype raises helpful error.\"\"\"\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(\n            xps.arrays(xp.int8, 10, fill=st.just(\"not a castable value\"))\n        )\n\n\ndef test_generate_unique_arrays_with_high_collision_elements(xp, xps):\n    \"\"\"Generates unique arrays with just elements of 0.0 and NaN fill.\"\"\"\n\n    @given(\n        xps.arrays(\n            dtype=xp.float32,\n            shape=st.integers(0, 20),\n            elements=st.just(0.0),\n            fill=st.just(xp.nan),\n            unique=True,\n        )\n    )\n    def test(x):\n        zero_mask = x == 0.0\n        assert xp.sum(xp.astype(zero_mask, xp.uint8)) <= 1\n\n    test()\n\n\ndef test_generate_unique_arrays_using_all_elements(xp, xps):\n    \"\"\"Unique strategy with elements strategy range equal to its size will only\n    generate arrays with one of each possible element.\"\"\"\n    skip_on_missing_unique_values(xp)\n    assert_all_examples(\n        xps.arrays(xp.int8, (4,), elements=st.integers(0, 3), unique=True),\n        lambda x: xp.unique_values(x).size == x.size,\n    )\n\n\ndef test_may_fill_unique_arrays_with_nan(xp, xps):\n    \"\"\"Unique strategy with NaN fill can generate arrays holding NaNs.\"\"\"\n    find_any(\n        xps.arrays(\n            dtype=xp.float32,\n            shape=10,\n            elements={\"allow_nan\": False},\n            unique=True,\n            fill=st.just(xp.nan),\n        ),\n        lambda x: xp.any(xp.isnan(x)),\n    )\n\n\ndef test_may_not_fill_unique_array_with_non_nan(xp, xps):\n    \"\"\"Unique strategy with just fill elements of 0.0 raises helpful error.\"\"\"\n    strat = xps.arrays(\n        dtype=xp.float32,\n        shape=10,\n        elements={\"allow_nan\": False},\n        unique=True,\n        fill=st.just(0.0),\n    )\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(strat)\n\n\ndef test_floating_point_array():\n    import warnings\n\n    from hypothesis.extra.array_api import make_strategies_namespace\n\n    try:\n        with warnings.catch_warnings():\n            warnings.simplefilter(\"ignore\")\n            import numpy.array_api as nxp\n    except ModuleNotFoundError:\n        import numpy as nxp\n    xps = make_strategies_namespace(nxp)\n    dtypes = xps.floating_dtypes() | xps.complex_dtypes()\n\n    strat = xps.arrays(dtype=dtypes, shape=10)\n\n    check_can_generate_examples(strat)\n\n\n@pytest.mark.parametrize(\n    \"kwargs\",\n    [\n        {\"elements\": st.just(300)},\n        {\"elements\": st.nothing(), \"fill\": st.just(300)},\n    ],\n)\ndef test_may_not_use_overflowing_integers(xp, xps, kwargs):\n    \"\"\"Strategy with elements strategy range outside the dtype's bounds raises\n    helpful error.\"\"\"\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(xps.arrays(dtype=xp.int8, shape=1, **kwargs))\n\n\n@pytest.mark.parametrize(\"fill\", [False, True])\n@pytest.mark.parametrize(\n    \"dtype, strat\",\n    [\n        (\"float32\", st.floats(min_value=10**40, allow_infinity=False)),\n        (\"float64\", st.floats(min_value=10**40, allow_infinity=False)),\n        pytest.param(\n            \"complex64\",\n            st.complex_numbers(min_magnitude=10**300, allow_infinity=False),\n            marks=pytest.mark.xp_min_version(MIN_VER_FOR_COMPLEX),\n        ),\n    ],\n)\ndef test_may_not_use_unrepresentable_elements(xp, xps, fill, dtype, strat):\n    \"\"\"Strategy with elements not representable by the dtype raises helpful error.\"\"\"\n    if fill:\n        kw = {\"elements\": st.nothing(), \"fill\": strat}\n    else:\n        kw = {\"elements\": strat}\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(xps.arrays(dtype=dtype, shape=1, **kw))\n\n\ndef test_floats_can_be_constrained(xp, xps):\n    \"\"\"Strategy with float dtype and specified elements strategy range\n    (inclusive) generates arrays with elements inside said range.\"\"\"\n    assert_all_examples(\n        xps.arrays(\n            dtype=xp.float32, shape=10, elements={\"min_value\": 0, \"max_value\": 1}\n        ),\n        lambda x: xp.all(x >= 0) and xp.all(x <= 1),\n    )\n\n\ndef test_floats_can_be_constrained_excluding_endpoints(xp, xps):\n    \"\"\"Strategy with float dtype and specified elements strategy range\n    (exclusive) generates arrays with elements inside said range.\"\"\"\n    assert_all_examples(\n        xps.arrays(\n            dtype=xp.float32,\n            shape=10,\n            elements={\n                \"min_value\": 0,\n                \"max_value\": 1,\n                \"exclude_min\": True,\n                \"exclude_max\": True,\n            },\n        ),\n        lambda x: xp.all(x > 0) and xp.all(x < 1),\n    )\n\n\ndef test_is_still_unique_with_nan_fill(xp, xps):\n    \"\"\"Unique strategy with NaN fill generates unique arrays.\"\"\"\n    skip_on_missing_unique_values(xp)\n    xfail_on_indistinct_nans(xp)\n    assert_all_examples(\n        xps.arrays(\n            dtype=xp.float32,\n            elements={\"allow_nan\": False},\n            shape=10,\n            unique=True,\n            fill=st.just(xp.nan),\n        ),\n        lambda x: xp.unique_values(x).size == x.size,\n    )\n\n\ndef test_unique_array_with_fill_can_use_all_elements(xp, xps):\n    \"\"\"Unique strategy with elements range equivalent to its size and NaN fill\n    can generate arrays with all possible values.\"\"\"\n    skip_on_missing_unique_values(xp)\n    xfail_on_indistinct_nans(xp)\n    find_any(\n        xps.arrays(\n            dtype=xp.float32,\n            shape=10,\n            unique=True,\n            elements=st.integers(1, 9),\n            fill=st.just(xp.nan),\n        ),\n        lambda x: xp.unique_values(x).size == x.size,\n    )\n\n\ndef test_generate_unique_arrays_without_fill(xp, xps):\n    \"\"\"Generate arrays from unique strategy with no fill.\n\n    Covers the collision-related branches for fully dense unique arrays.\n    Choosing 25 of 256 possible values means we're almost certain to see\n    collisions thanks to the birthday paradox, but finding unique values should\n    still be easy.\n    \"\"\"\n    skip_on_missing_unique_values(xp)\n    assert_all_examples(\n        xps.arrays(dtype=xp.uint8, shape=25, unique=True, fill=st.nothing()),\n        lambda x: xp.unique_values(x).size == x.size,\n    )\n\n\ndef test_efficiently_generate_unique_arrays_using_all_elements(xp, xps):\n    \"\"\"Unique strategy with elements strategy range equivalent to its size\n    generates arrays with all possible values. Generation is not too slow.\n\n    Avoids the birthday paradox with UniqueSampledListStrategy.\n    \"\"\"\n    skip_on_missing_unique_values(xp)\n    assert_all_examples(\n        xps.arrays(dtype=xp.int8, shape=255, unique=True),\n        lambda x: xp.unique_values(x).size == x.size,\n    )\n\n\n@given(st.data(), st.integers(-100, 100), st.integers(1, 100))\ndef test_array_element_rewriting(xp, xps, data, start, size):\n    \"\"\"Unique strategy generates arrays with expected elements.\"\"\"\n    x = data.draw(\n        xps.arrays(\n            dtype=xp.int64,\n            shape=size,\n            elements=st.integers(start, start + size - 1),\n            unique=True,\n        )\n    )\n    x_set_expect = xp.arange(start, start + size, dtype=xp.int64)\n    x_set = xp.sort(xp.unique_values(x))\n    assert xp.all(x_set == x_set_expect)\n\n\ndef test_generate_0d_arrays_with_no_fill(xp, xps):\n    \"\"\"Generate arrays with zero-dimensions and no fill.\"\"\"\n    assert_all_examples(\n        xps.arrays(xp.bool, (), fill=st.nothing()),\n        lambda x: x.dtype == xp.bool and x.shape == (),\n    )\n\n\n@pytest.mark.parametrize(\"dtype\", [\"float32\", \"float64\"])\n@pytest.mark.parametrize(\"low\", [-2.0, -1.0, 0.0, 1.0])\n@given(st.data())\ndef test_excluded_min_in_float_arrays(xp, xps, dtype, low, data):\n    \"\"\"Strategy with elements strategy excluding min does not generate arrays\n    with elements less or equal to said min.\"\"\"\n    strat = xps.arrays(\n        dtype=dtype,\n        shape=(),\n        elements={\n            \"min_value\": low,\n            \"max_value\": low + 1,\n            \"exclude_min\": True,\n        },\n    )\n    x = data.draw(strat, label=\"array\")\n    assert xp.all(x > low)\n\n\n@st.composite\ndef distinct_int64_integers(draw):\n    used = draw(st.shared(st.builds(set), key=\"distinct_int64_integers.used\"))\n    i = draw(st.integers(-(2**63), 2**63 - 1).filter(lambda x: x not in used))\n    used.add(i)\n    return i\n\n\ndef test_does_not_reuse_distinct_integers(xp, xps):\n    \"\"\"Strategy with distinct integer elements strategy generates arrays with\n    distinct values.\"\"\"\n    skip_on_missing_unique_values(xp)\n    assert_all_examples(\n        xps.arrays(xp.int64, 10, elements=distinct_int64_integers()),\n        lambda x: xp.unique_values(x).size == x.size,\n    )\n\n\ndef test_may_reuse_distinct_integers_if_asked(xp, xps):\n    \"\"\"Strategy with shared elements and fill strategies of distinct integers\n    may generate arrays with non-distinct values.\"\"\"\n    skip_on_missing_unique_values(xp)\n    find_any(\n        xps.arrays(\n            xp.int64,\n            10,\n            elements=distinct_int64_integers(),\n            fill=distinct_int64_integers(),\n        ),\n        lambda x: xp.unique_values(x).size < x.size,\n    )\n\n\ndef test_subnormal_elements_validation(xp, xps):\n    \"\"\"Strategy with subnormal elements strategy is correctly validated.\n\n    For FTZ builds of array modules, a helpful error should raise. Conversely,\n    for builds of array modules which support subnormals, the strategy should\n    generate arrays without raising.\n    \"\"\"\n    elements = {\n        \"min_value\": 0.0,\n        \"max_value\": width_smallest_normals[32],\n        \"exclude_min\": True,\n        \"exclude_max\": True,\n        \"allow_subnormal\": True,\n    }\n    strat = xps.arrays(xp.float32, 10, elements=elements)\n    if flushes_to_zero(xp, width=32):\n        with pytest.raises(InvalidArgument, match=\"Generated subnormal float\"):\n            check_can_generate_examples(strat)\n    else:\n        check_can_generate_examples(strat)\n"
  },
  {
    "path": "hypothesis-python/tests/array_api/test_from_dtype.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\n\nimport pytest\n\nfrom hypothesis.extra.array_api import find_castable_builtin_for_dtype\nfrom hypothesis.internal.floats import width_smallest_normals\n\nfrom tests.array_api.common import dtype_name_params, flushes_to_zero\nfrom tests.common.debug import (\n    assert_all_examples,\n    assert_no_examples,\n    find_any,\n    minimal,\n)\n\n\n@pytest.mark.parametrize(\"dtype_name\", dtype_name_params)\ndef test_strategies_have_reusable_values(xp, xps, dtype_name):\n    \"\"\"Inferred strategies have reusable values.\"\"\"\n    strat = xps.from_dtype(dtype_name)\n    assert strat.has_reusable_values\n\n\n@pytest.mark.parametrize(\"dtype_name\", dtype_name_params)\ndef test_produces_castable_instances_from_dtype(xp, xps, dtype_name):\n    \"\"\"Strategies inferred by dtype generate values of a builtin type castable\n    to the dtype.\"\"\"\n    dtype = getattr(xp, dtype_name)\n    builtin = find_castable_builtin_for_dtype(xp, xps.api_version, dtype)\n    assert_all_examples(xps.from_dtype(dtype), lambda v: isinstance(v, builtin))\n\n\n@pytest.mark.parametrize(\"dtype_name\", dtype_name_params)\ndef test_produces_castable_instances_from_name(xp, xps, dtype_name):\n    \"\"\"Strategies inferred by dtype name generate values of a builtin type\n    castable to the dtype.\"\"\"\n    dtype = getattr(xp, dtype_name)\n    builtin = find_castable_builtin_for_dtype(xp, xps.api_version, dtype)\n    assert_all_examples(xps.from_dtype(dtype_name), lambda v: isinstance(v, builtin))\n\n\n@pytest.mark.parametrize(\"dtype_name\", dtype_name_params)\ndef test_passing_inferred_strategies_in_arrays(xp, xps, dtype_name):\n    \"\"\"Inferred strategies usable in arrays strategy.\"\"\"\n    elements = xps.from_dtype(dtype_name)\n    find_any(xps.arrays(dtype_name, 10, elements=elements))\n\n\n@pytest.mark.parametrize(\n    \"dtype, kwargs, predicate\",\n    [\n        # Floating point: bounds, exclusive bounds, and excluding nonfinites\n        (\"float32\", {\"min_value\": 1, \"max_value\": 2}, lambda x: 1 <= x <= 2),\n        (\n            \"float32\",\n            {\"min_value\": 1, \"max_value\": 2, \"exclude_min\": True, \"exclude_max\": True},\n            lambda x: 1 < x < 2,\n        ),\n        (\"float32\", {\"allow_nan\": False}, lambda x: not math.isnan(x)),\n        (\"float32\", {\"allow_infinity\": False}, lambda x: not math.isinf(x)),\n        (\"float32\", {\"allow_nan\": False, \"allow_infinity\": False}, math.isfinite),\n        # Integer bounds, limited to the representable range\n        (\"int8\", {\"min_value\": -1, \"max_value\": 1}, lambda x: -1 <= x <= 1),\n        (\"uint8\", {\"min_value\": 1, \"max_value\": 2}, lambda x: 1 <= x <= 2),\n    ],\n)\ndef test_from_dtype_with_kwargs(xp, xps, dtype, kwargs, predicate):\n    \"\"\"Strategies inferred with kwargs generate values in bounds.\"\"\"\n    strat = xps.from_dtype(dtype, **kwargs)\n    assert_all_examples(strat, predicate)\n\n\ndef test_can_minimize_floats(xp, xps):\n    \"\"\"Inferred float strategy minimizes to a good example.\"\"\"\n    smallest = minimal(xps.from_dtype(xp.float32), lambda n: n >= 1.0)\n    # TODO_IR should be resolved by float widths on the ir, see other TODO_IR comments\n    assert smallest in {1, math.inf}\n\n\nsmallest_normal = width_smallest_normals[32]\n\n\n@pytest.mark.parametrize(\n    \"kwargs\",\n    [\n        {},\n        {\"min_value\": -1},\n        {\"max_value\": 1},\n        {\"min_value\": -1, \"max_value\": 1},\n    ],\n)\ndef test_subnormal_generation(xp, xps, kwargs):\n    \"\"\"Generation of subnormals is dependent on FTZ behaviour of array module.\"\"\"\n    strat = xps.from_dtype(xp.float32, **kwargs).filter(lambda n: n != 0)\n    if flushes_to_zero(xp, width=32):\n        assert_no_examples(strat, lambda n: -smallest_normal < n < smallest_normal)\n    else:\n        find_any(strat, lambda n: -smallest_normal < n < smallest_normal)\n"
  },
  {
    "path": "hypothesis-python/tests/array_api/test_indices.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\n\nimport pytest\n\nfrom hypothesis import assume, given, note, strategies as st\nfrom hypothesis.extra._array_helpers import NDIM_MAX\n\nfrom tests.common.debug import assert_all_examples, find_any\n\n\n@pytest.mark.parametrize(\n    \"condition\",\n    [\n        lambda ix: Ellipsis in ix,\n        lambda ix: Ellipsis not in ix,\n        lambda ix: None in ix,\n        lambda ix: None not in ix,\n    ],\n)\ndef test_generate_optional_indices(xp, xps, condition):\n    \"\"\"Strategy can generate indices with optional values.\"\"\"\n    strat = (\n        xps.array_shapes(min_dims=1, max_dims=32)\n        .flatmap(lambda s: xps.indices(s, allow_newaxis=True))\n        .map(lambda idx: idx if isinstance(idx, tuple) else (idx,))\n    )\n    find_any(strat, condition)\n\n\ndef test_cannot_generate_newaxis_when_disabled(xp, xps):\n    \"\"\"Strategy does not generate newaxis when disabled (i.e. the default).\"\"\"\n    assert_all_examples(\n        xps.indices((3, 3, 3)), lambda idx: idx == ... or None not in idx\n    )\n\n\ndef test_generate_indices_for_0d_shape(xp, xps):\n    \"\"\"Strategy only generates empty tuples or Ellipsis as indices for an empty\n    shape.\"\"\"\n    assert_all_examples(\n        xps.indices(shape=(), allow_ellipsis=True),\n        lambda idx: idx in [(), Ellipsis, (Ellipsis,)],\n    )\n\n\ndef test_generate_tuples_and_non_tuples_for_1d_shape(xp, xps):\n    \"\"\"Strategy can generate tuple and non-tuple indices with a 1-dimensional shape.\"\"\"\n    strat = xps.indices(shape=(1,), allow_ellipsis=True)\n    find_any(strat, lambda ix: isinstance(ix, tuple))\n    find_any(strat, lambda ix: not isinstance(ix, tuple))\n\n\ndef test_generate_long_ellipsis(xp, xps):\n    \"\"\"Strategy can replace runs of slice(None) with Ellipsis.\n\n    We specifically test if [0,...,0] is generated alongside [0,:,:,:,0]\n    \"\"\"\n    strat = xps.indices(shape=(1, 0, 0, 0, 1), max_dims=3, allow_ellipsis=True)\n    find_any(strat, lambda ix: len(ix) == 3 and ix[1] == Ellipsis)\n    find_any(\n        strat,\n        lambda ix: len(ix) == 5\n        and all(isinstance(key, slice) and key == slice(None) for key in ix[1:3]),\n    )\n\n\ndef test_indices_replaces_whole_axis_slices_with_ellipsis(xp, xps):\n    # `slice(None)` (aka `:`) is the only valid index for an axis of size\n    # zero, so if all dimensions are 0 then a `...` will replace all the\n    # slices because we generate `...` for entire contiguous runs of `:`\n    assert_all_examples(\n        xps.indices(shape=(0, 0, 0, 0, 0), max_dims=5).filter(\n            lambda idx: isinstance(idx, tuple) and Ellipsis in idx\n        ),\n        lambda idx: slice(None) not in idx,\n    )\n\n\ndef test_efficiently_generate_indexers(xp, xps):\n    \"\"\"Generation is not too slow.\"\"\"\n    find_any(xps.indices((3, 3, 3, 3, 3)))\n\n\n@given(allow_newaxis=st.booleans(), allow_ellipsis=st.booleans(), data=st.data())\ndef test_generate_valid_indices(xp, xps, allow_newaxis, allow_ellipsis, data):\n    \"\"\"Strategy generates valid indices.\"\"\"\n    shape = data.draw(\n        xps.array_shapes(min_dims=1, max_side=4)\n        | xps.array_shapes(min_dims=1, min_side=0, max_side=10),\n        label=\"shape\",\n    )\n    min_dims = data.draw(\n        st.integers(0, len(shape) if not allow_newaxis else len(shape) + 2),\n        label=\"min_dims\",\n    )\n    max_dims = data.draw(\n        st.none()\n        | st.integers(min_dims, len(shape) if not allow_newaxis else NDIM_MAX),\n        label=\"max_dims\",\n    )\n    indexer = data.draw(\n        xps.indices(\n            shape,\n            min_dims=min_dims,\n            max_dims=max_dims,\n            allow_newaxis=allow_newaxis,\n            allow_ellipsis=allow_ellipsis,\n        ),\n        label=\"indexer\",\n    )\n\n    _indexer = indexer if isinstance(indexer, tuple) else (indexer,)\n    # Check that disallowed things are indeed absent\n    if not allow_ellipsis:\n        assert Ellipsis not in _indexer\n    if not allow_newaxis:\n        assert None not in _indexer  # i.e. xp.newaxis\n    # Check index is composed of valid objects\n    for i in _indexer:\n        assert isinstance(i, (int, slice)) or i is None or i == Ellipsis\n    # Check indexer does not flat index\n    nonexpanding_indexer = [i for i in _indexer if i is not None]\n    if Ellipsis in _indexer:\n        assert sum(i == Ellipsis for i in _indexer) == 1\n        # Note ellipsis can index 0 axes\n        assert len(nonexpanding_indexer) <= len(shape) + 1\n    else:\n        assert len(nonexpanding_indexer) == len(shape)\n\n    if 0 in shape:\n        # If there's a zero in the shape, the array will have no elements.\n        array = xp.zeros(shape)\n        assert array.size == 0  # sanity check\n    elif math.prod(shape) <= 10**5:\n        # If it's small enough to instantiate, do so with distinct elements.\n        array = xp.reshape(xp.arange(math.prod(shape)), shape)\n    else:\n        # We can't cheat on this one, so just try another.\n        assume(False)\n    # Finally, check that we can use our indexer without error\n    note(f\"{array=}\")\n    array[indexer]\n"
  },
  {
    "path": "hypothesis-python/tests/array_api/test_partial_adoptors.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport functools\nimport warnings\nfrom copy import copy\nfrom types import SimpleNamespace\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import HypothesisWarning, InvalidArgument\nfrom hypothesis.extra.array_api import (\n    COMPLEX_NAMES,\n    DTYPE_NAMES,\n    FLOAT_NAMES,\n    INT_NAMES,\n    UINT_NAMES,\n    make_strategies_namespace,\n    mock_xp,\n)\n\nfrom tests.common.debug import check_can_generate_examples\n\nMOCK_WARN_MSG = f\"determine.*{mock_xp.__name__}.*Array API\"\n\n\nclass MockedArray:\n    def __init__(self, wrapped, *, exclude=()):\n        self.wrapped = wrapped\n        self.exclude = exclude\n\n    def __getattr__(self, name):\n        if name in self.exclude:\n            raise AttributeError(f\"removed on the mock: {name}\")\n\n        return object.__getattr__(self, name)\n\n\ndef wrap_array(func: callable, exclude: tuple[str, ...] = ()) -> callable:\n    @functools.wraps(func)\n    def wrapped(*args, **kwargs):\n        result = func(*args, **kwargs)\n\n        if isinstance(result, tuple):\n            return tuple(MockedArray(arr, exclude=exclude) for arr in result)\n\n        return MockedArray(result, exclude=exclude)\n\n    return wrapped\n\n\ndef make_mock_xp(\n    *, exclude: tuple[str, ...] = (), exclude_methods: tuple[str, ...] = ()\n) -> SimpleNamespace:\n    xp = copy(mock_xp)\n    assert isinstance(exclude, tuple)  # sanity check\n    assert isinstance(exclude_methods, tuple)  # sanity check\n    for attr in exclude:\n        delattr(xp, attr)\n\n    array_returning_funcs = (\n        \"astype\",\n        \"broadcast_arrays\",\n        \"arange\",\n        \"asarray\",\n        \"empty\",\n        \"zeros\",\n        \"ones\",\n        \"reshape\",\n        \"isnan\",\n        \"isfinite\",\n        \"logical_or\",\n        \"sum\",\n        \"nonzero\",\n        \"sort\",\n        \"unique_values\",\n        \"any\",\n        \"all\",\n    )\n\n    for name in array_returning_funcs:\n        func = getattr(xp, name, None)\n        if func is None:\n            # removed in the step before\n            continue\n        setattr(xp, name, wrap_array(func, exclude=exclude_methods))\n\n    return xp\n\n\ndef test_warning_on_noncompliant_xp():\n    \"\"\"Using non-compliant array modules raises helpful warning\"\"\"\n    xp = make_mock_xp(exclude_methods=(\"__array_namespace__\",))\n    with pytest.warns(HypothesisWarning, match=MOCK_WARN_MSG):\n        make_strategies_namespace(xp, api_version=\"draft\")\n\n\n@pytest.mark.filterwarnings(f\"ignore:.*{MOCK_WARN_MSG}.*\")\n@pytest.mark.parametrize(\n    \"stratname, args, attr\",\n    [(\"from_dtype\", [\"int8\"], \"iinfo\"), (\"arrays\", [\"int8\", 5], \"asarray\")],\n)\ndef test_error_on_missing_attr(stratname, args, attr):\n    \"\"\"Strategies raise helpful error when using array modules that lack\n    required attributes.\"\"\"\n    xp = make_mock_xp(exclude=(attr,))\n    xps = make_strategies_namespace(xp, api_version=\"draft\")\n    func = getattr(xps, stratname)\n    with pytest.raises(InvalidArgument, match=f\"{mock_xp.__name__}.*required.*{attr}\"):\n        check_can_generate_examples(func(*args))\n\n\ndtypeless_xp = make_mock_xp(exclude=tuple(DTYPE_NAMES))\nwith warnings.catch_warnings():\n    warnings.filterwarnings(\"ignore\", category=HypothesisWarning)\n    dtypeless_xps = make_strategies_namespace(dtypeless_xp, api_version=\"draft\")\n\n\n@pytest.mark.parametrize(\n    \"stratname\",\n    [\n        \"scalar_dtypes\",\n        \"boolean_dtypes\",\n        \"numeric_dtypes\",\n        \"integer_dtypes\",\n        \"unsigned_integer_dtypes\",\n        \"floating_dtypes\",\n        \"real_dtypes\",\n        \"complex_dtypes\",\n    ],\n)\ndef test_error_on_missing_dtypes(stratname):\n    \"\"\"Strategies raise helpful error when using array modules that lack\n    required dtypes.\"\"\"\n    func = getattr(dtypeless_xps, stratname)\n    with pytest.raises(InvalidArgument, match=f\"{mock_xp.__name__}.*dtype.*namespace\"):\n        check_can_generate_examples(func())\n\n\n@pytest.mark.filterwarnings(f\"ignore:.*{MOCK_WARN_MSG}.*\")\n@pytest.mark.parametrize(\n    \"stratname, keep_anys\",\n    [\n        (\"scalar_dtypes\", [INT_NAMES, UINT_NAMES, FLOAT_NAMES]),\n        (\"numeric_dtypes\", [INT_NAMES, UINT_NAMES, FLOAT_NAMES, COMPLEX_NAMES]),\n        (\"integer_dtypes\", [INT_NAMES]),\n        (\"unsigned_integer_dtypes\", [UINT_NAMES]),\n        (\"floating_dtypes\", [FLOAT_NAMES]),\n        (\"real_dtypes\", [INT_NAMES, UINT_NAMES, FLOAT_NAMES]),\n        (\"complex_dtypes\", [COMPLEX_NAMES]),\n    ],\n)\n@given(st.data())\ndef test_warning_on_partial_dtypes(stratname, keep_anys, data):\n    \"\"\"Strategies using array modules with at least one of a dtype in the\n    necessary category/categories execute with a warning.\"\"\"\n    exclude = []\n    for keep_any in keep_anys:\n        exclude.extend(\n            data.draw(\n                st.lists(\n                    st.sampled_from(keep_any),\n                    min_size=1,\n                    max_size=len(keep_any) - 1,\n                    unique=True,\n                )\n            )\n        )\n    xp = make_mock_xp(exclude=tuple(exclude))\n    xps = make_strategies_namespace(xp, api_version=\"draft\")\n    func = getattr(xps, stratname)\n    with pytest.warns(HypothesisWarning, match=f\"{mock_xp.__name__}.*dtype.*namespace\"):\n        data.draw(func())\n\n\ndef test_raises_on_inferring_with_no_dunder_version():\n    \"\"\"When xp has no __array_api_version__, inferring api_version raises\n    helpful error.\"\"\"\n    xp = make_mock_xp(exclude=(\"__array_api_version__\",))\n    with pytest.raises(InvalidArgument, match=\"has no attribute\"):\n        make_strategies_namespace(xp)\n\n\ndef test_raises_on_invalid_dunder_version():\n    \"\"\"When xp has invalid __array_api_version__, inferring api_version raises\n    helpful error.\"\"\"\n    xp = make_mock_xp()\n    xp.__array_api_version__ = None\n    with pytest.raises(InvalidArgument):\n        make_strategies_namespace(xp)\n"
  },
  {
    "path": "hypothesis-python/tests/array_api/test_pretty.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom inspect import signature\n\nimport pytest\n\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra import array_api\nfrom hypothesis.extra.array_api import make_strategies_namespace\n\nfrom tests.array_api.common import MIN_VER_FOR_COMPLEX\n\n\n@pytest.mark.parametrize(\n    \"name\",\n    [\n        \"from_dtype\",\n        \"arrays\",\n        \"array_shapes\",\n        \"scalar_dtypes\",\n        \"boolean_dtypes\",\n        \"numeric_dtypes\",\n        \"integer_dtypes\",\n        \"unsigned_integer_dtypes\",\n        \"floating_dtypes\",\n        \"real_dtypes\",\n        pytest.param(\n            \"complex_dtypes\", marks=pytest.mark.xp_min_version(MIN_VER_FOR_COMPLEX)\n        ),\n        \"valid_tuple_axes\",\n        \"broadcastable_shapes\",\n        \"mutually_broadcastable_shapes\",\n        \"indices\",\n    ],\n)\ndef test_namespaced_methods_meta(xp, xps, name):\n    \"\"\"Namespaced method objects have good meta attributes.\"\"\"\n    func = getattr(xps, name)\n    assert func.__name__ == name\n    assert func.__doc__ is not None\n    # The (private) top-level strategy methods may expose a xp argument in their\n    # function signatures. make_strategies_namespace() exists to wrap these\n    # top-level methods by binding the passed xp argument, and so the namespace\n    # it returns should not expose xp in any of its function signatures.\n    assert \"xp\" not in signature(func).parameters\n\n\n@pytest.mark.parametrize(\n    \"name, valid_args\",\n    [\n        (\"from_dtype\", [\"int8\"]),\n        (\"arrays\", [\"int8\", 5]),\n        (\"array_shapes\", []),\n        (\"scalar_dtypes\", []),\n        (\"boolean_dtypes\", []),\n        (\"numeric_dtypes\", []),\n        (\"integer_dtypes\", []),\n        (\"unsigned_integer_dtypes\", []),\n        (\"floating_dtypes\", []),\n        (\"real_dtypes\", []),\n        pytest.param(\n            \"complex_dtypes\", [], marks=pytest.mark.xp_min_version(MIN_VER_FOR_COMPLEX)\n        ),\n        (\"valid_tuple_axes\", [0]),\n        (\"broadcastable_shapes\", [()]),\n        (\"mutually_broadcastable_shapes\", [3]),\n        (\"indices\", [(5,)]),\n    ],\n)\ndef test_namespaced_strategies_repr(xp, xps, name, valid_args):\n    \"\"\"Namespaced strategies have good repr.\"\"\"\n    func = getattr(xps, name)\n    strat = func(*valid_args)\n    assert repr(strat).startswith(name + \"(\"), f\"{name} not in strat repr {strat!r}\"\n    assert len(repr(strat)) < 100, \"strat repr looks too long\"\n    assert xp.__name__ not in repr(strat), f\"{xp.__name__} in strat repr\"\n\n\n@pytest.mark.filterwarnings(\"ignore::hypothesis.errors.HypothesisWarning\")\ndef test_inferred_version_strategies_namespace_repr(xp):\n    \"\"\"Strategies namespace has good repr when api_version=None.\"\"\"\n    try:\n        xps = make_strategies_namespace(xp)\n    except InvalidArgument as e:\n        pytest.skip(str(e))\n    expected = f\"make_strategies_namespace({xp.__name__})\"\n    assert repr(xps) == expected\n    assert str(xps) == expected\n\n\n@pytest.mark.filterwarnings(\"ignore::hypothesis.errors.HypothesisWarning\")\ndef test_specified_version_strategies_namespace_repr(xp, monkeypatch):\n    \"\"\"Strategies namespace has good repr when api_version is specified.\"\"\"\n    monkeypatch.setattr(array_api, \"_args_to_xps\", {})  # ignore cached versions\n    xps = make_strategies_namespace(xp, api_version=\"2021.12\")\n    expected = f\"make_strategies_namespace({xp.__name__}, api_version='2021.12')\"\n    assert repr(xps) == expected\n    assert str(xps) == expected\n"
  },
  {
    "path": "hypothesis-python/tests/array_api/test_scalar_dtypes.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis.extra.array_api import (\n    COMPLEX_NAMES,\n    DTYPE_NAMES,\n    FLOAT_NAMES,\n    INT_NAMES,\n    NUMERIC_NAMES,\n    REAL_NAMES,\n    UINT_NAMES,\n)\n\nfrom tests.array_api.common import MIN_VER_FOR_COMPLEX\nfrom tests.common.debug import assert_all_examples, find_any, minimal\n\n\n@pytest.mark.parametrize(\n    (\"strat_name\", \"dtype_names\"),\n    [\n        (\"integer_dtypes\", INT_NAMES),\n        (\"unsigned_integer_dtypes\", UINT_NAMES),\n        (\"floating_dtypes\", FLOAT_NAMES),\n        (\"real_dtypes\", REAL_NAMES),\n        pytest.param(\n            \"complex_dtypes\",\n            COMPLEX_NAMES,\n            marks=pytest.mark.xp_min_version(MIN_VER_FOR_COMPLEX),\n        ),\n    ],\n)\ndef test_all_generated_dtypes_are_of_group(xp, xps, strat_name, dtype_names):\n    \"\"\"Strategy only generates expected dtypes.\"\"\"\n    strat_func = getattr(xps, strat_name)\n    dtypes = [getattr(xp, n) for n in dtype_names]\n    assert_all_examples(strat_func(), lambda dtype: dtype in dtypes)\n\n\ndef test_all_generated_scalar_dtypes_are_scalar(xp, xps):\n    \"\"\"Strategy only generates scalar dtypes.\"\"\"\n    if xps.api_version > \"2021.12\":\n        dtypes = [getattr(xp, n) for n in DTYPE_NAMES]\n    else:\n        dtypes = [getattr(xp, n) for n in (\"bool\", *REAL_NAMES)]\n    assert_all_examples(xps.scalar_dtypes(), lambda dtype: dtype in dtypes)\n\n\ndef test_all_generated_numeric_dtypes_are_numeric(xp, xps):\n    \"\"\"Strategy only generates numeric dtypes.\"\"\"\n    if xps.api_version > \"2021.12\":\n        dtypes = [getattr(xp, n) for n in NUMERIC_NAMES]\n    else:\n        dtypes = [getattr(xp, n) for n in REAL_NAMES]\n    assert_all_examples(xps.numeric_dtypes(), lambda dtype: dtype in dtypes)\n\n\ndef skipif_unsupported_complex(strat_name, dtype_name):\n    if not dtype_name.startswith(\"complex\"):\n        return strat_name, dtype_name\n    mark = pytest.mark.xp_min_version(MIN_VER_FOR_COMPLEX)\n    return pytest.param(strat_name, dtype_name, marks=mark)\n\n\n@pytest.mark.parametrize(\n    (\"strat_name\", \"dtype_name\"),\n    [\n        *[skipif_unsupported_complex(\"scalar_dtypes\", n) for n in DTYPE_NAMES],\n        *[skipif_unsupported_complex(\"numeric_dtypes\", n) for n in NUMERIC_NAMES],\n        *[(\"integer_dtypes\", n) for n in INT_NAMES],\n        *[(\"unsigned_integer_dtypes\", n) for n in UINT_NAMES],\n        *[(\"floating_dtypes\", n) for n in FLOAT_NAMES],\n        *[(\"real_dtypes\", n) for n in REAL_NAMES],\n        *[skipif_unsupported_complex(\"complex_dtypes\", n) for n in COMPLEX_NAMES],\n    ],\n)\ndef test_strategy_can_generate_every_dtype(xp, xps, strat_name, dtype_name):\n    \"\"\"Strategy generates every expected dtype.\"\"\"\n    strat_func = getattr(xps, strat_name)\n    dtype = getattr(xp, dtype_name)\n    find_any(strat_func(), lambda d: d == dtype)\n\n\ndef test_minimise_scalar_dtypes(xp, xps):\n    \"\"\"Strategy minimizes to bool dtype.\"\"\"\n    assert minimal(xps.scalar_dtypes()) == xp.bool\n\n\n@pytest.mark.parametrize(\n    \"strat_name, sizes\",\n    [\n        (\"integer_dtypes\", 8),\n        (\"unsigned_integer_dtypes\", 8),\n        (\"floating_dtypes\", 32),\n        pytest.param(\n            \"complex_dtypes\", 64, marks=pytest.mark.xp_min_version(MIN_VER_FOR_COMPLEX)\n        ),\n    ],\n)\ndef test_can_specify_sizes_as_an_int(xp, xps, strat_name, sizes):\n    \"\"\"Strategy treats ints as a single size.\"\"\"\n    strat_func = getattr(xps, strat_name)\n    strat = strat_func(sizes=sizes)\n    find_any(strat)\n"
  },
  {
    "path": "hypothesis-python/tests/array_api/test_strategies_namespace.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom types import SimpleNamespace\nfrom weakref import WeakValueDictionary\n\nimport pytest\n\nfrom hypothesis.control import settings\nfrom hypothesis.extra import array_api\nfrom hypothesis.extra.array_api import (\n    NOMINAL_VERSIONS,\n    make_strategies_namespace,\n    mock_xp,\n)\nfrom hypothesis.strategies import SearchStrategy\n\npytestmark = [\n    pytest.mark.filterwarnings(\"ignore::hypothesis.errors.HypothesisWarning\"),\n    pytest.mark.skipif(\n        settings.get_current_profile_name() == \"threading\",\n        reason=\"make_strategies_namespace is not thread safe\",\n    ),\n]\n\n\nclass HashableArrayModuleFactory:\n    \"\"\"\n    mock_xp cannot be hashed and thus cannot be used in our cache. So just for\n    the purposes of testing the cache, we wrap it with an unsafe hash method.\n    \"\"\"\n\n    def __getattr__(self, name):\n        return getattr(mock_xp, name)\n\n    def __hash__(self):\n        return hash(tuple(sorted(mock_xp.__dict__)))\n\n\n@pytest.mark.parametrize(\"api_version\", [\"2021.12\", None])\ndef test_caching(api_version, monkeypatch):\n    \"\"\"Caches namespaces respective to arguments.\"\"\"\n    xp = HashableArrayModuleFactory()\n    assert isinstance(array_api._args_to_xps, WeakValueDictionary)  # sanity check\n    monkeypatch.setattr(array_api, \"_args_to_xps\", WeakValueDictionary())\n    assert len(array_api._args_to_xps) == 0  # sanity check\n    xps1 = array_api.make_strategies_namespace(xp, api_version=api_version)\n    assert len(array_api._args_to_xps) == 1\n    xps2 = array_api.make_strategies_namespace(xp, api_version=api_version)\n    assert len(array_api._args_to_xps) == 1\n    assert isinstance(xps2, SimpleNamespace)\n    assert xps2 is xps1\n    del xps1\n    del xps2\n    assert len(array_api._args_to_xps) == 0\n\n\n@pytest.mark.parametrize(\n    \"api_version1, api_version2\", [(None, \"2021.12\"), (\"2021.12\", None)]\n)\ndef test_inferred_namespace_shares_cache(api_version1, api_version2, monkeypatch):\n    \"\"\"Results from inferred versions share the same cache key as results\n    from specified versions.\"\"\"\n    xp = HashableArrayModuleFactory()\n    xp.__array_api_version__ = \"2021.12\"\n    assert isinstance(array_api._args_to_xps, WeakValueDictionary)  # sanity check\n    monkeypatch.setattr(array_api, \"_args_to_xps\", WeakValueDictionary())\n    assert len(array_api._args_to_xps) == 0  # sanity check\n    xps1 = array_api.make_strategies_namespace(xp, api_version=api_version1)\n    assert xps1.api_version == \"2021.12\"  # sanity check\n    assert len(array_api._args_to_xps) == 1\n    xps2 = array_api.make_strategies_namespace(xp, api_version=api_version2)\n    assert xps2.api_version == \"2021.12\"  # sanity check\n    assert len(array_api._args_to_xps) == 1\n    assert xps2 is xps1\n\n\ndef test_complex_dtypes_raises_on_2021_12():\n    \"\"\"Accessing complex_dtypes() for 2021.12 strategy namespace raises helpful\n    error, but accessing on future versions returns expected strategy.\"\"\"\n    first_xps = make_strategies_namespace(mock_xp, api_version=\"2021.12\")\n    with pytest.raises(AttributeError, match=\"attempted to access\"):\n        first_xps.complex_dtypes()\n    for api_version in NOMINAL_VERSIONS[1:]:\n        xps = make_strategies_namespace(mock_xp, api_version=api_version)\n        assert isinstance(xps.complex_dtypes(), SearchStrategy)\n"
  },
  {
    "path": "hypothesis-python/tests/attrs/test_attrs.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport warnings\n\nimport attr\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import SmallSearchSpaceWarning\nfrom hypothesis.strategies._internal.utils import to_jsonable\n\nfrom tests.common.debug import check_can_generate_examples\n\n\ndef a_converter(x) -> int:\n    return int(x)\n\n\n@attr.s\nclass Inferrables:\n    annot_converter = attr.ib(converter=a_converter)\n\n\n@given(st.builds(Inferrables))\ndef test_attrs_inference_builds(c):\n    pass\n\n\ndef test_attrs_inference_from_type():\n    s = st.from_type(Inferrables)\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", SmallSearchSpaceWarning)\n        check_can_generate_examples(s)\n\n\n@attr.s\nclass AttrsClass:\n    n = attr.ib()\n\n\ndef test_jsonable_attrs():\n    obj = AttrsClass(n=10)\n    assert to_jsonable(obj, avoid_realization=False) == {\"n\": 10}\n\n\ndef test_hypothesis_is_not_the_first_to_import_attrs(testdir):\n    # We only import attrs if the user did so first.\n\n    test_path = testdir.makepyfile(\n        \"\"\"\n        import os\n        # don't load hypothesis plugins, which might transitively import attrs\n        os.environ[\"HYPOTHESIS_NO_PLUGINS\"] = \"1\"\n\n        import sys\n        assert \"attrs\" not in sys.modules\n\n        from hypothesis import given, strategies as st\n        assert \"attrs\" not in sys.modules\n\n        @given(st.integers() | st.floats() | st.sampled_from([\"a\", \"b\"]))\n        def test_no_attrs_import(x):\n            assert \"attrs\" not in sys.modules\n        \"\"\"\n    )\n    # don't load pytest plugins, which might transitively import attrs\n    result = testdir.runpytest(test_path, \"--disable-plugin-autoload\")\n    result.assert_outcomes(passed=1, failed=0)\n"
  },
  {
    "path": "hypothesis-python/tests/attrs/test_inference.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport typing\n\nimport attr\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import ResolutionFailed\n\nfrom tests.common.debug import check_can_generate_examples\n\n# Union[A, B] is not equivalent to A | B until 3.14. We'll continue to test both\n# until then.\n# ruff: noqa: UP045, UP007\n\n\n@attr.s\nclass Inferrables:\n    type_ = attr.ib(type=int)\n    type_converter = attr.ib(converter=bool)\n    validator_type = attr.ib(validator=attr.validators.instance_of(str))\n    validator_type_tuple = attr.ib(validator=attr.validators.instance_of((str, int)))\n    validator_type_multiple = attr.ib(\n        validator=[\n            attr.validators.instance_of(str),\n            attr.validators.instance_of((str, int, bool)),\n        ]\n    )\n    validator_type_has_overlap = attr.ib(\n        validator=[\n            attr.validators.instance_of(str),\n            attr.validators.instance_of((str, list)),\n            attr.validators.instance_of(object),\n        ]\n    )\n    validator_optional = attr.ib(\n        validator=attr.validators.optional(lambda inst, atrib, val: float(val))\n    )\n    validator_in = attr.ib(validator=attr.validators.in_([1, 2, 3]))\n    validator_in_multiple = attr.ib(\n        validator=[attr.validators.in_(list(range(100))), attr.validators.in_([1, -1])]\n    )\n    validator_in_multiple_strings = attr.ib(\n        validator=[attr.validators.in_(\"abcd\"), attr.validators.in_([\"ab\", \"cd\"])]\n    )\n\n    typing_list = attr.ib(type=list[int])\n    typing_list_of_list = attr.ib(type=list[list[int]])\n    typing_dict = attr.ib(type=dict[str, int])\n    typing_optional = attr.ib(type=typing.Optional[bool])\n    typing_optional_new = attr.ib(type=bool | None)\n    typing_union = attr.ib(type=typing.Union[str, int])\n    typing_union_new = attr.ib(type=str | int)\n\n    has_default = attr.ib(default=0)\n    has_default_factory = attr.ib(default=attr.Factory(list))\n    has_default_factory_takes_self = attr.ib(  # uninferrable but has default\n        default=attr.Factory(lambda _: [], takes_self=True)\n    )\n\n\n@attr.s\nclass Required:\n    a = attr.ib()\n\n\n@attr.s\nclass UnhelpfulConverter:\n    a = attr.ib(converter=lambda x: x)\n\n\n@given(st.builds(Inferrables, has_default=..., has_default_factory=...))\ndef test_attrs_inference_builds(c):\n    pass\n\n\n@given(st.from_type(Inferrables))\ndef test_attrs_inference_from_type(c):\n    pass\n\n\n@pytest.mark.parametrize(\"c\", [Required, UnhelpfulConverter])\ndef test_cannot_infer(c):\n    with pytest.raises(ResolutionFailed):\n        check_can_generate_examples(st.builds(c))\n\n\ndef test_cannot_infer_takes_self():\n    with pytest.raises(ResolutionFailed):\n        check_can_generate_examples(\n            st.builds(Inferrables, has_default_factory_takes_self=...)\n        )\n\n\n@attr.s\nclass HasPrivateAttribute:\n    _x: int = attr.ib()\n\n\n@pytest.mark.parametrize(\"s\", [st.just(42)])\ndef test_private_attribute(s):\n    check_can_generate_examples(st.builds(HasPrivateAttribute, x=s))\n\n\ndef test_private_attribute_underscore_fails():\n    with pytest.raises(TypeError, match=\"unexpected keyword argument '_x'\"):\n        check_can_generate_examples(st.builds(HasPrivateAttribute, _x=st.just(42)))\n\n\ndef test_private_attribute_underscore_infer_fails():\n    # this has a slightly different failure case, because it goes through\n    # attrs-specific resolution logic.\n    with pytest.raises(\n        TypeError, match=\"Unexpected keyword argument _x for attrs class\"\n    ):\n        check_can_generate_examples(st.builds(HasPrivateAttribute, _x=...))\n\n\n@attr.s\nclass HasAliasedAttribute:\n    x: int = attr.ib(alias=\"crazyname\")\n\n\n@pytest.mark.parametrize(\"s\", [st.just(42)])\ndef test_aliased_attribute(s):\n    check_can_generate_examples(st.builds(HasAliasedAttribute, crazyname=s))\n"
  },
  {
    "path": "hypothesis-python/tests/attrs/test_pretty.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport attrs\n\nfrom hypothesis.vendor import pretty\n\n\nclass ReprDetector:\n    def _repr_pretty_(self, p, cycle):\n        \"\"\"Exercise the IPython callback interface.\"\"\"\n        p.text(\"GOOD\")\n\n    def __repr__(self):\n        return \"BAD\"\n\n\n@attrs.define\nclass SomeAttrsClass:\n    x: ReprDetector\n\n\ndef test_pretty_prints_attrs_classes():\n    assert pretty.pretty(SomeAttrsClass(ReprDetector())) == \"SomeAttrsClass(x=GOOD)\"\n\n\n@attrs.define\nclass SomeAttrsClassWithCustomPretty:\n    def _repr_pretty_(self, p, cycle):\n        \"\"\"Exercise the IPython callback interface.\"\"\"\n        p.text(\"I am a banana\")\n\n\ndef test_custom_pretty_print_method_overrides_field_printing():\n    assert pretty.pretty(SomeAttrsClassWithCustomPretty()) == \"I am a banana\"\n\n\n@attrs.define\nclass SomeAttrsClassWithLotsOfFields:\n    a: int\n    b: int\n    c: int\n    d: int\n    e: int\n    f: int\n    g: int\n    h: int\n    i: int\n    j: int\n    k: int\n    l: int\n    m: int\n    n: int\n    o: int\n    p: int\n    q: int\n    r: int\n    s: int\n\n\ndef test_will_line_break_between_fields():\n    obj = SomeAttrsClassWithLotsOfFields(\n        **{\n            at.name: 12345678900000000000000001\n            for at in SomeAttrsClassWithLotsOfFields.__attrs_attrs__\n        }\n    )\n    assert \"\\n\" in pretty.pretty(obj)\n\n\n@attrs.define\nclass SomeDataClassWithNoFields: ...\n\n\ndef test_prints_empty_dataclass_correctly():\n    assert pretty.pretty(SomeDataClassWithNoFields()) == \"SomeDataClassWithNoFields()\"\n\n\n@attrs.define\nclass AttrsClassWithNoInitField:\n    x: int\n    y: int = attrs.field(init=False)\n\n\ndef test_does_not_include_no_init_fields_in_attrs_printing():\n    record = AttrsClassWithNoInitField(x=1)\n    assert pretty.pretty(record) == \"AttrsClassWithNoInitField(x=1)\"\n    record.y = 1\n    assert pretty.pretty(record) == \"AttrsClassWithNoInitField(x=1)\"\n\n\nclass Namespace:\n    @attrs.define\n    class A:\n        x: int\n\n\ndef test_includes_namespace_classes_in_pretty():\n    obj = Namespace.A(x=1)\n    assert pretty.pretty(obj) == \"Namespace.A(x=1)\"\n"
  },
  {
    "path": "hypothesis-python/tests/codemods/test_codemod_cli.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport subprocess\n\nBEFORE = \"\"\"\nfrom hypothesis.strategies import complex_numbers, complex_numbers as cn\n\ncomplex_numbers(min_magnitude=None)  # simple call to fix\ncomplex_numbers(min_magnitude=None, max_magnitude=1)  # plus arg after\ncomplex_numbers(allow_infinity=False, min_magnitude=None)  # plus arg before\ncn(min_magnitude=None)  # imported as alias\n\"\"\"\nAFTER = BEFORE.replace(\"None\", \"0\")\n_unchanged = \"\"\"\ncomplex_numbers(min_magnitude=1)  # value OK\n\nclass Foo:\n    def complex_numbers(self, **kw): pass\n\n    complex_numbers(min_magnitude=None)  # defined in a different scope\n\"\"\"\nBEFORE += _unchanged\nAFTER += _unchanged\ndel _unchanged\n\n\ndef run(command, *, cwd=None, input=None):\n    return subprocess.run(\n        command,\n        input=input,\n        capture_output=True,\n        shell=True,\n        text=True,\n        cwd=cwd,\n        encoding=\"utf-8\",\n    )\n\n\ndef test_codemod_single_file(tmp_path):\n    fname = tmp_path / \"mycode.py\"\n    fname.write_text(BEFORE, encoding=\"utf-8\")\n    result = run(\"hypothesis codemod mycode.py\", cwd=tmp_path)\n    assert result.returncode == 0\n    assert fname.read_text(encoding=\"utf-8\") == AFTER\n\n\ndef test_codemod_multiple_files(tmp_path):\n    # LibCST had some trouble with multiprocessing on Windows\n    files = [tmp_path / \"mycode1.py\", tmp_path / \"mycode2.py\"]\n    for f in files:\n        f.write_text(BEFORE, encoding=\"utf-8\")\n    result = run(\"hypothesis codemod mycode1.py mycode2.py\", cwd=tmp_path)\n    assert result.returncode == 0\n    for f in files:\n        assert f.read_text(encoding=\"utf-8\") == AFTER\n\n\ndef test_codemod_from_stdin():\n    result = run(\"hypothesis codemod -\", input=BEFORE)\n    assert result.returncode == 0\n    assert result.stdout.rstrip() == AFTER.rstrip()\n"
  },
  {
    "path": "hypothesis-python/tests/codemods/test_codemods.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom libcst.codemod import CodemodTest\n\nfrom hypothesis.extra import codemods\n\n\ndef test_refactor_function_is_idempotent():\n    before = (\n        \"from hypothesis.strategies import complex_numbers\\n\\n\"\n        \"complex_numbers(None)\\n\"\n    )\n    after = codemods.refactor(before)\n    assert before.replace(\"None\", \"min_magnitude=0\") == after\n    assert codemods.refactor(after) == after\n\n\nclass TestFixComplexMinMagnitude(CodemodTest):\n    TRANSFORM = codemods.HypothesisFixComplexMinMagnitude\n\n    def test_noop(self) -> None:\n        before = \"\"\"\n            from hypothesis.strategies import complex_numbers, complex_numbers as cn\n\n            complex_numbers(min_magnitude=1)  # value OK\n            complex_numbers(max_magnitude=None)  # different argument\n\n            class Foo:\n                def complex_numbers(self, **kw): pass\n\n                complex_numbers(min_magnitude=None)  # defined in a different scope\n        \"\"\"\n        self.assertCodemod(before=before, after=before)\n\n    def test_substitution(self) -> None:\n        before = \"\"\"\n            from hypothesis.strategies import complex_numbers, complex_numbers as cn\n\n            complex_numbers(min_magnitude=None)  # simple call to fix\n            complex_numbers(min_magnitude=None, max_magnitude=1)  # plus arg after\n            complex_numbers(allow_infinity=False, min_magnitude=None)  # plus arg before\n            cn(min_magnitude=None)  # imported as alias\n        \"\"\"\n        self.assertCodemod(before=before, after=before.replace(\"None\", \"0\"))\n\n\nclass TestFixPositionalKeywonlyArgs(CodemodTest):\n    TRANSFORM = codemods.HypothesisFixPositionalKeywonlyArgs\n\n    def test_substitution(self) -> None:\n        before = \"\"\"\n            import hypothesis.strategies as st\n\n            st.floats(0, 1, False, False, 32)\n            st.fractions(0, 1, 9)\n        \"\"\"\n        after = \"\"\"\n            import hypothesis.strategies as st\n\n            st.floats(0, 1, allow_nan=False, allow_infinity=False, width=32)\n            st.fractions(0, 1, max_denominator=9)\n        \"\"\"\n        self.assertCodemod(before=before, after=after)\n\n    def test_noop_with_new_floats_kw(self) -> None:\n        before = \"\"\"\n            import hypothesis.strategies as st\n\n            st.floats(0, 1, False, False, True, 32, False, False)  # allow_subnormal=True\n        \"\"\"\n        self.assertCodemod(before=before, after=before)\n\n    def test_noop_if_unsure(self) -> None:\n        before = \"\"\"\n            import random\n\n            if random.getrandbits(1):\n                from hypothesis import target\n                from hypothesis.strategies import lists as sets\n\n                def fractions(*args):\n                    pass\n\n            else:\n                from hypothesis import target\n                from hypothesis.strategies import fractions, sets\n\n            fractions(0, 1, 9)\n            sets(None, 1)\n            target(0, 'label')\n        \"\"\"\n        after = before.replace(\"'label'\", \"label='label'\")\n        self.assertCodemod(before=before, after=after)\n\n    def test_stateful_rule_noop(self):\n        # `rule()(lambda self: None)` is a call with a positional argument, and\n        # so we need an additional check that the \"func\" node is a Name rather than\n        # itself being a Call, lest we rewrite the outer instead of the inner.\n        # (this may be an upstream bug in metadata processing)\n        before = \"\"\"\n            from hypothesis.stateful import RuleBasedStateMachine, rule\n\n            class MultipleRulesSameFuncMachine(RuleBasedStateMachine):\n                rule1 = rule()(lambda self: None)\n        \"\"\"\n        self.assertCodemod(before=before, after=before)\n\n    def test_kwargs_noop(self):\n        before = \"\"\"\n            from hypothesis import target\n\n            kwargs = {\"observation\": 1, \"label\": \"foobar\"}\n            target(**kwargs)\n        \"\"\"\n        self.assertCodemod(before=before, after=before)\n\n    def test_noop_with_too_many_arguments_passed(self) -> None:\n        # If there are too many arguments, we should leave this alone to raise\n        # TypeError on older versions instead of deleting the additional args.\n        before = \"\"\"\n            import hypothesis.strategies as st\n\n            st.sets(st.integers(), 0, 1, True)\n        \"\"\"\n        self.assertCodemod(before=before, after=before)\n\n\nclass TestHealthCheckAll(CodemodTest):\n    TRANSFORM = codemods.HypothesisFixHealthCheckAll\n\n    def test_noop_other_attributes(self):\n        # Test that calls to other attributes of HealthCheck are not modified\n        before = \"result = HealthCheck.data_too_large\"\n        self.assertCodemod(before=before, after=before)\n\n    def test_substitution(self) -> None:\n        # Test that HealthCheck.all() is replaced with list(HealthCheck)\n        before = \"result = HealthCheck.all()\"\n        after = \"result = list(HealthCheck)\"\n        # self.assertEqual(run_codemod(input_code), expected_code)\n        self.assertCodemod(before=before, after=after)\n\n\nclass TestFixCharactersArguments(CodemodTest):\n    TRANSFORM = codemods.HypothesisFixCharactersArguments\n\n    def test_substitution(self) -> None:\n        for in_, out in codemods.HypothesisFixCharactersArguments._replacements.items():\n            before = f\"\"\"\n                import hypothesis.strategies as st\n                st.characters({in_}=...)\n            \"\"\"\n            self.assertCodemod(before=before, after=before.replace(in_, out))\n\n    def test_remove_redundant_exclude_categories(self) -> None:\n        args = \"blacklist_categories=OUT, whitelist_categories=IN\"\n        before = f\"\"\"\n                import hypothesis.strategies as st\n                st.characters({args})\n            \"\"\"\n        self.assertCodemod(before=before, after=before.replace(args, \"categories=IN\"))\n"
  },
  {
    "path": "hypothesis-python/tests/common/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport sys\nfrom collections import namedtuple\n\nfrom hypothesis.strategies import (\n    binary,\n    booleans,\n    builds,\n    complex_numbers,\n    decimals,\n    dictionaries,\n    fixed_dictionaries,\n    floats,\n    fractions,\n    frozensets,\n    integers,\n    just,\n    lists,\n    none,\n    one_of,\n    randoms,\n    recursive,\n    sampled_from,\n    sets,\n    text,\n    tuples,\n)\n\nfrom tests.common.debug import TIME_INCREMENT\n\n__all__ = [\"TIME_INCREMENT\", \"standard_types\"]\n\nOrderedPair = namedtuple(\"OrderedPair\", (\"left\", \"right\"))\nABC = namedtuple(\"ABC\", (\"a\", \"b\", \"c\"))\n\n\ndef abc(x, y, z):\n    return builds(ABC, x, y, z)\n\n\nstandard_types = [\n    lists(none(), max_size=0),\n    tuples(),\n    sets(none(), max_size=0),\n    frozensets(none(), max_size=0),\n    fixed_dictionaries({}),\n    abc(booleans(), booleans(), booleans()),\n    abc(booleans(), booleans(), integers()),\n    fixed_dictionaries({\"a\": integers(), \"b\": booleans()}),\n    dictionaries(booleans(), integers()),\n    dictionaries(text(), booleans()),\n    one_of(integers(), tuples(booleans())),\n    sampled_from(range(10)),\n    one_of(just(\"a\"), just(\"b\"), just(\"c\")),\n    sampled_from((\"a\", \"b\", \"c\")),\n    integers(),\n    integers(min_value=3),\n    integers(min_value=(-(2**32)), max_value=(2**64)),\n    floats(),\n    floats(min_value=-2.0, max_value=3.0),\n    floats(),\n    floats(min_value=-2.0),\n    floats(),\n    floats(max_value=-0.0),\n    floats(),\n    floats(min_value=0.0),\n    floats(min_value=3.14, max_value=3.14),\n    text(),\n    binary(),\n    booleans(),\n    tuples(booleans(), booleans()),\n    frozensets(integers()),\n    sets(frozensets(booleans())),\n    complex_numbers(),\n    fractions(),\n    decimals(),\n    lists(lists(booleans())),\n    lists(floats(0.0, 0.0)),\n    integers().flatmap(\n        lambda right: integers(min_value=0).map(\n            lambda length: OrderedPair(right - length, right)\n        )\n    ),\n    integers().flatmap(lambda v: lists(just(v))),\n    integers().filter(lambda x: abs(x) > 100),\n    floats(min_value=-sys.float_info.max, max_value=sys.float_info.max),\n    none(),\n    randoms(use_true_random=True),\n    booleans().flatmap(lambda x: booleans() if x else complex_numbers()),\n    recursive(base=booleans(), extend=lambda x: lists(x, max_size=3), max_leaves=10),\n]\n"
  },
  {
    "path": "hypothesis-python/tests/common/arguments.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given, settings\nfrom hypothesis.errors import InvalidArgument\n\n\ndef e(a, *args, **kwargs):\n    return (a, args, kwargs)\n\n\ndef e_to_str(elt):\n    f, args, kwargs = getattr(elt, \"values\", elt)\n    bits = list(map(repr, args))\n    bits.extend(sorted(f\"{k}={v!r}\" for k, v in kwargs.items()))\n    return \"{}({})\".format(f.__name__, \", \".join(bits))\n\n\ndef argument_validation_test(bad_args):\n    @pytest.mark.parametrize(\n        (\"function\", \"args\", \"kwargs\"), bad_args, ids=list(map(e_to_str, bad_args))\n    )\n    def test_raise_invalid_argument(function, args, kwargs):\n        # some invalid argument tests may find multiple distinct invalid inputs,\n        # which hypothesis raises as an exception group (and is not caught by\n        # pytest.raises).\n        @given(function(*args, **kwargs))\n        @settings(report_multiple_bugs=False)\n        def test(x):\n            pass\n\n        with pytest.raises(InvalidArgument):\n            test()\n\n    return test_raise_invalid_argument\n"
  },
  {
    "path": "hypothesis-python/tests/common/costbounds.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.internal.conjecture.shrinking.common import find_integer\n\nFIND_INTEGER_COSTS = {}\n\n\ndef find_integer_cost(n):\n    try:\n        return FIND_INTEGER_COSTS[n]\n    except KeyError:\n        pass\n\n    cost = 0\n\n    def test(i):\n        nonlocal cost\n        cost += 1\n        return i <= n\n\n    find_integer(test)\n\n    return FIND_INTEGER_COSTS.setdefault(n, cost)\n"
  },
  {
    "path": "hypothesis-python/tests/common/debug.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom typing import TypeVar\nfrom unittest import SkipTest\n\nfrom hypothesis import HealthCheck, Phase, Verbosity, given, settings as Settings\nfrom hypothesis._settings import local_settings\nfrom hypothesis.control import _current_build_context\nfrom hypothesis.errors import NoSuchExample, Unsatisfiable\nfrom hypothesis.internal.reflection import get_pretty_function_description\nfrom hypothesis.strategies import SearchStrategy\n\nfrom tests.common.utils import no_shrink\n\nTIME_INCREMENT = 0.00001\nT = TypeVar(\"T\")\n\n\n# don't use hypothesis.errors.Found, which inherits from HypothesisException\n# and therefore has weird semantics around e.g. backend=\"crosshair\".\nclass Found(Exception):\n    pass\n\n\ndef minimal(\n    definition: SearchStrategy[T],\n    condition=lambda x: True,\n    settings: Settings | None = None,\n) -> T:\n    from tests.conftest import in_shrinking_benchmark\n\n    definition.validate()\n    result = None\n\n    def wrapped_condition(x):\n        # This sure seems pointless, but `test_sum_of_pair` fails otherwise...\n        return condition(x)\n\n    if (\n        context := _current_build_context.value\n    ) and context.data.provider.avoid_realization:\n        raise SkipTest(\"`minimal()` helper not supported under symbolic execution\")\n\n    if settings is None:\n        settings = Settings(max_examples=500, phases=(Phase.generate, Phase.shrink))\n\n    verbosity = settings.verbosity\n    if verbosity == Verbosity.normal:\n        verbosity = Verbosity.quiet\n\n    @given(definition)\n    @Settings(\n        parent=settings,\n        suppress_health_check=list(HealthCheck),\n        report_multiple_bugs=False,\n        # we derandomize in general to avoid flaky tests, but we do want to\n        # measure this variation while benchmarking.\n        derandomize=not in_shrinking_benchmark,\n        database=None,\n        verbosity=verbosity,\n    )\n    def inner(x):\n        if wrapped_condition(x):\n            nonlocal result\n            result = x\n            raise Found\n\n    try:\n        inner()\n    except Found:\n        return result\n    raise Unsatisfiable(\n        f\"Could not find any examples from {definition!r} that satisfied \"\n        f\"{get_pretty_function_description(condition)}\"\n    )\n\n\ndef find_any(definition, condition=lambda _: True, settings=None):\n    # If nested within an existing @given\n    if context := _current_build_context.value:\n        while True:\n            if condition(s := context.data.draw(definition)):\n                return s\n\n    # If top-level\n    settings = settings or Settings.default\n    return minimal(\n        definition,\n        condition,\n        settings=Settings(\n            settings, phases=no_shrink, max_examples=max(1000, settings.max_examples)\n        ),\n    )\n\n\ndef assert_no_examples(strategy, condition=lambda _: True):\n    try:\n        assert_all_examples(strategy, lambda val: not condition(val))\n    except (Unsatisfiable, NoSuchExample):\n        pass\n\n\ndef assert_all_examples(strategy, predicate, settings=None):\n    \"\"\"Asserts that all examples of the given strategy match the predicate.\n\n    :param strategy: Hypothesis strategy to check\n    :param predicate: (callable) Predicate that takes example and returns bool\n    \"\"\"\n    if context := _current_build_context.value:\n        with local_settings(Settings(parent=settings)):\n            for _ in range(20):\n                s = context.data.draw(strategy)\n                msg = f\"Found {s!r} using strategy {strategy} which does not match\"\n                assert predicate(s), msg\n\n    else:\n\n        @given(strategy)\n        @Settings(parent=settings, database=None)\n        def assert_examples(s):\n            msg = f\"Found {s!r} using strategy {strategy} which does not match\"\n            assert predicate(s), msg\n\n        assert_examples()\n\n\ndef assert_simple_property(strategy, predicate, settings=None):\n    \"\"\"Like assert_all_examples, intended as a self-documenting shortcut for simple constant\n    properties (`is`, `isinstance`, `==`, ...) that can be adequately verified in just a few\n    examples.\n\n    For more thorough checking, use assert_all_examples.\n    \"\"\"\n\n    assert_all_examples(\n        strategy,\n        predicate,\n        Settings(\n            parent=settings,\n            max_examples=15,\n            suppress_health_check=list(HealthCheck),\n        ),\n    )\n\n\ndef check_can_generate_examples(strategy, settings=None):\n    \"\"\"Tries to generate a small number of examples from the strategy, to verify that it can\n    do so without raising.\n\n    Nothing is returned, it only checks that no error is raised.\n    \"\"\"\n\n    assert_simple_property(\n        strategy,\n        lambda _: True,\n        settings=Settings(\n            parent=settings,\n            phases=(Phase.generate,),\n        ),\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/common/setup.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nfrom warnings import filterwarnings\n\nfrom hypothesis import (\n    HealthCheck,\n    Phase,\n    Verbosity,\n    _settings as settings_module,\n    settings,\n)\nfrom hypothesis._settings import CI, default as default_settings, is_in_ci, not_set\nfrom hypothesis.internal.conjecture.providers import AVAILABLE_PROVIDERS\nfrom hypothesis.internal.coverage import IN_COVERAGE_TESTS\n\n\ndef run():\n    filterwarnings(\"error\")\n    filterwarnings(\"ignore\", category=ImportWarning)\n    filterwarnings(\"ignore\", category=FutureWarning, module=\"pandas._version\")\n\n    # See https://github.com/numpy/numpy/pull/432; still a thing as of 2022.\n    filterwarnings(\"ignore\", message=\"numpy.dtype size changed\")\n    filterwarnings(\"ignore\", message=\"numpy.ufunc size changed\")\n\n    # See https://github.com/HypothesisWorks/hypothesis/issues/1674\n    filterwarnings(\n        \"ignore\",\n        message=(\n            \"The virtualenv distutils package at .+ appears to be in the \"\n            \"same location as the system distutils?\"\n        ),\n        category=UserWarning,\n    )\n\n    # We do a smoke test here before we mess around with settings.\n    for setting_name in settings_module.all_settings:\n        # database value is dynamically calculated\n        if setting_name == \"database\":\n            continue\n\n        value = getattr(settings(), setting_name)\n        default_value = getattr(default_settings, setting_name)\n        assert value == default_value or (\n            is_in_ci() and value == getattr(CI, setting_name)\n        ), f\"({value!r} == x.{setting_name}) != (s.{setting_name} == {default_value!r})\"\n\n    settings.register_profile(\n        \"default\",\n        settings(\n            default_settings,\n            max_examples=20 if IN_COVERAGE_TESTS else not_set,\n            phases=list(Phase),  # Dogfooding the explain phase\n        ),\n    )\n    settings.register_profile(\"speedy\", max_examples=5)\n    settings.register_profile(\"debug\", verbosity=Verbosity.debug)\n    settings.register_profile(\n        \"threading\",\n        # we would normally not disable the deadline here, but we disable the\n        # _consistently_increment_time fixture under threading tests (since\n        # monkeypatching is not thread safe), which leads to real deadline errors\n        # that are normally masked by that fixture.\n        deadline=None,\n    )\n\n    if \"crosshair\" in AVAILABLE_PROVIDERS:\n        settings.register_profile(\n            \"crosshair\",\n            # inherit from default profile, even on CI. See\n            # https://github.com/HypothesisWorks/hypothesis/pull/4536#issuecomment-3366741772\n            settings.get_profile(\"default\"),\n            backend=\"crosshair\",\n            max_examples=20,\n            deadline=None,\n            suppress_health_check=(HealthCheck.too_slow, HealthCheck.filter_too_much),\n            report_multiple_bugs=False,\n        )\n\n    for backend in set(AVAILABLE_PROVIDERS) - {\"hypothesis\", \"crosshair\"}:\n        settings.register_profile(backend, backend=backend)\n\n    settings.load_profile(os.getenv(\"HYPOTHESIS_PROFILE\", \"default\"))\n"
  },
  {
    "path": "hypothesis-python/tests/common/strategies.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport time\n\nfrom hypothesis.strategies._internal import SearchStrategy\n\n\nclass _Slow(SearchStrategy):\n    def do_draw(self, data):\n        time.sleep(1.01)\n        data.draw_bytes(2, 2)\n\n\nSLOW = _Slow()\n\n\nclass HardToShrink(SearchStrategy):\n    def __init__(self):\n        super().__init__()\n        self.__last = None\n        self.accepted = set()\n\n    def do_draw(self, data):\n        x = bytes(data.draw_integer(0, 255) for _ in range(100))\n        if x in self.accepted:\n            return True\n        ls = self.__last\n        if ls is None:\n            if all(x):\n                self.__last = x\n                self.accepted.add(x)\n                return True\n            else:\n                return False\n        diffs = [i for i in range(len(x)) if x[i] != ls[i]]\n        if len(diffs) == 1:\n            i = diffs[0]\n            if x[i] + 1 == ls[i]:\n                self.__last = x\n                self.accepted.add(x)\n                return True\n        return False\n"
  },
  {
    "path": "hypothesis-python/tests/common/utils.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport contextlib\nimport enum\nimport math\nimport sys\nimport time\nimport warnings\nfrom io import StringIO\nfrom threading import Barrier, Lock, RLock, Thread\n\nimport pytest\nfrom pytest import mark\n\nfrom hypothesis import Phase, settings\nfrom hypothesis.errors import HypothesisDeprecationWarning\nfrom hypothesis.internal import observability\nfrom hypothesis.internal.floats import next_down\nfrom hypothesis.internal.observability import (\n    Observation,\n    add_observability_callback,\n    remove_observability_callback,\n)\nfrom hypothesis.internal.reflection import get_pretty_function_description, proxies\nfrom hypothesis.reporting import default, with_reporter\nfrom hypothesis.strategies._internal.core import from_type, register_type_strategy\nfrom hypothesis.strategies._internal.types import _global_type_lookup\n\n# we need real time here, not monkeypatched for CI\ntime_sleep = time.sleep\n\nskipif_emscripten = mark.skipif(\n    sys.platform == \"emscripten\",\n    reason=\"threads, processes, etc. are not available in the browser\",\n)\n\nno_shrink = tuple(set(settings.default.phases) - {Phase.shrink, Phase.explain})\n\n\ndef flaky(max_runs, min_passes):\n    assert isinstance(max_runs, int)\n    assert isinstance(min_passes, int)\n    assert 0 < min_passes <= max_runs <= 50  # arbitrary cap\n\n    def accept(func):\n        @proxies(func)\n        def inner(*args, **kwargs):\n            runs = passes = 0\n            while passes < min_passes:\n                runs += 1\n                try:\n                    func(*args, **kwargs)\n                    passes += 1\n                except BaseException:\n                    if runs >= max_runs:\n                        raise\n\n        return inner\n\n    return accept\n\n\ncapture_out_lock = Lock()\n\n\n@contextlib.contextmanager\ndef capture_out():\n    # replacing the singleton sys.stdout can't be made thread safe. Disallow\n    # concurrency by wrapping a lock around the entire block\n    with capture_out_lock:\n        old_out = sys.stdout\n        try:\n            new_out = StringIO()\n            sys.stdout = new_out\n            with with_reporter(default):\n                yield new_out\n        finally:\n            sys.stdout = old_out\n\n\nclass ExcInfo:\n    pass\n\n\ndef fails_with(e, *, match=None):\n    def accepts(f):\n        @proxies(f)\n        def inverted_test(*arguments, **kwargs):\n            with pytest.raises(e, match=match):\n                f(*arguments, **kwargs)\n\n        return inverted_test\n\n    return accepts\n\n\nfails = fails_with(AssertionError)\n\n\nclass NotDeprecated(Exception):\n    pass\n\n\n@contextlib.contextmanager\ndef validate_deprecation():\n\n    if settings.get_current_profile_name() == \"threading\":\n        import pytest\n\n        if sys.version_info[:2] < (3, 14):\n            pytest.skip(\"warnings module is not thread-safe before 3.14\")\n\n    import warnings\n\n    try:\n        warnings.simplefilter(\"always\", HypothesisDeprecationWarning)\n        with warnings.catch_warnings(record=True) as w:\n            yield\n    finally:\n        warnings.simplefilter(\"error\", HypothesisDeprecationWarning)\n        if not any(e.category == HypothesisDeprecationWarning for e in w):\n            raise NotDeprecated(\n                f\"Expected a deprecation warning but got {[e.category for e in w]!r}\"\n            )\n\n\ndef checks_deprecated_behaviour(func):\n    \"\"\"A decorator for testing deprecated behaviour.\"\"\"\n\n    @proxies(func)\n    def _inner(*args, **kwargs):\n        with validate_deprecation():\n            return func(*args, **kwargs)\n\n    return _inner\n\n\ndef all_values(db):\n    return {v for vs in db.data.values() for v in vs}\n\n\ndef non_covering_examples(database):\n    return {\n        v for k, vs in database.data.items() if not k.endswith(b\".pareto\") for v in vs\n    }\n\n\ndef counts_calls(func):\n    \"\"\"A decorator that counts how many times a function was called, and\n    stores that value in a ``.calls`` attribute.\n    \"\"\"\n    assert not hasattr(func, \"calls\")\n\n    @proxies(func)\n    def _inner(*args, **kwargs):\n        _inner.calls += 1\n        return func(*args, **kwargs)\n\n    _inner.calls = 0\n    return _inner\n\n\ndef assert_output_contains_failure(output, test, **kwargs):\n    assert test.__name__ + \"(\" in output\n    for k, v in kwargs.items():\n        assert f\"{k}={v!r}\" in output, (f\"{k}={v!r}\", output)\n\n\ndef assert_falsifying_output(\n    test, example_type=\"Falsifying\", expected_exception=AssertionError, **kwargs\n):\n    with capture_out() as out:\n        if expected_exception is None:\n            # Some tests want to check the output of non-failing runs.\n            test()\n            msg = \"\"\n        else:\n            with pytest.raises(expected_exception) as exc_info:\n                test()\n            notes = \"\\n\".join(getattr(exc_info.value, \"__notes__\", []))\n            msg = str(exc_info.value) + \"\\n\" + notes\n\n    output = out.getvalue() + msg\n    assert f\"{example_type} example:\" in output\n    assert_output_contains_failure(output, test, **kwargs)\n\n\ntemp_registered_lock = RLock()\n\n\n@contextlib.contextmanager\ndef temp_registered(type_, strat_or_factory):\n    \"\"\"Register and un-register a type for st.from_type().\n\n    This is not too hard, but there's a subtlety in restoring the\n    previously-registered strategy which we got wrong in a few places.\n    \"\"\"\n    with temp_registered_lock:\n        prev = _global_type_lookup.get(type_)\n        register_type_strategy(type_, strat_or_factory)\n        try:\n            yield\n        finally:\n            del _global_type_lookup[type_]\n            from_type.__clear_cache()\n            if prev is not None:\n                register_type_strategy(type_, prev)\n\n\n@contextlib.contextmanager\ndef raises_warning(expected_warning, match=None):\n    \"\"\"Use instead of pytest.warns to check that the raised warning is handled properly\"\"\"\n    with pytest.raises(expected_warning, match=match) as r, warnings.catch_warnings():\n        warnings.simplefilter(\"error\", category=expected_warning)\n        yield r\n\n\n@contextlib.contextmanager\ndef capture_observations(*, choices=None):\n    ls: list[Observation] = []\n    add_observability_callback(ls.append)\n    if choices is not None:\n        old_choices = observability.OBSERVABILITY_CHOICES\n        observability.OBSERVABILITY_CHOICES = choices\n\n    try:\n        yield ls\n    finally:\n        remove_observability_callback(ls.append)\n        if choices is not None:\n            observability.OBSERVABILITY_CHOICES = old_choices\n\n\n# Specifies whether we can represent subnormal floating point numbers.\n# IEE-754 requires subnormal support, but it's often disabled anyway by unsafe\n# compiler options like `-ffast-math`.  On most hardware that's even a global\n# config option, so *linking against* something built this way can break us.\n# Everything is terrible\nPYTHON_FTZ = next_down(sys.float_info.min) == 0.0\n\n\nclass Why(enum.Enum):\n    # Categorizing known failures, to ease later follow-up investigation.\n    # Some are crosshair issues, some hypothesis issues, others truly ok-to-xfail tests.\n    symbolic_outside_context = \"CrosshairInternal error (using value outside context)\"\n    nested_given = \"nested @given decorators don't work with crosshair\"\n    undiscovered = \"crosshair may not find the failing input\"\n    other = \"reasons not elsewhere categorized\"\n\n\ndef xfail_on_crosshair(why: Why, /, *, strict=True, as_marks=False):\n    # run `pytest -m xf_crosshair` to select these tests!\n    mark = pytest.mark.xfail(\n        strict=strict and why != Why.undiscovered,\n        reason=f\"Expected failure due to: {why.value}\",\n        condition=settings().backend == \"crosshair\",\n    )\n    if as_marks:  # for use with pytest.param(..., marks=xfail_on_crosshair())\n        return (pytest.mark.xf_crosshair, mark)\n    return lambda fn: pytest.mark.xf_crosshair(mark(fn))\n\n\ndef skipif_threading(f):\n    return pytest.mark.skipif(\n        settings.get_current_profile_name() == \"threading\", reason=\"not thread safe\"\n    )(f)\n\n\ndef xfail_if_gil_disabled(f):\n    try:\n        if not sys._is_gil_enabled():  # 3.13+\n            return pytest.mark.xfail(\n                reason=\"fails on free-threading build\", strict=False\n            )(f)\n    except Exception:\n        pass\n    return f\n\n\n# we don't monkeypatch _consistently_increment_time under threading\nskipif_time_unpatched = skipif_threading\n\n\n_restore_recursion_limit_lock = RLock()\n\n\n@contextlib.contextmanager\ndef restore_recursion_limit():\n    with _restore_recursion_limit_lock:\n        original_limit = sys.getrecursionlimit()\n        try:\n            yield\n        finally:\n            sys.setrecursionlimit(original_limit)\n\n\ndef run_concurrently(function, *, n: int) -> None:\n    import pytest\n\n    if settings.get_current_profile_name() == \"crosshair\":\n        pytest.skip(\"crosshair is not thread safe\")\n    if sys.platform == \"emscripten\":\n        pytest.skip(\"no threads on emscripten\")\n\n    def run():\n        barrier.wait()\n        function()\n\n    threads = [Thread(target=run) for _ in range(n)]\n    barrier = Barrier(n)\n\n    for thread in threads:\n        thread.start()\n\n    for thread in threads:\n        thread.join(timeout=10)\n\n\ndef wait_for(condition, *, timeout=1, interval=0.01):\n    for _ in range(math.ceil(timeout / interval)):\n        if condition():\n            return\n        time_sleep(interval)\n    raise Exception(\n        f\"timing out after waiting {timeout}s for condition \"\n        f\"{get_pretty_function_description(condition)}\"\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/conftest.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport gc\nimport inspect\nimport json\nimport os\nimport random\nimport sys\nimport time as time_module\nfrom functools import wraps\nfrom pathlib import Path\n\nimport pytest\nfrom _pytest.monkeypatch import MonkeyPatch\n\nfrom hypothesis import is_hypothesis_test, settings\nfrom hypothesis._settings import is_in_ci\nfrom hypothesis.errors import NonInteractiveExampleWarning\nfrom hypothesis.internal import lambda_sources\nfrom hypothesis.internal.compat import add_note\nfrom hypothesis.internal.conjecture import junkdrawer\n\nfrom tests.common import TIME_INCREMENT\nfrom tests.common.setup import run\nfrom tests.common.utils import raises_warning\n\nrun()\n\n# Skip collection of tests which require the Django test runner,\n# or that don't work on the current version of Python.\ncollect_ignore_glob = [\"django/*\"]\n# this checks up until py319\nfor minor_increment in range(10):\n    minor = 10 + minor_increment\n    if sys.version_info < (3, minor):\n        collect_ignore_glob.append(f\"cover/*py3{minor}*.py\")\n\nif sys.version_info >= (3, 11):\n    collect_ignore_glob.append(\"cover/test_asyncio.py\")  # @asyncio.coroutine removed\n\n\nin_shrinking_benchmark = False\n\n\ndef pytest_configure(config):\n    config.addinivalue_line(\"markers\", \"slow: pandas expects this marker to exist.\")\n    config.addinivalue_line(\n        \"markers\",\n        \"xp_min_version(api_version): run when greater or equal to api_version\",\n    )\n    config.addinivalue_line(\"markers\", \"xf_crosshair: selection for xfailing symbolics\")\n\n    if config.getoption(\"--hypothesis-benchmark-shrinks\"):\n        # we'd like to support xdist here, but a session-scope fixture won't\n        # be enough: https://github.com/pytest-dev/pytest-xdist/issues/271.\n        # Need a lockfile or equivalent.\n\n        assert config.getoption(\n            \"--hypothesis-benchmark-output\"\n        ), \"must specify shrinking output file\"\n\n        global in_shrinking_benchmark\n        in_shrinking_benchmark = True\n\n\ndef pytest_addoption(parser):\n    parser.addoption(\"--hypothesis-update-outputs\", action=\"store_true\")\n    parser.addoption(\"--hypothesis-benchmark-shrinks\", type=str, choices=[\"new\", \"old\"])\n    parser.addoption(\"--hypothesis-benchmark-output\", type=str)\n\n\n@pytest.fixture(scope=\"function\", params=[\"warns\", \"raises\"])\ndef warns_or_raises(request):\n    \"\"\"This runs the test twice: first to check that a warning is emitted\n    and execution continues successfully despite the warning; then to check\n    that the raised warning is handled properly.\n    \"\"\"\n    if request.param == \"raises\":\n        return raises_warning\n    else:\n        return pytest.warns\n\n\n# crosshair needs actual time for its path timeouts; load it before patching\ntry:\n    import hypothesis_crosshair_provider.crosshair_provider  # noqa: F401\nexcept ImportError:\n    pass\n\n\nif sys.version_info >= (3, 11):\n    # To detect if changes in code generation causes lambda test compilation\n    # to fail. Older versions (3.10 and earlier) have a few known false\n    # negatives which we ignore.\n    @pytest.fixture(scope=\"function\", autouse=True)\n    def _make_unknown_lambdas_fail(monkeypatch):\n\n        def fail(candidate):\n            msg = (\n                f\"Failed to find a matching source for {candidate}. \"\n                \"This could indicate changes in the Python code generator,\\n\"\n                \"or just a previously unknown case. To quickly resolve this \"\n                \"problem, use the `allow_unknown_lambdas` fixture.\"\n            )\n            raise AssertionError(msg)\n\n        monkeypatch.setattr(\n            lambda_sources, \"_check_unknown_perfectly_aligned_lambda\", fail\n        )\n\n\n@pytest.fixture(scope=\"function\")\ndef allow_unknown_lambdas(monkeypatch):\n    # Will run after make...fail since autouse are run first\n\n    def nofail(candidate):\n        pass\n\n    monkeypatch.setattr(\n        lambda_sources, \"_check_unknown_perfectly_aligned_lambda\", nofail\n    )\n\n\n# monkeypatch is not thread-safe, so pytest-run-parallel will skip all our tests\n# if we define this.\nif settings.get_current_profile_name() != \"threading\":\n\n    @pytest.fixture(scope=\"function\", autouse=True)\n    def _consistently_increment_time(monkeypatch):\n        \"\"\"Rather than rely on real system time we monkey patch time.time so that\n        it passes at a consistent rate between calls.\n\n        The reason for this is that when these tests run in CI, their performance is\n        extremely variable and the VM the tests are on might go to sleep for a bit,\n        introducing arbitrary delays. This can cause a number of tests to fail\n        flakily.\n\n        Replacing time with a fake version under our control avoids this problem.\n        \"\"\"\n        frozen = False\n\n        current_time = time_module.time()\n\n        def time():\n            nonlocal current_time\n            if not frozen:\n                current_time += TIME_INCREMENT\n            return current_time\n\n        def sleep(naptime):\n            nonlocal current_time\n            current_time += naptime\n\n        def freeze():\n            nonlocal frozen\n            frozen = True\n\n        def _patch(name, fn):\n            monkeypatch.setattr(\n                time_module, name, wraps(getattr(time_module, name))(fn)\n            )\n\n        _patch(\"time\", time)\n        _patch(\"monotonic\", time)\n        _patch(\"perf_counter\", time)\n        _patch(\"sleep\", sleep)\n        monkeypatch.setattr(time_module, \"freeze\", freeze, raising=False)\n\n        # In the patched time regime, observing it causes it to increment. To avoid reintroducing\n        # non-determinism due to GC running at arbitrary times, we patch the GC observer\n        # to NOT increment time.\n\n        monkeypatch.setattr(junkdrawer, \"_perf_counter\", time)\n\n        if hasattr(gc, \"callbacks\"):\n            # ensure timer callback is added, then bracket it by freeze/unfreeze below\n            junkdrawer.gc_cumulative_time()\n\n            _was_frozen = False\n\n            def _freezer(*_):\n                nonlocal _was_frozen, frozen\n                _was_frozen = frozen\n                frozen = True\n\n            def _unfreezer(*_):\n                nonlocal _was_frozen, frozen\n                frozen = _was_frozen\n\n            gc.callbacks.insert(0, _freezer)  # freeze before gc callback\n            gc.callbacks.append(_unfreezer)  # unfreeze after\n\n            yield\n\n            assert gc.callbacks.pop(0) == _freezer\n            assert gc.callbacks.pop() == _unfreezer\n        else:  # pragma: no cover # branch never taken in CPython\n            yield\n\n\nrandom_states_after_tests = {}\nindependent_random = random.Random()\n\n\n@pytest.hookimpl(hookwrapper=True)\ndef pytest_runtest_call(item):\n    if item.config.getoption(\"--hypothesis-benchmark-shrinks\"):\n        yield from _benchmark_shrinks(item)\n        # ideally benchmark shrinking would not be mutually exclusive with the\n        # other checks in this function, but it's cleaner to early-return here,\n        # and in practice they will error in normal tests before one runs a\n        # benchmark.\n        return\n    # This hookwrapper checks for PRNG state leaks from Hypothesis tests.\n    # See: https://github.com/HypothesisWorks/hypothesis/issues/1919\n    if (\n        not (hasattr(item, \"obj\") and is_hypothesis_test(item.obj))\n        # we disable this check on the threading job, due to races in the global\n        # state.\n        or settings.get_current_profile_name() == \"threading\"\n    ):\n        outcome = yield\n    elif \"pytest_randomly\" in sys.modules:\n        # See https://github.com/HypothesisWorks/hypothesis/issues/3041 - this\n        # branch exists to make it easier on external contributors, but should\n        # never run in our CI (because that would disable the check entirely).\n        assert not is_in_ci()\n        outcome = yield\n    else:\n        # We start by peturbing the state of the PRNG, because repeatedly\n        # leaking PRNG state resets state_after to the (previously leaked)\n        # state_before, and that just shows as \"no use of random\".\n        random.seed(independent_random.randrange(2**32))\n        before = random.getstate()\n        outcome = yield\n        after = random.getstate()\n        if before != after:\n            if after in random_states_after_tests:\n                raise Exception(\n                    f\"{item.nodeid!r} and {random_states_after_tests[after]!r} \"\n                    \"both used the `random` module, and finished with the \"\n                    \"same global `random.getstate()`; this is probably a nasty bug!\"\n                )\n            random_states_after_tests[after] = item.nodeid\n\n    # Annotate usage of .example() with a hint about alternatives\n    if isinstance(getattr(outcome, \"exception\", None), NonInteractiveExampleWarning):\n        add_note(\n            outcome.exception,\n            \"For hypothesis' own test suite, consider using one of the helper \"\n            \"methods in tests.common.debug instead.\",\n        )\n\n\ntimer = time_module.process_time\n\n\ndef _worker_path(session: pytest.Session) -> Path:\n    return (\n        Path(session.config.getoption(\"--hypothesis-benchmark-output\")).parent\n        # https://pytest-xdist.readthedocs.io/en/stable/how-to.html#envvar-PYTEST_XDIST_WORKER\n        / f\"shrinking_results_{os.environ['PYTEST_XDIST_WORKER']}.json\"\n    )\n\n\ndef _benchmark_shrinks(item: pytest.Function) -> None:\n    from hypothesis.internal.conjecture.shrinker import Shrinker\n\n    # this isn't perfect, but it is cheap!\n    if \"minimal(\" not in inspect.getsource(item.function):\n        pytest.skip(\"(probably) does not call minimal()\")\n\n    actual_shrink = Shrinker.shrink\n    shrink_calls = []\n    shrink_time = []\n\n    def shrink(self, *args, **kwargs):\n        nonlocal shrink_calls\n        nonlocal shrink_time\n        start_t = timer()\n        result = actual_shrink(self, *args, **kwargs)\n        shrink_calls.append(self.engine.call_count - self.initial_calls)\n        shrink_time.append(timer() - start_t)\n        return result\n\n    monkeypatch = MonkeyPatch()\n    monkeypatch.setattr(Shrinker, \"shrink\", shrink)\n\n    # pytest_runtest_call must yield at some point. This executes the test function\n    # n - 1 times, and then yields for the final execution.\n    for _ in range(5 - 1):\n        item.runtest()\n    yield\n\n    monkeypatch.undo()\n\n    # remove leading hypothesis-python/tests/...\n    nodeid = item.nodeid.rsplit(\"/\", 1)[1]\n\n    results_p = _worker_path(item.session)\n    if not results_p.exists():\n        results_p.write_text(json.dumps({\"calls\": {}, \"time\": {}}))\n\n    data = json.loads(results_p.read_text())\n    data[\"calls\"][nodeid] = shrink_calls\n    data[\"time\"][nodeid] = shrink_time\n    results_p.write_text(json.dumps(data))\n\n\ndef pytest_sessionfinish(session, exitstatus):\n    if not (mode := session.config.getoption(\"--hypothesis-benchmark-shrinks\")):\n        return\n    # only run on the controller process, not the workers\n    if hasattr(session.config, \"workerinput\"):\n        return\n\n    results = {\"calls\": {}, \"time\": {}}\n    output_p = Path(session.config.getoption(\"--hypothesis-benchmark-output\"))\n    for p in output_p.parent.iterdir():\n        if p.name.startswith(\"shrinking_results_\"):\n            worker_results = json.loads(p.read_text())\n            results[\"calls\"] |= worker_results[\"calls\"]\n            results[\"time\"] |= worker_results[\"time\"]\n            p.unlink()\n\n    results = {mode: results}\n    if not output_p.exists():\n        output_p.write_text(json.dumps(results))\n    else:\n        data = json.loads(output_p.read_text())\n        data[mode] = results[mode]\n        output_p.write_text(json.dumps(data))\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/common.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport dataclasses\nimport math\nimport sys\nfrom contextlib import contextmanager\nfrom random import Random\nfrom threading import RLock\n\nimport pytest\n\nfrom hypothesis import HealthCheck, Phase, settings, strategies as st\nfrom hypothesis.control import current_build_context, currently_in_test_context\nfrom hypothesis.internal.conjecture import engine as engine_module\nfrom hypothesis.internal.conjecture.choice import ChoiceNode, ChoiceT\nfrom hypothesis.internal.conjecture.data import ConjectureData, Status\nfrom hypothesis.internal.conjecture.engine import ConjectureRunner\nfrom hypothesis.internal.conjecture.provider_conformance import (\n    choice_types_constraints,\n    constraints_strategy,\n)\nfrom hypothesis.internal.conjecture.providers import COLLECTION_DEFAULT_MAX_SIZE\nfrom hypothesis.internal.conjecture.utils import calc_label_from_name\nfrom hypothesis.internal.escalation import InterestingOrigin\nfrom hypothesis.internal.floats import SMALLEST_SUBNORMAL\nfrom hypothesis.internal.intervalsets import IntervalSet\n\nSOME_LABEL = calc_label_from_name(\"some label\")\n\n\ndef interesting_origin(n: int | None = None) -> InterestingOrigin:\n    \"\"\"\n    Creates and returns an InterestingOrigin, parameterized by n, such that\n    interesting_origin(n) == interesting_origin(m) iff n = m.\n\n    Since n=None may by chance concide with an explicitly-passed value of n, I\n    recommend not mixing interesting_origin() and interesting_origin(n) in the\n    same test.\n    \"\"\"\n    try:\n        int(\"not an int\")\n    except Exception as e:\n        origin = InterestingOrigin.from_exception(e)\n        return dataclasses.replace(origin, lineno=n if n is not None else origin.lineno)\n\n\ndef run_to_data(f):\n    runner = ConjectureRunner(\n        f,\n        settings=settings(\n            max_examples=300, database=None, suppress_health_check=list(HealthCheck)\n        ),\n        random=Random(0),\n    )\n    runner.run()\n    assert runner.interesting_examples\n    (last_data,) = runner.interesting_examples.values()\n    return last_data\n\n\ndef run_to_nodes(f):\n    return run_to_data(f).nodes\n\n\n_buffer_size_lock = RLock()\n\n\n@contextmanager\ndef buffer_size_limit(n):\n    with _buffer_size_lock:\n        original = engine_module.BUFFER_SIZE\n        try:\n            engine_module.BUFFER_SIZE = n\n            yield\n        finally:\n            engine_module.BUFFER_SIZE = original\n\n\ndef shrinking_from(start):\n    def accept(f):\n        runner = ConjectureRunner(\n            f,\n            settings=settings(\n                max_examples=5000,\n                database=None,\n                suppress_health_check=list(HealthCheck),\n                # avoid running the explain phase in shrinker.shrink() in tests\n                # which don't test the inquisitor.\n                phases=set(settings.default.phases) - {Phase.explain},\n            ),\n            random=Random(0),\n        )\n        runner.cached_test_function(start)\n        assert runner.interesting_examples\n\n        (last_data,) = runner.interesting_examples.values()\n        return runner.new_shrinker(last_data, lambda d: d.status == Status.INTERESTING)\n\n    return accept\n\n\ndef fresh_data(*, random=None, observer=None) -> ConjectureData:\n    context = current_build_context() if currently_in_test_context() else None\n    if context is not None and settings().backend == \"crosshair\":\n        # we should reeaxmine fresh_data sometime and see if we can replace it\n        # with nicer and higher level hypothesis idioms.\n        #\n        # For now it doesn't work well with crosshair tests. This is no big\n        # loss, because these tests often rely on hypothesis-provider-specific\n        # things.\n        pytest.skip(\n            \"Fresh data is too low level (and too much of a hack) to be \"\n            \"worth supporting when testing with crosshair\"\n        )\n\n    if random is None:\n        if context is None:\n            # ensure usage of fresh_data() is not flaky outside of property tests.\n            raise ValueError(\n                \"must pass a seeded Random instance to fresh_data() when \"\n                \"outside of a build context\"\n            ) from None\n\n        # within property tests, ensure fresh_data uses a controlled source of\n        # randomness.\n        # drawing this from the current build context is almost *too* magical. But\n        # the alternative is an extra @given(st.randoms()) everywhere we use\n        # fresh_data, so eh.\n\n        # @example uses a zero-length data, which means we can't use a\n        # hypothesis-backed random (which would entail drawing from the data).\n        # In this case, use a deterministic Random(0).\n        random = (\n            context.data.draw(st.randoms(use_true_random=True))\n            if (choices := context.data.max_choices) is None or choices > 0\n            else Random(0)\n        )\n\n    return ConjectureData(random=random, observer=observer)\n\n\ndef clamped_shrink_towards(constraints):\n    v = constraints[\"shrink_towards\"]\n    if constraints[\"min_value\"] is not None:\n        v = max(constraints[\"min_value\"], v)\n    if constraints[\"max_value\"] is not None:\n        v = min(constraints[\"max_value\"], v)\n    return v\n\n\ndef draw_value(choice_type, constraints):\n    data = fresh_data()\n    return getattr(data, f\"draw_{choice_type}\")(**constraints)\n\n\n@st.composite\ndef choices(draw):\n    (choice_type, constraints) = draw(choice_types_constraints())\n    return draw_value(choice_type, constraints)\n\n\n@st.composite\ndef nodes(draw, *, was_forced=None, choice_types=None):\n    if choice_types is None:\n        (choice_type, constraints) = draw(choice_types_constraints())\n    else:\n        choice_type = draw(st.sampled_from(choice_types))\n        constraints = draw(constraints_strategy(choice_type))\n    # choice nodes don't include forced in their constraints. see was_forced attribute\n    del constraints[\"forced\"]\n    value = draw_value(choice_type, constraints)\n    was_forced = draw(st.booleans()) if was_forced is None else was_forced\n\n    return ChoiceNode(\n        type=choice_type, value=value, constraints=constraints, was_forced=was_forced\n    )\n\n\ndef nodes_inline(*values: list[ChoiceT]) -> list[ChoiceNode]:\n    \"\"\"\n    For inline-creating a choice node or list of choice nodes, where you don't\n    care about the constraints. This uses maximally-permissable constraints and\n    infers the choice_type you meant based on the type of the value.\n\n    You can optionally pass (value, constraints) to as an element in order to override\n    the default constraints for that element.\n    \"\"\"\n    mapping = {\n        float: (\n            \"float\",\n            {\n                \"min_value\": -math.inf,\n                \"max_value\": math.inf,\n                \"allow_nan\": True,\n                \"smallest_nonzero_magnitude\": SMALLEST_SUBNORMAL,\n            },\n        ),\n        int: (\n            \"integer\",\n            {\n                \"min_value\": None,\n                \"max_value\": None,\n                \"weights\": None,\n                \"shrink_towards\": 0,\n            },\n        ),\n        str: (\n            \"string\",\n            {\n                \"intervals\": IntervalSet(((0, sys.maxunicode),)),\n                \"min_size\": 0,\n                \"max_size\": COLLECTION_DEFAULT_MAX_SIZE,\n            },\n        ),\n        bytes: (\"bytes\", {\"min_size\": 0, \"max_size\": COLLECTION_DEFAULT_MAX_SIZE}),\n        bool: (\"boolean\", {\"p\": 0.5}),\n    }\n    nodes = []\n    for value in values:\n        override_constraints = {}\n        if isinstance(value, tuple):\n            (value, override_constraints) = value\n            if override_constraints is None:\n                override_constraints = {}\n\n        (choice_type, constraints) = mapping[type(value)]\n\n        nodes.append(\n            ChoiceNode(\n                type=choice_type,\n                value=value,\n                constraints=constraints | override_constraints,\n                was_forced=False,\n            )\n        )\n\n    return tuple(nodes)\n\n\ndef float_constr(\n    min_value=-math.inf,\n    max_value=math.inf,\n    *,\n    allow_nan=True,\n    smallest_nonzero_magnitude=SMALLEST_SUBNORMAL,\n):\n    return {\n        \"min_value\": float(min_value),\n        \"max_value\": float(max_value),\n        \"allow_nan\": allow_nan,\n        \"smallest_nonzero_magnitude\": float(smallest_nonzero_magnitude),\n    }\n\n\ndef integer_constr(min_value=None, max_value=None, *, weights=None, shrink_towards=0):\n    return {\n        \"min_value\": min_value,\n        \"max_value\": max_value,\n        \"weights\": weights,\n        \"shrink_towards\": shrink_towards,\n    }\n\n\ndef string_constr(intervals, *, min_size=0, max_size=COLLECTION_DEFAULT_MAX_SIZE):\n    return {\"intervals\": intervals, \"min_size\": min_size, \"max_size\": max_size}\n\n\n# we could in theory define bytes_constr and boolean_constr, but without any\n# default kw values they aren't really a time save.\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_choice.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nimport sys\nfrom copy import deepcopy\n\nimport pytest\n\nfrom hypothesis import (\n    HealthCheck,\n    assume,\n    example,\n    given,\n    note,\n    settings,\n    strategies as st,\n)\nfrom hypothesis.errors import StopTest\nfrom hypothesis.internal.conjecture.choice import (\n    ChoiceNode,\n    ChoiceTemplate,\n    choice_equal,\n    choice_from_index,\n    choice_permitted,\n    choice_to_index,\n    choices_key,\n)\nfrom hypothesis.internal.conjecture.data import (\n    COLLECTION_DEFAULT_MAX_SIZE,\n    ConjectureData,\n    Status,\n    choices_size,\n)\nfrom hypothesis.internal.conjecture.datatree import (\n    MAX_CHILDREN_EFFECTIVELY_INFINITE,\n    all_children,\n    compute_max_children,\n)\nfrom hypothesis.internal.conjecture.engine import choice_count\nfrom hypothesis.internal.conjecture.provider_conformance import integer_constraints\nfrom hypothesis.internal.floats import SMALLEST_SUBNORMAL, next_down, next_up\nfrom hypothesis.internal.intervalsets import IntervalSet\n\nfrom tests.common.debug import minimal\nfrom tests.conjecture.common import (\n    choice_types_constraints,\n    clamped_shrink_towards,\n    draw_value,\n    float_constr,\n    fresh_data,\n    integer_constr,\n    nodes,\n)\n\n\n# we max out at 128 bit integers in the *unbounded* case, but someone may\n# specify a bound with a larger magnitude. Ensure we calculate max children for\n# those cases correctly.\n@example((\"integer\", integer_constr(max_value=-(2**200))))\n@example((\"integer\", integer_constr(min_value=2**200)))\n@example((\"integer\", integer_constr(-(2**200), 2**200)))\n@given(choice_types_constraints())\ndef test_compute_max_children_is_positive(choice_type_and_constraints):\n    choice_type, constraints = choice_type_and_constraints\n    assert compute_max_children(choice_type, constraints) >= 0\n\n\n@pytest.mark.parametrize(\n    \"choice_type, constraints, count_children\",\n    [\n        (\"integer\", {\"min_value\": 1, \"max_value\": 2, \"weights\": {1: 0.1, 2: 0.1}}, 2),\n        # only possibility is the empty string\n        (\n            \"string\",\n            {\"min_size\": 0, \"max_size\": 100, \"intervals\": IntervalSet.from_string(\"\")},\n            1,\n        ),\n        (\n            \"string\",\n            {\"min_size\": 0, \"max_size\": 0, \"intervals\": IntervalSet.from_string(\"abc\")},\n            1,\n        ),\n        # 3 possibilities for each character, 8 characters, 3 ** 8 possibilities.\n        (\n            \"string\",\n            {\"min_size\": 8, \"max_size\": 8, \"intervals\": IntervalSet.from_string(\"abc\")},\n            3**8,\n        ),\n        (\n            \"string\",\n            {\n                \"min_size\": 2,\n                \"max_size\": 8,\n                \"intervals\": IntervalSet.from_string(\"abcd\"),\n            },\n            sum(4**k for k in range(2, 8 + 1)),\n        ),\n        (\n            \"string\",\n            {\n                \"min_size\": 0,\n                \"max_size\": COLLECTION_DEFAULT_MAX_SIZE,\n                \"intervals\": IntervalSet.from_string(\"a\"),\n            },\n            COLLECTION_DEFAULT_MAX_SIZE + 1,\n        ),\n        (\n            \"string\",\n            {\n                \"min_size\": 0,\n                \"max_size\": 10_000,\n                \"intervals\": IntervalSet.from_string(\"abcdefg\"),\n            },\n            MAX_CHILDREN_EFFECTIVELY_INFINITE,\n        ),\n        (\n            \"bytes\",\n            {\n                \"min_size\": 0,\n                \"max_size\": 2,\n            },\n            sum(2 ** (8 * k) for k in range(2 + 1)),\n        ),\n        (\n            \"bytes\",\n            {\n                \"min_size\": 0,\n                \"max_size\": COLLECTION_DEFAULT_MAX_SIZE,\n            },\n            MAX_CHILDREN_EFFECTIVELY_INFINITE,\n        ),\n        (\n            \"bytes\",\n            {\n                \"min_size\": 0,\n                \"max_size\": 10_000,\n            },\n            MAX_CHILDREN_EFFECTIVELY_INFINITE,\n        ),\n        (\"boolean\", {\"p\": 0.0}, 1),\n        (\"boolean\", {\"p\": 1.0}, 1),\n        (\"boolean\", {\"p\": 0.5}, 2),\n        (\"boolean\", {\"p\": 0.001}, 2),\n        (\"boolean\", {\"p\": 0.999}, 2),\n        (\"float\", float_constr(0.0, 0.0), 1),\n        (\"float\", float_constr(-0.0, -0.0), 1),\n        (\"float\", float_constr(-0.0, 0.0), 2),\n        (\"float\", float_constr(next_down(-0.0), next_up(0.0)), 4),\n        (\n            \"float\",\n            float_constr(\n                next_down(next_down(-0.0)),\n                next_up(next_up(0.0)),\n                smallest_nonzero_magnitude=next_up(SMALLEST_SUBNORMAL),\n            ),\n            4,\n        ),\n        (\"float\", float_constr(smallest_nonzero_magnitude=next_down(math.inf)), 6),\n        (\"float\", float_constr(1, 10, smallest_nonzero_magnitude=11.0), 0),\n        (\"float\", float_constr(-3, -2, smallest_nonzero_magnitude=4.0), 0),\n    ],\n)\ndef test_compute_max_children(choice_type, constraints, count_children):\n    assert compute_max_children(choice_type, constraints) == count_children\n\n\n@given(st.text(min_size=1, max_size=1), st.integers(0, 100))\ndef test_draw_string_single_interval_with_equal_bounds(s, n):\n    data = fresh_data()\n    intervals = IntervalSet.from_string(s)\n    assert data.draw_string(intervals, min_size=n, max_size=n) == s * n\n\n\n@example((\"boolean\", {\"p\": 2**-65}))\n@example((\"boolean\", {\"p\": 1 - 2**-65}))\n@example(\n    (\n        \"string\",\n        {\"min_size\": 0, \"max_size\": 0, \"intervals\": IntervalSet.from_string(\"abc\")},\n    )\n)\n@example(\n    (\"string\", {\"min_size\": 0, \"max_size\": 3, \"intervals\": IntervalSet.from_string(\"\")})\n)\n@example(\n    (\n        \"string\",\n        {\"min_size\": 0, \"max_size\": 3, \"intervals\": IntervalSet.from_string(\"a\")},\n    )\n)\n# all combinations of float signs\n@example((\"float\", float_constr(next_down(-0.0), -0.0)))\n@example((\"float\", float_constr(next_down(-0.0), next_up(0.0))))\n@example((\"float\", float_constr(0.0, next_up(0.0))))\n# using a smallest_nonzero_magnitude which happens to filter out everything\n@example((\"float\", float_constr(1.0, 2.0, smallest_nonzero_magnitude=3.0)))\n@example((\"integer\", integer_constr(1, 2, weights={1: 0.2, 2: 0.4})))\n@given(choice_types_constraints())\n@settings(suppress_health_check=[HealthCheck.filter_too_much])\ndef test_compute_max_children_and_all_children_agree(choice_type_and_constraints):\n    choice_type, constraints = choice_type_and_constraints\n    max_children = compute_max_children(choice_type, constraints)\n\n    # avoid slowdowns / OOM when reifying extremely large all_children generators.\n    # We also hard cap at MAX_CHILDREN_EFFECTIVELY_INFINITE, because max_children\n    # returns approximations after this value and so will disagree with\n    # all_children.\n    cap = min(100_000, MAX_CHILDREN_EFFECTIVELY_INFINITE)\n    assume(max_children < cap)\n    assert len(list(all_children(choice_type, constraints))) == max_children\n\n\n# it's very hard to test that unbounded integer ranges agree with\n# compute_max_children, because they by necessity require iterating over 2**127\n# or more elements. We do the not great approximation of checking just the first\n# element is what we expect.\n\n\n@given(integer_constraints())\ndef test_compute_max_children_unbounded_integer_ranges(constraints):\n    expected = clamped_shrink_towards(constraints)\n    first = next(all_children(\"integer\", constraints))\n    assert expected == first, (expected, first)\n\n\n@given(st.randoms())\ndef test_nodes(random):\n    data = fresh_data(random=random)\n    data.draw_float(min_value=-10.0, max_value=10.0, forced=5.0)\n    data.draw_boolean(forced=True)\n\n    data.start_span(42)\n    data.draw_string(IntervalSet.from_string(\"abcd\"), forced=\"abbcccdddd\")\n    data.draw_bytes(8, 8, forced=bytes(8))\n    data.stop_span()\n\n    data.draw_integer(0, 100, forced=50)\n\n    data.freeze()\n    expected_tree_nodes = (\n        ChoiceNode(\n            type=\"float\",\n            value=5.0,\n            constraints=float_constr(-10.0, 10.0),\n            was_forced=True,\n        ),\n        ChoiceNode(\n            type=\"boolean\",\n            value=True,\n            constraints={\"p\": 0.5},\n            was_forced=True,\n        ),\n        ChoiceNode(\n            type=\"string\",\n            value=\"abbcccdddd\",\n            constraints={\n                \"intervals\": IntervalSet.from_string(\"abcd\"),\n                \"min_size\": 0,\n                \"max_size\": COLLECTION_DEFAULT_MAX_SIZE,\n            },\n            was_forced=True,\n        ),\n        ChoiceNode(\n            type=\"bytes\",\n            value=bytes(8),\n            constraints={\"min_size\": 8, \"max_size\": 8},\n            was_forced=True,\n        ),\n        ChoiceNode(\n            type=\"integer\",\n            value=50,\n            constraints=integer_constr(0, 100),\n            was_forced=True,\n        ),\n    )\n    assert data.nodes == expected_tree_nodes\n\n\n@given(nodes())\ndef test_copy_choice_node(node):\n    assert node == node\n\n    assume(not node.was_forced)\n    new_value = draw_value(node.type, node.constraints)\n    # if we drew the same value as before, the node should still be equal\n    assert (node.copy(with_value=new_value) == node) is (\n        choice_equal(new_value, node.value)\n    )\n\n\n@given(nodes())\ndef test_choice_node_equality(node):\n    assert node == node\n    # for coverage on our NotImplemented return, more than anything.\n    assert node != 42\n\n\n@given(nodes(was_forced=True))\ndef test_cannot_modify_forced_nodes(node):\n    with pytest.raises(AssertionError):\n        node.copy(with_value=42)\n\n\ndef test_data_with_empty_choices_is_overrun():\n    data = ConjectureData.for_choices([])\n    with pytest.raises(StopTest):\n        data.draw_integer()\n\n    assert data.status is Status.OVERRUN\n\n\n@given(nodes(was_forced=True))\ndef test_data_with_changed_forced_value(node):\n    # we had a forced node and then tried to draw a different forced value from it.\n    # nodes:   v1 [was_forced=True]\n    # drawing:    [forced=v2]\n    #\n    # This is actually fine; we'll just ignore the forced node (v1) and return\n    # what the draw expects (v2).\n\n    data = ConjectureData.for_choices([node.value])\n\n    draw_func = getattr(data, f\"draw_{node.type}\")\n    constraints = deepcopy(node.constraints)\n    constraints[\"forced\"] = draw_value(node.type, node.constraints)\n    assume(not choice_equal(constraints[\"forced\"], node.value))\n\n    assert choice_equal(draw_func(**constraints), constraints[\"forced\"])\n\n\n# ensure we hit bare-minimum coverage for all choice sequence types.\n@example(\n    ChoiceNode(type=\"float\", value=0.0, constraints=float_constr(), was_forced=True)\n)\n@example(\n    ChoiceNode(\n        type=\"boolean\",\n        value=False,\n        constraints={\"p\": 0.5},\n        was_forced=True,\n    )\n)\n@example(\n    ChoiceNode(\n        type=\"integer\", value=50, constraints=integer_constr(50, 100), was_forced=True\n    )\n)\n@example(\n    ChoiceNode(\n        type=\"string\",\n        value=\"aaaa\",\n        constraints={\n            \"intervals\": IntervalSet.from_string(\"bcda\"),\n            \"min_size\": 4,\n            \"max_size\": COLLECTION_DEFAULT_MAX_SIZE,\n        },\n        was_forced=True,\n    )\n)\n@example(\n    ChoiceNode(\n        type=\"bytes\",\n        value=bytes(8),\n        constraints={\"min_size\": 8, \"max_size\": 8},\n        was_forced=True,\n    )\n)\n@given(nodes(was_forced=True))\ndef test_data_with_same_forced_value_is_valid(node):\n    # we had a forced node and then drew the same forced value. This is totally\n    # fine!\n    # nodes:   v1 [was_forced=True]\n    # drawing:    [forced=v1]\n    data = ConjectureData.for_choices([node.value])\n    draw_func = getattr(data, f\"draw_{node.type}\")\n\n    constraints = deepcopy(node.constraints)\n    constraints[\"forced\"] = node.value\n    assert choice_equal(draw_func(**constraints), constraints[\"forced\"])\n\n\n@given(choice_types_constraints())\n@settings(suppress_health_check=[HealthCheck.filter_too_much])\ndef test_all_children_are_permitted_values(choice_type_and_constraints):\n    choice_type, constraints = choice_type_and_constraints\n    max_children = compute_max_children(choice_type, constraints)\n\n    cap = min(100_000, MAX_CHILDREN_EFFECTIVELY_INFINITE)\n    assume(max_children < cap)\n\n    # test that all_children -> choice_permitted (but not necessarily the converse.)\n    for value in all_children(choice_type, constraints):\n        assert choice_permitted(value, constraints), value\n\n\n@pytest.mark.parametrize(\n    \"value, constraints, permitted\",\n    [\n        (0, integer_constr(1, 2), False),\n        (2, integer_constr(0, 1), False),\n        (10, integer_constr(0, 20), True),\n        (int(2**128 / 2) - 1, integer_constr(), True),\n        (int(2**128 / 2), integer_constr(), True),\n        (math.nan, float_constr(0.0, 0.0), True),\n        (math.nan, float_constr(0.0, 0.0, allow_nan=False), False),\n        (2.0, float_constr(1.0, 3.0, smallest_nonzero_magnitude=2.5), False),\n        (\n            -2.0,\n            float_constr(-3.0, -1.0, smallest_nonzero_magnitude=2.5),\n            False,\n        ),\n        (1.0, float_constr(1.0, 1.0), True),\n        (\n            \"abcd\",\n            {\n                \"min_size\": 10,\n                \"max_size\": 20,\n                \"intervals\": IntervalSet.from_string(\"abcd\"),\n            },\n            False,\n        ),\n        (\n            \"abcd\",\n            {\n                \"min_size\": 1,\n                \"max_size\": 3,\n                \"intervals\": IntervalSet.from_string(\"abcd\"),\n            },\n            False,\n        ),\n        (\n            \"abcd\",\n            {\"min_size\": 1, \"max_size\": 10, \"intervals\": IntervalSet.from_string(\"e\")},\n            False,\n        ),\n        (\n            \"e\",\n            {\"min_size\": 1, \"max_size\": 10, \"intervals\": IntervalSet.from_string(\"e\")},\n            True,\n        ),\n        (b\"a\", {\"min_size\": 2, \"max_size\": 2}, False),\n        (b\"aa\", {\"min_size\": 2, \"max_size\": 2}, True),\n        (b\"aa\", {\"min_size\": 0, \"max_size\": 3}, True),\n        (b\"a\", {\"min_size\": 2, \"max_size\": 10}, False),\n        (True, {\"p\": 0}, False),\n        (False, {\"p\": 0}, True),\n        (True, {\"p\": 1}, True),\n        (False, {\"p\": 1}, False),\n        (True, {\"p\": 0.5}, True),\n        (False, {\"p\": 0.5}, True),\n    ],\n)\ndef test_choice_permitted(value, constraints, permitted):\n    assert choice_permitted(value, constraints) == permitted\n\n\n@given(nodes(was_forced=True))\ndef test_forced_nodes_are_trivial(node):\n    assert node.trivial\n\n\n@pytest.mark.parametrize(\n    \"node\",\n    [\n        ChoiceNode(\n            type=\"float\",\n            value=5.0,\n            constraints=float_constr(5.0, 10.0),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"float\",\n            value=0.0,\n            constraints=float_constr(-5.0, 5.0),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"float\", value=0.0, constraints=float_constr(), was_forced=False\n        ),\n        ChoiceNode(\n            type=\"boolean\", value=False, constraints={\"p\": 0.5}, was_forced=False\n        ),\n        ChoiceNode(\n            type=\"boolean\", value=True, constraints={\"p\": 1.0}, was_forced=False\n        ),\n        ChoiceNode(\n            type=\"boolean\", value=False, constraints={\"p\": 0.0}, was_forced=False\n        ),\n        ChoiceNode(\n            type=\"string\",\n            value=\"\",\n            constraints={\n                \"intervals\": IntervalSet.from_string(\"abcd\"),\n                \"min_size\": 0,\n                \"max_size\": COLLECTION_DEFAULT_MAX_SIZE,\n            },\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"string\",\n            value=\"aaaa\",\n            constraints={\n                \"intervals\": IntervalSet.from_string(\"bcda\"),\n                \"min_size\": 4,\n                \"max_size\": COLLECTION_DEFAULT_MAX_SIZE,\n            },\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"bytes\",\n            value=bytes(8),\n            constraints={\"min_size\": 8, \"max_size\": 8},\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"bytes\",\n            value=bytes(2),\n            constraints={\"min_size\": 2, \"max_size\": COLLECTION_DEFAULT_MAX_SIZE},\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"integer\",\n            value=50,\n            constraints=integer_constr(50, 100),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"integer\",\n            value=0,\n            constraints=integer_constr(-10, 10),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"integer\",\n            value=2,\n            constraints=integer_constr(-10, 10, shrink_towards=2),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"integer\",\n            value=-10,\n            constraints=integer_constr(-10, 10, shrink_towards=-12),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"integer\",\n            value=10,\n            constraints=integer_constr(-10, 10, shrink_towards=12),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"integer\", value=0, constraints=integer_constr(), was_forced=False\n        ),\n        ChoiceNode(\n            type=\"integer\",\n            value=1,\n            constraints=integer_constr(min_value=-10, shrink_towards=1),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"integer\",\n            value=1,\n            constraints=integer_constr(max_value=10, shrink_towards=1),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"integer\",\n            value=1,\n            constraints={\n                \"min_value\": None,\n                \"max_value\": None,\n                \"weights\": None,\n                \"shrink_towards\": 1,\n            },\n            was_forced=False,\n        ),\n    ],\n)\ndef test_trivial_nodes(node):\n    assert node.trivial\n\n    @st.composite\n    def values(draw):\n        data = draw(st.data()).conjecture_data\n        return getattr(data, f\"draw_{node.type}\")(**node.constraints)\n\n    # if we're trivial, then shrinking should produce the same value.\n    assert choice_equal(minimal(values()), node.value)\n\n\n@pytest.mark.parametrize(\n    \"node\",\n    [\n        ChoiceNode(\n            type=\"float\",\n            value=6.0,\n            constraints=float_constr(5.0, 10.0),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"float\",\n            value=-5.0,\n            constraints=float_constr(-5.0, 5.0),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"float\", value=1.0, constraints=float_constr(), was_forced=False\n        ),\n        ChoiceNode(\n            type=\"boolean\", value=True, constraints={\"p\": 0.5}, was_forced=False\n        ),\n        ChoiceNode(\n            type=\"boolean\", value=True, constraints={\"p\": 0.99}, was_forced=False\n        ),\n        ChoiceNode(\n            type=\"string\",\n            value=\"d\",\n            constraints={\n                \"intervals\": IntervalSet.from_string(\"abcd\"),\n                \"min_size\": 1,\n                \"max_size\": COLLECTION_DEFAULT_MAX_SIZE,\n            },\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"bytes\",\n            value=b\"\\x01\",\n            constraints={\"min_size\": 1, \"max_size\": 1},\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"bytes\",\n            value=bytes(1),\n            constraints={\"min_size\": 0, \"max_size\": COLLECTION_DEFAULT_MAX_SIZE},\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"bytes\",\n            value=bytes(2),\n            constraints={\"min_size\": 1, \"max_size\": 10},\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"integer\",\n            value=-10,\n            constraints=integer_constr(-10, 10),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"integer\", value=42, constraints=integer_constr(), was_forced=False\n        ),\n    ],\n)\ndef test_nontrivial_nodes(node):\n    assert not node.trivial\n\n    @st.composite\n    def values(draw):\n        data = draw(st.data()).conjecture_data\n        return getattr(data, f\"draw_{node.type}\")(**node.constraints)\n\n    # if we're nontrivial, then shrinking should produce something different.\n    assert not choice_equal(minimal(values()), node.value)\n\n\n@pytest.mark.parametrize(\n    \"node\",\n    [\n        ChoiceNode(\n            type=\"float\",\n            value=1.5,\n            constraints=float_constr(1.1, 1.6),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"float\",\n            value=float(math.floor(sys.float_info.max)),\n            constraints=float_constr(sys.float_info.max - 1, math.inf),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"float\",\n            value=float(math.ceil(-sys.float_info.max)),\n            constraints=float_constr(-math.inf, -sys.float_info.max + 1),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"float\",\n            value=math.inf,\n            constraints=float_constr(math.inf, math.inf),\n            was_forced=False,\n        ),\n        ChoiceNode(\n            type=\"float\",\n            value=-math.inf,\n            constraints=float_constr(-math.inf, -math.inf),\n            was_forced=False,\n        ),\n    ],\n)\ndef test_conservative_nontrivial_nodes(node):\n    # these nodes actually are trivial, but our analysis doesn't compute them\n    # as such. We'd like to improve this in the future!\n    assert not node.trivial\n\n    @st.composite\n    def values(draw):\n        data = draw(st.data()).conjecture_data\n        return getattr(data, f\"draw_{node.type}\")(**node.constraints)\n\n    assert choice_equal(minimal(values()), node.value)\n\n\n@given(nodes())\ndef test_choice_node_is_hashable(node):\n    hash(node)\n\n\n@given(st.lists(nodes()))\ndef test_choices_size_positive(nodes):\n    assert choices_size([n.value for n in nodes]) >= 0\n\n\n@given(st.integers(min_value=1))\ndef test_node_template_count(n):\n    node = ChoiceTemplate(type=\"simplest\", count=n)\n    assert choice_count([node]) == n\n\n\ndef test_node_template_to_overrun():\n    data = ConjectureData.for_choices([1, ChoiceTemplate(\"simplest\", count=5)])\n    data.draw_integer()\n    with pytest.raises(StopTest):\n        for _ in range(10):\n            data.draw_integer()\n\n    assert data.status is Status.OVERRUN\n\n\ndef test_node_template_single_node_overruns():\n    # test for when drawing a single node takes more than BUFFER_SIZE, while in\n    # the ChoiceTemplate case\n    data = ConjectureData.for_choices((ChoiceTemplate(\"simplest\", count=1),))\n    with pytest.raises(StopTest):\n        data.draw_bytes(10_000, 10_000)\n\n    assert data.status is Status.OVERRUN\n\n\n@given(nodes())\ndef test_node_template_simplest_is_actually_trivial(node):\n    # TODO_IR node.trivial is sound but not complete for floats.\n    assume(node.type != \"float\")\n    data = ConjectureData.for_choices((ChoiceTemplate(\"simplest\", count=1),))\n    getattr(data, f\"draw_{node.type}\")(**node.constraints)\n    assert len(data.nodes) == 1\n    assert data.nodes[0].trivial\n\n\n@given(choice_types_constraints())\n@example((\"boolean\", {\"p\": 0}))\n@example((\"boolean\", {\"p\": 1}))\ndef test_choice_indices_are_positive(choice_type_and_constraints):\n    choice_type, constraints = choice_type_and_constraints\n    v = draw_value(choice_type, constraints)\n    assert choice_to_index(v, constraints) >= 0\n\n\n@given(integer_constraints())\ndef test_shrink_towards_has_index_0(constraints):\n    shrink_towards = clamped_shrink_towards(constraints)\n    note({\"clamped_shrink_towards\": shrink_towards})\n    assert choice_to_index(shrink_towards, constraints) == 0\n    assert choice_from_index(0, \"integer\", constraints) == shrink_towards\n\n\n@given(choice_types_constraints())\n@settings(max_examples=20)\ndef test_choice_to_index_injective(choice_type_and_constraints):\n    # choice sequence ordering should be injective both ways.\n    choice_type, constraints = choice_type_and_constraints\n    # ...except for floats, which are hard to order bijectively.\n    assume(choice_type != \"float\")\n    # cap to 10k so this test finishes in a reasonable amount of time\n    cap = min(compute_max_children(choice_type, constraints), 10_000)\n\n    indices = set()\n    for i, choice in enumerate(all_children(choice_type, constraints)):\n        if i >= cap:\n            break\n        index = choice_to_index(choice, constraints)\n        assert index not in indices\n        indices.add(index)\n\n\n@given(choice_types_constraints())\n@settings(max_examples=10)\n@example(\n    (\n        \"string\",\n        {\"min_size\": 0, \"max_size\": 10, \"intervals\": IntervalSet.from_string(\"a\")},\n    )\n)\ndef test_choice_from_value_injective(choice_type_and_constraints):\n    choice_type, constraints = choice_type_and_constraints\n    assume(choice_type != \"float\")\n    cap = min(compute_max_children(choice_type, constraints), 10_000)\n\n    choices = set()\n    for index in range(cap):\n        choice = choice_from_index(index, choice_type, constraints)\n        assert choice not in choices\n        choices.add(choice)\n\n\n@given(choice_types_constraints())\ndef test_choice_index_and_value_are_inverses(choice_type_and_constraints):\n    choice_type, constraints = choice_type_and_constraints\n    v = draw_value(choice_type, constraints)\n    index = choice_to_index(v, constraints)\n    note({\"v\": v, \"index\": index})\n    choice_equal(choice_from_index(index, choice_type, constraints), v)\n\n\n@pytest.mark.parametrize(\n    \"choice_type, constraints, choices\",\n    [\n        (\"boolean\", {\"p\": 1}, [True]),\n        (\"boolean\", {\"p\": 0}, [False]),\n        (\"integer\", integer_constr(min_value=1, shrink_towards=4), range(1, 10)),\n        (\"integer\", integer_constr(max_value=5, shrink_towards=2), range(-10, 5 + 1)),\n        (\"integer\", integer_constr(max_value=5), range(-10, 5 + 1)),\n        (\"integer\", integer_constr(min_value=0, shrink_towards=1), range(10)),\n        (\"integer\", integer_constr(-5, 5, shrink_towards=3), range(-5, 5 + 1)),\n        (\"integer\", integer_constr(-5, 5, shrink_towards=-3), range(-5, 5 + 1)),\n        (\n            \"float\",\n            float_constr(1.0, next_up(next_up(1.0))),\n            [1.0, next_up(1.0), next_up(next_up(1.0))],\n        ),\n        (\n            \"float\",\n            float_constr(next_down(-0.0), next_up(0.0)),\n            [next_down(-0.0), -0.0, 0.0, next_up(0.0)],\n        ),\n    ],\n)\ndef test_choice_index_and_value_are_inverses_explicit(\n    choice_type, constraints, choices\n):\n    for choice in choices:\n        index = choice_to_index(choice, constraints)\n        assert choice_equal(choice_from_index(index, choice_type, constraints), choice)\n\n\n@pytest.mark.parametrize(\n    \"constraints, choices\",\n    [\n        # unbounded\n        (integer_constr(), (0, 1, -1, 2, -2, 3, -3)),\n        (integer_constr(shrink_towards=2), (2, 3, 1, 4, 0, 5, -1, 6, -2)),\n        # semibounded (below)\n        (integer_constr(min_value=3), (3, 4, 5, 6, 7)),\n        (integer_constr(min_value=3, shrink_towards=5), (5, 6, 4, 7, 3, 8, 9)),\n        (integer_constr(min_value=-3), (0, 1, -1, 2, -2, 3, -3, 4, 5, 6)),\n        (integer_constr(min_value=-3, shrink_towards=-1), (-1, 0, -2, 1, -3, 2, 3, 4)),\n        # semibounded (above)\n        (integer_constr(max_value=3), (0, 1, -1, 2, -2, 3, -3, -4, -5, -6)),\n        (integer_constr(max_value=3, shrink_towards=1), (1, 2, 0, 3, -1, -2, -3, -4)),\n        (integer_constr(max_value=-3), (-3, -4, -5, -6, -7)),\n        (integer_constr(max_value=-3, shrink_towards=-5), (-5, -4, -6, -3, -7, -8, -9)),\n        # bounded\n        (integer_constr(-3, 3), (0, 1, -1, 2, -2, 3, -3)),\n        (integer_constr(-3, 3, shrink_towards=1), (1, 2, 0, 3, -1, -2, -3)),\n        (integer_constr(-3, 3, shrink_towards=-1), (-1, 0, -2, 1, -3, 2, 3)),\n    ],\n    ids=repr,\n)\ndef test_integer_choice_index(constraints, choices):\n    # explicit test which checks that the order of `choices` matches the index\n    # order.\n    for i, choice in enumerate(choices):\n        assert choice_to_index(choice, constraints) == i\n\n\n@given(st.lists(nodes()))\ndef test_drawing_directly_matches_for_choices(nodes):\n    data = ConjectureData.for_choices([n.value for n in nodes])\n    for node in nodes:\n        value = getattr(data, f\"draw_{node.type}\")(**node.constraints)\n        assert choice_equal(node.value, value)\n\n\ndef test_draw_directly_explicit():\n    # this is a much weaker and more explicit variant of the property-based test\n    # directly above, but this is such an important thing to ensure that we have\n    # correct that it's worth some duplication in case we ever screw up our pbt test.\n    assert (\n        ConjectureData.for_choices([\"a\"]).draw_string(\n            IntervalSet([(0, 127)]), min_size=1\n        )\n        == \"a\"\n    )\n    assert ConjectureData.for_choices([b\"a\"]).draw_bytes() == b\"a\"\n    assert (\n        ConjectureData.for_choices([1.0]).draw_float(\n            0.0, 2.0, allow_nan=False, smallest_nonzero_magnitude=0.5\n        )\n        == 1.0\n    )\n    assert ConjectureData.for_choices([True]).draw_boolean(0.3)\n    assert ConjectureData.for_choices([42]).draw_integer() == 42\n    assert (\n        ConjectureData.for_choices([-42]).draw_integer(min_value=-50, max_value=0)\n        == -42\n    )\n    assert (\n        ConjectureData.for_choices([10]).draw_integer(\n            min_value=10, max_value=11, weights={10: 0.1, 11: 0.3}\n        )\n        == 10\n    )\n\n\n@pytest.mark.parametrize(\n    \"choices1, choices2\",\n    [\n        [(True,), (1,)],\n        [(True,), (1.0,)],\n        [(False,), (0,)],\n        [(False,), (0.0,)],\n        [(False,), (-0.0,)],\n        [(0.0,), (-0.0,)],\n    ],\n)\ndef test_choices_key_distinguishes_weird_cases(choices1, choices2):\n    assert choices_key(choices1) != choices_key(choices2)\n\n\ndef test_node_template_overrun():\n    # different code path for overruning the ChoiceTemplate count, not BUFFER_SIZE.\n    cd = ConjectureData(\n        random=None,\n        prefix=[ChoiceTemplate(\"simplest\", count=2)],\n        max_choices=100,\n    )\n\n    cd.draw_integer()\n    cd.draw_integer()\n    try:\n        cd.draw_integer()\n    except StopTest:\n        pass\n    assert cd.status is Status.OVERRUN\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_choice_tree.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom random import Random\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.internal.conjecture.shrinking.choicetree import (\n    ChoiceTree,\n    prefix_selection_order,\n    random_selection_order,\n)\n\n\ndef select(*args):\n    return prefix_selection_order(args)\n\n\ndef exhaust(f):\n    tree = ChoiceTree()\n\n    results = []\n\n    prefix = ()\n\n    while not tree.exhausted:\n        prefix = tree.step(\n            prefix_selection_order(prefix), lambda chooser: results.append(f(chooser))\n        )\n    return results\n\n\n@given(st.lists(st.integers()))\ndef test_can_enumerate_a_shallow_set(ls):\n    results = exhaust(lambda chooser: chooser.choose(ls))\n\n    assert sorted(results) == sorted(ls)\n\n\ndef test_can_enumerate_a_nested_set():\n    @exhaust\n    def nested(chooser):\n        i = chooser.choose(range(10))\n        j = chooser.choose(range(10), condition=lambda j: j > i)\n        return (i, j)\n\n    assert sorted(nested) == [(i, j) for i in range(10) for j in range(i + 1, 10)]\n\n\ndef test_can_enumerate_empty():\n    @exhaust\n    def empty(chooser):\n        return 1\n\n    assert empty == [1]\n\n\ndef test_all_filtered_child():\n    @exhaust\n    def all_filtered(chooser):\n        chooser.choose(range(10), condition=lambda j: False)\n\n    assert all_filtered == []\n\n\ndef test_skips_over_exhausted_children():\n    results = []\n\n    def f(chooser):\n        results.append(\n            (\n                chooser.choose(range(3), condition=lambda x: x > 0),\n                chooser.choose(range(2)),\n            )\n        )\n\n    tree = ChoiceTree()\n\n    tree.step(select(1, 0), f)\n    tree.step(select(1, 1), f)\n    tree.step(select(0, 0), f)\n\n    assert results == [(1, 0), (1, 1), (2, 0)]\n\n\ndef test_extends_prefix_from_right():\n    def f(chooser):\n        chooser.choose(range(4))\n\n    tree = ChoiceTree()\n    result = tree.step(select(), f)\n    assert result == (3,)\n\n\ndef test_starts_from_the_end():\n    def f(chooser):\n        chooser.choose(range(3))\n\n    tree = ChoiceTree()\n    assert tree.step(select(), f) == (2,)\n\n\ndef test_skips_over_exhausted_subtree():\n    def f(chooser):\n        chooser.choose(range(10))\n\n    tree = ChoiceTree()\n    assert tree.step(select(8), f) == (8,)\n    assert tree.step(select(8), f) == (7,)\n\n\ndef test_exhausts_randomly():\n    def f(chooser):\n        chooser.choose(range(10))\n\n    tree = ChoiceTree()\n\n    random = Random()\n\n    seen = set()\n\n    for _ in range(10):\n        seen.add(tree.step(random_selection_order(random), f))\n\n    assert len(seen) == 10\n    assert tree.exhausted\n\n\ndef test_exhausts_randomly_when_filtering():\n    def f(chooser):\n        chooser.choose(range(10), lambda x: False)\n\n    tree = ChoiceTree()\n\n    random = Random()\n\n    tree.step(random_selection_order(random), f)\n\n    assert tree.exhausted\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_data_tree.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport textwrap\nfrom random import Random\n\nimport pytest\n\nfrom hypothesis import HealthCheck, assume, given, settings\nfrom hypothesis.errors import Flaky\nfrom hypothesis.internal.conjecture.choice import ChoiceTemplate\nfrom hypothesis.internal.conjecture.data import ConjectureData, Status, StopTest\nfrom hypothesis.internal.conjecture.datatree import (\n    Branch,\n    DataTree,\n    compute_max_children,\n)\nfrom hypothesis.internal.conjecture.engine import ConjectureRunner\nfrom hypothesis.internal.conjecture.floats import float_to_int\nfrom hypothesis.internal.conjecture.provider_conformance import (\n    boolean_constraints,\n    integer_constraints,\n)\nfrom hypothesis.internal.floats import next_up\nfrom hypothesis.vendor import pretty\n\nfrom tests.conjecture.common import (\n    constraints_strategy,\n    fresh_data,\n    interesting_origin,\n    nodes,\n    run_to_nodes,\n)\n\nrunner_settings = settings(\n    max_examples=100, database=None, suppress_health_check=list(HealthCheck)\n)\n\n\ndef runner_for(*examples):\n    def accept(tf):\n        runner = ConjectureRunner(\n            tf, settings=runner_settings, random=Random(0), ignore_limits=True\n        )\n        ran_examples = []\n        for choices in examples:\n            data = runner.cached_test_function(choices)\n            ran_examples.append((choices, data))\n        for choices, d in ran_examples:\n            rewritten, status = runner.tree.rewrite(choices)\n            assert status == d.status\n            assert rewritten == d.choices\n        return runner\n\n    return accept\n\n\ndef test_can_lookup_cached_examples():\n    @runner_for((0, 0), (0, 1))\n    def runner(data):\n        data.draw_integer()\n        data.draw_integer()\n\n\ndef test_can_lookup_cached_examples_with_forced():\n    @runner_for((0, 0), (0, 1))\n    def runner(data):\n        data.draw_integer(forced=1)\n        data.draw_integer()\n\n\ndef test_can_detect_when_tree_is_exhausted():\n    @runner_for((False,), (True,))\n    def runner(data):\n        data.draw_boolean()\n\n    assert runner.tree.is_exhausted\n\n\ndef test_can_detect_when_tree_is_exhausted_variable_size():\n    @runner_for((False,), (True, False), (True, True))\n    def runner(data):\n        if data.draw_boolean():\n            data.draw_boolean()\n\n    assert runner.tree.is_exhausted\n\n\ndef test_one_dead_branch():\n    @runner_for(*([(0, i) for i in range(16)] + [(i,) for i in range(1, 16)]))\n    def runner(data):\n        i = data.draw_integer(0, 15)\n        if i > 0:\n            data.mark_invalid()\n        data.draw_integer(0, 15)\n\n    assert runner.tree.is_exhausted\n\n\ndef test_non_dead_root():\n    @runner_for((False, False), (True, False), (True, True))\n    def runner(data):\n        data.draw_boolean()\n        data.draw_boolean()\n\n\ndef test_can_reexecute_dead_examples():\n    @runner_for((False, False), (False, True), (False, False))\n    def runner(data):\n        data.draw_boolean()\n        data.draw_boolean()\n\n\ndef test_novel_prefixes_are_novel():\n    def tf(data):\n        for _ in range(4):\n            data.draw_bytes(1, 1, forced=b\"\\0\")\n            data.draw_integer(0, 3)\n\n    runner = ConjectureRunner(\n        tf, settings=settings(runner_settings, max_examples=1000), random=Random(0)\n    )\n    for _ in range(100):\n        prefix = runner.tree.generate_novel_prefix(runner.random)\n        extension = prefix + (ChoiceTemplate(\"simplest\", count=100),)\n        assert runner.tree.rewrite(extension)[1] is None\n        result = runner.cached_test_function(extension)\n        assert runner.tree.rewrite(extension)[0] == result.choices\n\n\ndef test_overruns_if_prefix():\n    runner = ConjectureRunner(\n        lambda data: [data.draw_boolean() for _ in range(2)],\n        settings=runner_settings,\n        random=Random(0),\n    )\n    runner.cached_test_function([False, False])\n    assert runner.tree.rewrite([False])[1] is Status.OVERRUN\n\n\ndef test_stores_the_tree_flat_until_needed():\n    @runner_for((False,) * 10)\n    def runner(data):\n        for _ in range(10):\n            data.draw_boolean()\n        data.mark_interesting(interesting_origin())\n\n    root = runner.tree.root\n    assert len(root.constraints) == 10\n    assert len(root.values) == 10\n    assert root.transition.status == Status.INTERESTING\n\n\ndef test_split_in_the_middle():\n    @runner_for((0, 0, 2), (0, 1, 3))\n    def runner(data):\n        data.draw_integer(0, 1)\n        data.draw_integer(0, 1)\n        data.draw_integer(0, 15)\n        data.mark_interesting(interesting_origin())\n\n    root = runner.tree.root\n    assert len(root.constraints) == len(root.values) == 1\n    assert list(root.transition.children[0].values) == [2]\n    assert list(root.transition.children[1].values) == [3]\n\n\ndef test_stores_forced_nodes():\n    @runner_for((0, 0, 0))\n    def runner(data):\n        data.draw_integer(0, 1, forced=0)\n        data.draw_integer(0, 1)\n        data.draw_integer(0, 1, forced=0)\n        data.mark_interesting(interesting_origin())\n\n    root = runner.tree.root\n    assert root.forced == {0, 2}\n\n\ndef test_correctly_relocates_forced_nodes():\n    @runner_for((0, 0), (1, 0))\n    def runner(data):\n        data.draw_integer(0, 1)\n        data.draw_integer(0, 1, forced=0)\n        data.mark_interesting(interesting_origin())\n\n    root = runner.tree.root\n    assert root.transition.children[1].forced == {0}\n    assert root.transition.children[0].forced == {0}\n\n\ndef test_can_go_from_interesting_to_valid():\n    tree = DataTree()\n    data = ConjectureData.for_choices([], observer=tree.new_observer())\n    with pytest.raises(StopTest):\n        data.conclude_test(Status.INTERESTING)\n\n    data = ConjectureData.for_choices([], observer=tree.new_observer())\n    with pytest.raises(StopTest):\n        data.conclude_test(Status.VALID)\n\n\ndef test_going_from_interesting_to_invalid_is_flaky():\n    tree = DataTree()\n    data = ConjectureData.for_choices([], observer=tree.new_observer())\n    with pytest.raises(StopTest):\n        data.conclude_test(Status.INTERESTING)\n\n    data = ConjectureData.for_choices([], observer=tree.new_observer())\n    with pytest.raises(Flaky):\n        data.conclude_test(Status.INVALID)\n\n\ndef test_concluding_at_prefix_is_flaky():\n    tree = DataTree()\n    data = ConjectureData.for_choices((True,), observer=tree.new_observer())\n    data.draw_boolean()\n    with pytest.raises(StopTest):\n        data.conclude_test(Status.INTERESTING)\n\n    data = ConjectureData.for_choices([], observer=tree.new_observer())\n    with pytest.raises(Flaky):\n        data.conclude_test(Status.INVALID)\n\n\ndef test_concluding_with_overrun_at_prefix_is_not_flaky():\n    tree = DataTree()\n    data = ConjectureData.for_choices((True,), observer=tree.new_observer())\n    data.draw_boolean()\n    with pytest.raises(StopTest):\n        data.conclude_test(Status.INTERESTING)\n\n    data = ConjectureData.for_choices([], observer=tree.new_observer())\n    with pytest.raises(StopTest):\n        data.conclude_test(Status.OVERRUN)\n\n\ndef test_changing_n_bits_is_flaky_in_prefix():\n    tree = DataTree()\n    data = ConjectureData.for_choices((1,), observer=tree.new_observer())\n    data.draw_integer(0, 1)\n    with pytest.raises(StopTest):\n        data.conclude_test(Status.INTERESTING)\n\n    data = ConjectureData.for_choices((1,), observer=tree.new_observer())\n    with pytest.raises(Flaky):\n        data.draw_integer(0, 3)\n\n\ndef test_changing_n_bits_is_flaky_in_branch():\n    tree = DataTree()\n\n    for i in [0, 1]:\n        data = ConjectureData.for_choices((i,), observer=tree.new_observer())\n        data.draw_integer(0, 1)\n        with pytest.raises(StopTest):\n            data.conclude_test(Status.INTERESTING)\n\n    data = ConjectureData.for_choices((1,), observer=tree.new_observer())\n    with pytest.raises(Flaky):\n        data.draw_integer(0, 3)\n\n\ndef test_extending_past_conclusion_is_flaky():\n    tree = DataTree()\n    data = ConjectureData.for_choices((True,), observer=tree.new_observer())\n    data.draw_boolean()\n    with pytest.raises(StopTest):\n        data.conclude_test(Status.INTERESTING)\n\n    data = ConjectureData.for_choices((True, False), observer=tree.new_observer())\n    data.draw_boolean()\n\n    with pytest.raises(Flaky):\n        data.draw_boolean()\n\n\ndef test_changing_to_forced_is_flaky():\n    tree = DataTree()\n    data = ConjectureData.for_choices((True,), observer=tree.new_observer())\n    data.draw_boolean()\n    with pytest.raises(StopTest):\n        data.conclude_test(Status.INTERESTING)\n\n    data = ConjectureData.for_choices((True, False), observer=tree.new_observer())\n\n    with pytest.raises(Flaky):\n        data.draw_boolean(forced=True)\n\n\ndef test_changing_value_of_forced_is_flaky():\n    tree = DataTree()\n    data = ConjectureData.for_choices((True,), observer=tree.new_observer())\n    data.draw_boolean(forced=True)\n    with pytest.raises(StopTest):\n        data.conclude_test(Status.INTERESTING)\n\n    data = ConjectureData.for_choices((True, False), observer=tree.new_observer())\n\n    with pytest.raises(Flaky):\n        data.draw_boolean(forced=False)\n\n\ndef test_does_not_truncate_if_unseen():\n    tree = DataTree()\n    nodes = (1, 2, 3, 4)\n    assert tree.rewrite(nodes) == (nodes, None)\n\n\ndef test_truncates_if_seen():\n    tree = DataTree()\n\n    nodes = (1, 2, 3, 4)\n\n    data = ConjectureData.for_choices(nodes, observer=tree.new_observer())\n    data.draw_integer()\n    data.draw_integer()\n    data.freeze()\n\n    assert tree.rewrite(nodes) == (nodes[:2], Status.VALID)\n\n\ndef test_child_becomes_exhausted_after_split():\n    tree = DataTree()\n    data = ConjectureData.for_choices((b\"\\0\", b\"\\0\"), observer=tree.new_observer())\n    data.draw_bytes(1, 1)\n    data.draw_bytes(1, 1, forced=b\"\\0\")\n    data.freeze()\n\n    data = ConjectureData.for_choices((b\"\\1\", b\"\\0\"), observer=tree.new_observer())\n    data.draw_bytes(1, 1)\n    data.draw_bytes(1, 1)\n    data.freeze()\n\n    assert not tree.is_exhausted\n    assert tree.root.transition.children[b\"\\0\"].is_exhausted\n\n\ndef test_will_generate_novel_prefix_to_avoid_exhausted_branches():\n    tree = DataTree()\n    data = ConjectureData.for_choices((1,), observer=tree.new_observer())\n    data.draw_integer(0, 1)\n    data.freeze()\n\n    data = ConjectureData.for_choices((0, b\"\\1\"), observer=tree.new_observer())\n    data.draw_integer(0, 1)\n    data.draw_bytes(1, 1)\n    data.freeze()\n\n    prefix = tree.generate_novel_prefix(Random(0))\n\n    assert len(prefix) == 2\n    assert prefix[0] == 0\n\n\ndef test_will_mark_changes_in_discard_as_flaky():\n    tree = DataTree()\n    data = ConjectureData.for_choices((1, 1), observer=tree.new_observer())\n    data.start_span(10)\n    data.draw_integer(0, 1)\n    data.stop_span()\n    data.draw_integer(0, 1)\n    data.freeze()\n\n    data = ConjectureData.for_choices((1, 1), observer=tree.new_observer())\n    data.start_span(10)\n    data.draw_integer(0, 1)\n\n    with pytest.raises(Flaky):\n        data.stop_span(discard=True)\n\n\ndef test_is_not_flaky_on_positive_zero_and_negative_zero():\n    # if we store floats in a naive way, the 0.0 and -0.0 draws will be treated\n    # equivalently and will lead to flaky errors when they diverge on the boolean\n    # draw.\n    tree = DataTree()\n\n    data = ConjectureData.for_choices((0.0, False), observer=tree.new_observer())\n    f = data.draw_float()\n    assert float_to_int(f) == float_to_int(0.0)\n    data.draw_boolean()\n    data.freeze()\n\n    data = ConjectureData.for_choices((-0.0, True), observer=tree.new_observer())\n    f = data.draw_float()\n    assert float_to_int(f) == float_to_int(-0.0)\n    data.draw_boolean()\n    data.freeze()\n\n    assert isinstance(tree.root.transition, Branch)\n    children = tree.root.transition.children\n    assert children[float_to_int(0.0)].values == [False]\n    assert children[float_to_int(-0.0)].values == [True]\n\n\ndef test_low_probabilities_are_still_explored():\n    tree = DataTree()\n    data = ConjectureData.for_choices([False], observer=tree.new_observer())\n    data.draw_boolean(p=1e-10)  # False\n\n    prefix = tree.generate_novel_prefix(Random())\n    assert prefix[0]\n\n\ndef _test_observed_draws_are_recorded_in_tree(choice_type):\n    @given(constraints_strategy(choice_type))\n    def test(constraints):\n        # we currently split pseudo-choices with a single child into their\n        # own transition, which clashes with our asserts below. If we ever\n        # change this (say, by not writing pseudo choices to the ir at all),\n        # this restriction can be relaxed.\n        assume(compute_max_children(choice_type, constraints) > 1)\n\n        tree = DataTree()\n        data = fresh_data(observer=tree.new_observer())\n        draw_func = getattr(data, f\"draw_{choice_type}\")\n        draw_func(**constraints)\n\n        assert tree.root.transition is None\n        assert tree.root.choice_types == [choice_type]\n\n    test()\n\n\ndef _test_non_observed_draws_are_not_recorded_in_tree(choice_type):\n    @given(constraints_strategy(choice_type))\n    def test(constraints):\n        assume(compute_max_children(choice_type, constraints) > 1)\n\n        tree = DataTree()\n        data = fresh_data(observer=tree.new_observer())\n        draw_func = getattr(data, f\"draw_{choice_type}\")\n        draw_func(**constraints, observe=False)\n\n        root = tree.root\n        assert root.transition is None\n        assert root.constraints == root.values == root.choice_types == []\n\n    test()\n\n\n@pytest.mark.parametrize(\n    \"choice_type\", [\"integer\", \"float\", \"boolean\", \"string\", \"bytes\"]\n)\ndef test_observed_choice_type_draw(choice_type):\n    _test_observed_draws_are_recorded_in_tree(choice_type)\n\n\n@pytest.mark.parametrize(\n    \"choice_type\", [\"integer\", \"float\", \"boolean\", \"string\", \"bytes\"]\n)\ndef test_non_observed_choice_type_draw(choice_type):\n    _test_non_observed_draws_are_not_recorded_in_tree(choice_type)\n\n\ndef test_can_generate_hard_values():\n    tree = DataTree()\n\n    min_value = 0\n    max_value = 1000\n    # set up `tree` such that [0, 999] have been drawn and only n=1000 remains.\n    for i in range(max_value):\n        data = ConjectureData.for_choices([i], observer=tree.new_observer())\n        data.draw_integer(min_value, max_value)\n        data.freeze()\n\n    # this test doubles as conjecture coverage for using our child cache, so\n    # ensure we don't miss that logic by getting lucky and drawing the correct\n    # value once or twice.\n    for _ in range(20):\n        prefix = tree.generate_novel_prefix(Random())\n        data = ConjectureData.for_choices(prefix)\n        assert data.draw_integer(min_value, max_value) == 1000\n\n\ndef test_can_generate_hard_floats():\n    # similar to test_can_generate_hard_values, but exercises float-specific\n    # logic for handling e.g. 0.0 vs -0.0 as different keys.\n    tree = DataTree()\n\n    def next_up_n(f, n):\n        for _ in range(n):\n            f = next_up(f)\n        return f\n\n    min_value = -0.0\n    max_value = next_up_n(min_value, 100)\n    for n in range(100):\n\n        @run_to_nodes\n        def nodes(data):\n            f = next_up_n(min_value, n)\n            data.draw_float(min_value, max_value, forced=f, allow_nan=False)\n            data.mark_interesting(interesting_origin())\n\n        data = ConjectureData.for_choices(\n            [n.value for n in nodes], observer=tree.new_observer()\n        )\n        data.draw_float(min_value, max_value, allow_nan=False)\n        data.freeze()\n\n    # we have left out a single value, so we can assert that generate_novel_prefix\n    # is equal to that value.\n    #\n    # this test doubles as conjecture coverage for drawing floats from the\n    # children cache. Draw a few times to ensure we hit that logic (as opposed\n    # to getting lucky and drawing the correct value the first time).\n    for _ in range(20):\n        expected_value = next_up_n(min_value, 100)\n        prefix = tree.generate_novel_prefix(Random())\n        data = ConjectureData.for_choices(prefix)\n        assert data.draw_float(min_value, max_value, allow_nan=False) == expected_value\n\n\n@given(boolean_constraints(), integer_constraints())\ndef test_datatree_repr(bool_constraints, int_constraints):\n    tree = DataTree()\n\n    origin = interesting_origin()\n\n    observer = tree.new_observer()\n    observer.draw_boolean(True, was_forced=False, constraints=bool_constraints)\n    observer.conclude_test(Status.INVALID, interesting_origin=None)\n\n    observer = tree.new_observer()\n    observer.draw_boolean(False, was_forced=False, constraints=bool_constraints)\n    observer.draw_integer(42, was_forced=False, constraints=int_constraints)\n    observer.conclude_test(Status.VALID, interesting_origin=None)\n\n    observer = tree.new_observer()\n    observer.draw_boolean(False, was_forced=False, constraints=bool_constraints)\n    observer.draw_integer(0, was_forced=False, constraints=int_constraints)\n    observer.draw_boolean(False, was_forced=True, constraints=bool_constraints)\n    observer.conclude_test(Status.INTERESTING, interesting_origin=origin)\n\n    observer = tree.new_observer()\n    observer.draw_boolean(False, was_forced=False, constraints=bool_constraints)\n    observer.draw_integer(5, was_forced=False, constraints=int_constraints)\n\n    assert (\n        pretty.pretty(tree)\n        == textwrap.dedent(\n            f\"\"\"\n        boolean True {bool_constraints}\n          Conclusion (Status.INVALID)\n        boolean False {bool_constraints}\n          integer 42 {int_constraints}\n            Conclusion (Status.VALID)\n          integer 0 {int_constraints}\n            boolean False [forced] {bool_constraints}\n              Conclusion (Status.INTERESTING, {origin})\n          integer 5 {int_constraints}\n            unknown\n        \"\"\"\n        ).strip()\n    )\n\n\ndef _draw(data, node, *, forced=None):\n    return getattr(data, f\"draw_{node.type}\")(**node.constraints, forced=forced)\n\n\n@given(nodes(was_forced=True, choice_types=[\"float\"]))\ndef test_simulate_forced_floats(node):\n    tree = DataTree()\n\n    data = ConjectureData.for_choices([node.value], observer=tree.new_observer())\n    data.draw_float(**node.constraints, forced=node.value)\n    with pytest.raises(StopTest):\n        data.conclude_test(Status.VALID)\n\n    data = ConjectureData.for_choices([node.value], observer=tree.new_observer())\n    tree.simulate_test_function(data)\n    data.freeze()\n    assert data.nodes == (node,)\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_engine.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport enum\nimport re\nimport time\nfrom random import Random\nfrom unittest.mock import Mock\n\nimport pytest\n\nfrom hypothesis import (\n    HealthCheck,\n    Phase,\n    Verbosity,\n    assume,\n    given,\n    settings,\n    strategies as st,\n)\nfrom hypothesis.database import (\n    InMemoryExampleDatabase,\n    choices_from_bytes,\n    choices_to_bytes,\n)\nfrom hypothesis.errors import FailedHealthCheck, FlakyStrategyDefinition\nfrom hypothesis.internal.compat import PYPY, bit_count, int_from_bytes\nfrom hypothesis.internal.conjecture import engine as engine_module\nfrom hypothesis.internal.conjecture.data import ConjectureData, Overrun, Status\nfrom hypothesis.internal.conjecture.datatree import compute_max_children\nfrom hypothesis.internal.conjecture.engine import (\n    INVALID_PER_VALID,\n    INVALID_THRESHOLD_BASE,\n    MIN_TEST_CALLS,\n    ConjectureRunner,\n    ExitReason,\n    HealthCheckState,\n    RunIsComplete,\n)\nfrom hypothesis.internal.conjecture.junkdrawer import startswith\nfrom hypothesis.internal.conjecture.pareto import DominanceRelation, dominance\nfrom hypothesis.internal.conjecture.shrinker import Shrinker, ShrinkPass\nfrom hypothesis.internal.coverage import IN_COVERAGE_TESTS\n\nfrom tests.common.debug import minimal\nfrom tests.common.strategies import SLOW, HardToShrink\nfrom tests.common.utils import no_shrink, skipif_time_unpatched\nfrom tests.conjecture.common import (\n    SOME_LABEL,\n    buffer_size_limit,\n    interesting_origin,\n    nodes,\n    run_to_nodes,\n    shrinking_from,\n)\n\nrunner_settings = settings(\n    max_examples=100, database=None, suppress_health_check=list(HealthCheck)\n)\n\n\ndef test_non_cloneable_intervals():\n    @run_to_nodes\n    def nodes(data):\n        data.draw_bytes(10, 10)\n        data.draw_bytes(9, 9)\n        data.mark_interesting(interesting_origin())\n\n    assert tuple(n.value for n in nodes) == (bytes(10), bytes(9))\n\n\ndef test_deletable_draws():\n    @run_to_nodes\n    def nodes(data):\n        while True:\n            x = data.draw_bytes(2, 2)\n            if x[0] == 255:\n                data.mark_interesting(interesting_origin())\n\n    assert tuple(n.value for n in nodes) == (b\"\\xff\\x00\",)\n\n\ndef test_can_load_data_from_a_corpus():\n    key = b\"hi there\"\n    db = InMemoryExampleDatabase()\n    value = b\"=\\xc3\\xe4l\\x81\\xe1\\xc2H\\xc9\\xfb\\x1a\\xb6bM\\xa8\\x7f\"\n    db.save(key, choices_to_bytes([value]))\n\n    def f(data):\n        if data.draw_bytes() == value:\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(f, settings=settings(database=db), database_key=key)\n    runner.run()\n    (last_data,) = runner.interesting_examples.values()\n    assert last_data.choices == (value,)\n    assert len(list(db.fetch(key))) == 1\n\n\ndef slow_shrinker():\n    strat = HardToShrink()\n\n    def accept(data):\n        if data.draw(strat):\n            data.mark_interesting(interesting_origin())\n\n    return accept\n\n\n@pytest.mark.parametrize(\"n\", [1, 5])\ndef test_terminates_shrinks(n, monkeypatch):\n    db = InMemoryExampleDatabase()\n\n    def generate_new_examples(self):\n        self.cached_test_function((255,) * 1000)\n\n    monkeypatch.setattr(\n        ConjectureRunner, \"generate_new_examples\", generate_new_examples\n    )\n    monkeypatch.setattr(engine_module, \"MAX_SHRINKS\", n)\n\n    runner = ConjectureRunner(\n        slow_shrinker(),\n        settings=settings(max_examples=5000, database=db),\n        random=Random(0),\n        database_key=b\"key\",\n    )\n    runner.run()\n    (last_data,) = runner.interesting_examples.values()\n    assert last_data.status == Status.INTERESTING\n    assert runner.exit_reason == ExitReason.max_shrinks\n    assert runner.shrinks == n\n    in_db = set(db.data[runner.secondary_key])\n    assert len(in_db) == n\n\n\ndef test_detects_flakiness():\n    failed_once = False\n    count = 0\n\n    def tf(data):\n        nonlocal count, failed_once\n        data.draw_bytes(1, 1)\n        count += 1\n        if not failed_once:\n            failed_once = True\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(tf)\n    runner.run()\n    assert runner.exit_reason == ExitReason.flaky\n    assert count == MIN_TEST_CALLS + 1\n\n\ndef recur(i, data):\n    if i >= 1:\n        recur(i - 1, data)\n\n\n@pytest.mark.skipif(PYPY, reason=\"stack tricks only work reliably on CPython\")\n@pytest.mark.skipif(\n    IN_COVERAGE_TESTS, reason=\"flaky under coverage instrumentation? see #4391\"\n)\ndef test_recursion_error_is_not_flaky():\n    def tf(data):\n        i = data.draw_integer(0, 2**16 - 1)\n        try:\n            recur(i, data)\n        except RecursionError:\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(tf, settings=settings(derandomize=True))\n    runner.run()\n    assert runner.exit_reason == ExitReason.finished\n\n\ndef test_variadic_draw():\n    def draw_list(data):\n        result = []\n        while True:\n            data.start_span(SOME_LABEL)\n            n = data.draw_integer(0, 2)\n            if n:\n                result.append(data.draw_bytes(n, n))\n            data.stop_span()\n            if not n:\n                break\n        return result\n\n    @run_to_nodes\n    def nodes(data):\n        if any(all(d) for d in draw_list(data)):\n            data.mark_interesting(interesting_origin())\n\n    assert tuple(n.value for n in nodes) == (1, b\"\\x01\", 0)\n\n\ndef test_draw_to_overrun():\n    @run_to_nodes\n    def nodes(data):\n        d = (data.draw_bytes(1, 1)[0] - 8) & 0xFF\n        data.draw_bytes(128 * d, 128 * d)\n        if d >= 2:\n            data.mark_interesting(interesting_origin())\n\n    assert tuple(n.value for n in nodes) == (bytes([10]),) + (bytes(128 * 2),)\n\n\ndef test_can_navigate_to_a_valid_example():\n    def f(data):\n        i = int_from_bytes(data.draw_bytes(2, 2))\n        data.draw_bytes(i, i)\n        data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(f, settings=settings(max_examples=5000, database=None))\n    with buffer_size_limit(4):\n        runner.run()\n    assert runner.interesting_examples\n\n\ndef test_stops_after_max_examples_when_reading():\n    key = b\"key\"\n\n    db = InMemoryExampleDatabase()\n    for i in range(10):\n        db.save(key, bytes([i]))\n\n    seen = []\n\n    def f(data):\n        seen.append(data.draw_bytes(1, 1))\n\n    runner = ConjectureRunner(\n        f, settings=settings(max_examples=1, database=db), database_key=key\n    )\n    runner.run()\n    assert len(seen) == 1\n\n\ndef test_stops_after_max_examples_when_generating():\n    seen = []\n\n    def f(data):\n        seen.append(data.draw_bytes(1, 1))\n\n    runner = ConjectureRunner(f, settings=settings(max_examples=1, database=None))\n    runner.run()\n    assert len(seen) == 1\n\n\n@pytest.mark.parametrize(\"examples\", [1, 5, 20, 50])\ndef test_stops_after_max_examples_when_generating_more_bugs(examples):\n    seen = []\n    err_common = False\n    err_rare = False\n\n    def f(data):\n        seen.append(data.draw_integer(0, 2**32 - 1))\n        # Rare, potentially multi-error conditions\n        nonlocal err_common, err_rare\n        if seen[-1] > 2**31:\n            err_rare = True\n            raise ValueError\n        err_common = True\n        raise Exception\n\n    runner = ConjectureRunner(\n        f, settings=settings(max_examples=examples, phases=[Phase.generate])\n    )\n    try:\n        runner.run()\n    except Exception:\n        pass\n    # No matter what, whether examples is larger or smalller than MAX_TEST_CALLS,\n    # we stop looking at max_examples.  (and re-run each failure for the traceback)\n    assert len(seen) <= examples + err_common + err_rare\n\n\ndef test_interleaving_engines():\n    children = []\n\n    @run_to_nodes\n    def nodes(data):\n        rnd = Random(data.draw_bytes(1, 1))\n\n        def g(d2):\n            d2.draw_bytes(1, 1)\n            data.mark_interesting(interesting_origin())\n\n        runner = ConjectureRunner(g, random=rnd)\n        children.append(runner)\n        runner.run()\n        if runner.interesting_examples:\n            data.mark_interesting(interesting_origin())\n\n    assert tuple(n.value for n in nodes) == (b\"\\0\",)\n    for c in children:\n        assert not c.interesting_examples\n\n\ndef test_phases_can_disable_shrinking():\n    seen = set()\n\n    def f(data):\n        seen.add(bytes(data.draw_bytes(32, 32)))\n        data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(\n        f, settings=settings(database=None, phases=(Phase.reuse, Phase.generate))\n    )\n    runner.run()\n    assert len(seen) == 1\n\n\ndef test_reuse_phase_runs_for_max_examples_if_generation_is_disabled():\n    db = InMemoryExampleDatabase()\n    for i in range(256):\n        db.save(b\"key\", choices_to_bytes([i]))\n    seen = set()\n\n    def test(data):\n        seen.add(data.draw_integer(0, 2**8 - 1))\n\n    ConjectureRunner(\n        test,\n        settings=settings(max_examples=100, database=db, phases=[Phase.reuse]),\n        database_key=b\"key\",\n        random=Random(0),\n    ).run()\n\n    assert len(seen) == 100\n\n\ndef test_erratic_draws():\n    n = 0\n\n    with pytest.raises(FlakyStrategyDefinition):\n\n        @run_to_nodes\n        def nodes(data):\n            nonlocal n\n            data.draw_bytes(n, n)\n            data.draw_bytes(255 - n, 255 - n)\n            if n == 255:\n                data.mark_interesting(interesting_origin())\n            else:\n                n += 1\n\n\ndef test_no_read_no_shrink():\n    count = 0\n\n    @run_to_nodes\n    def nodes(data):\n        nonlocal count\n        count += 1\n        data.mark_interesting(interesting_origin())\n\n    assert nodes == ()\n    assert count == 1\n\n\ndef test_one_dead_branch():\n    seen = set()\n\n    @run_to_nodes\n    def nodes(data):\n        i = data.draw_bytes(1, 1)[0]\n        if i > 0:\n            data.mark_invalid()\n        i = data.draw_bytes(1, 1)[0]\n        if len(seen) < 255:\n            seen.add(i)\n        elif i not in seen:\n            data.mark_interesting(interesting_origin())\n\n\ndef test_does_not_save_on_interrupt():\n    def interrupts(data):\n        raise KeyboardInterrupt\n\n    db = InMemoryExampleDatabase()\n    runner = ConjectureRunner(\n        interrupts, settings=settings(database=db), database_key=b\"key\"\n    )\n    with pytest.raises(KeyboardInterrupt):\n        runner.run()\n    assert not db.data\n\n\ndef test_saves_on_skip_exceptions_to_reraise():\n    # skip exceptions should be saved to the db so we spend as little time as\n    # possible exploring these tests in the future (if eg the skip is guarded\n    # by a conditional that takes some time to hit). see also\n    # https://github.com/HypothesisWorks/hypothesis/pull/4316#discussion_r2008912585\n    def raises(data):\n        pytest.skip()\n\n    db = InMemoryExampleDatabase()\n    runner = ConjectureRunner(\n        raises, settings=settings(database=db), database_key=b\"key\"\n    )\n    with pytest.raises(pytest.skip.Exception):\n        runner.run()\n\n    assert len(db.data) == 1\n\n\ndef test_returns_forced():\n    value = b\"\\0\\1\\2\\3\"\n\n    @run_to_nodes\n    def nodes(data):\n        data.draw_bytes(len(value), len(value), forced=value)\n        data.mark_interesting(interesting_origin())\n\n    assert tuple(n.value for n in nodes) == (value,)\n\n\ndef fails_health_check(label, **kwargs):\n    def accept(f):\n        runner = ConjectureRunner(\n            f,\n            settings=settings(\n                max_examples=100, phases=no_shrink, database=None, **kwargs\n            ),\n        )\n\n        with pytest.raises(FailedHealthCheck) as e:\n            runner.run()\n        assert str(label) in str(e.value)\n        assert not runner.interesting_examples\n\n    return accept\n\n\ndef test_fails_health_check_for_all_invalid():\n    @fails_health_check(HealthCheck.filter_too_much)\n    def _(data):\n        data.draw_bytes(2, 2)\n        data.mark_invalid()\n\n\ndef test_fails_health_check_for_large_base():\n    @fails_health_check(HealthCheck.large_base_example)\n    def _(data):\n        data.draw_bytes(10**6, 10**6)\n\n\ndef test_fails_health_check_for_large_non_base():\n    @fails_health_check(HealthCheck.data_too_large)\n    def _(data):\n        if data.draw_boolean():\n            data.draw_bytes(10_000, 10_000)\n\n\n@skipif_time_unpatched\ndef test_fails_health_check_for_slow_draws():\n    @fails_health_check(HealthCheck.too_slow)\n    def _(data):\n        data.draw(SLOW)\n\n\ndef test_health_check_too_slow_with_invalid_examples():\n    @st.composite\n    def s(draw):\n        n = draw(st.integers())\n        if n > 0:\n            assume(False)\n\n        time.sleep(0.2)\n\n    @given(s())\n    @settings(derandomize=True, max_examples=100)\n    def test(x):\n        pass\n\n    with pytest.raises(FailedHealthCheck) as exc:\n        test()\n\n    assert str(HealthCheck.too_slow) in str(exc.value)\n    assert re.search(r\"\\d+ invalid inputs\", str(exc.value))\n\n\ndef test_health_check_too_slow_with_overrun_examples():\n    @st.composite\n    def s(draw):\n        n = draw(st.integers())\n        if n > 0:\n            draw(st.binary(min_size=50))\n            assume(False)\n\n        time.sleep(0.2)\n\n    @given(s())\n    @settings(derandomize=True, max_examples=100)\n    def test(x):\n        pass\n\n    with buffer_size_limit(10), pytest.raises(FailedHealthCheck) as exc:\n        test()\n\n    assert str(HealthCheck.too_slow) in str(exc.value)\n    assert re.search(\n        r\"\\d+ inputs which exceeded the maximum allowed entropy\", str(exc.value)\n    )\n\n\n@pytest.mark.parametrize(\"n_large\", [1, 5, 8, 15])\ndef test_can_shrink_variable_draws(n_large):\n    target = 128 * n_large\n\n    @st.composite\n    def strategy(draw):\n        n = draw(st.integers(0, 15))\n        return [draw(st.integers(0, 255)) for _ in range(n)]\n\n    ints = minimal(strategy(), lambda ints: sum(ints) >= target)\n    # should look like [4, 255, 255, 255]\n    assert ints == [target % 255] + [255] * (len(ints) - 1)\n\n\ndef test_can_shrink_variable_string_draws():\n    @st.composite\n    def strategy(draw):\n        n = draw(st.integers(min_value=0, max_value=20))\n        return draw(st.text(st.characters(codec=\"ascii\"), min_size=n, max_size=n))\n\n    s = minimal(strategy(), lambda s: len(s) >= 10 and \"a\" in s)\n\n    # TODO_BETTER_SHRINK: this should be\n    # assert s == \"0\" * 9 + \"a\"\n    # but we first shrink to having a single a at the end of the string and then\n    # fail to apply our special case invalid logic when shrinking the min_size n,\n    # because that logic removes from the end of the string (which fails our\n    # precondition).\n    assert re.match(\"0+a\", s)\n\n\ndef test_variable_size_string_increasing():\n    # coverage test for min_size increasing during shrinking (because the test\n    # function inverts n).\n    # ...except this currently overruns instead and misses that check.\n    @st.composite\n    def strategy(draw):\n        n = 10 - draw(st.integers(0, 10))\n        return draw(st.text(st.characters(codec=\"ascii\"), min_size=n, max_size=n))\n\n    s = minimal(strategy(), lambda s: len(s) >= 5 and \"a\" in s)\n    # TODO_BETTER_SHRINK: this should be\n    # assert s == \"0000a\"\n    # but instead shrinks to 00000000a.\n    assert re.match(\"0+a\", s)\n\n\ndef test_run_nothing():\n    def f(data):\n        raise AssertionError\n\n    runner = ConjectureRunner(f, settings=settings(phases=()))\n    runner.run()\n    assert runner.call_count == 0\n\n\nclass Foo:\n    def __repr__(self):\n        return \"stuff\"\n\n\ndef test_debug_data(capsys):\n    choices = (0, 1, 2)\n\n    def f(data):\n        for choice in choices:\n            if data.draw(st.integers(0, 100)) != choice:\n                data.mark_invalid()\n            data.start_span(1)\n            data.stop_span()\n        data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(\n        f,\n        settings=settings(\n            max_examples=5000,\n            database=None,\n            suppress_health_check=list(HealthCheck),\n            verbosity=Verbosity.debug,\n        ),\n    )\n    runner.cached_test_function(choices)\n    runner.run()\n\n    out, _ = capsys.readouterr()\n    assert re.match(r\"\\d+ choices -> \", out)\n    assert \"INTERESTING\" in out\n\n\ndef test_can_write_bytes_towards_the_end():\n    buf = b\"\\1\\2\\3\"\n\n    def f(data):\n        if data.draw_boolean():\n            data.draw_bytes(5, 5)\n            data.draw_bytes(len(buf), len(buf), forced=buf)\n            assert data.choices[2] == buf\n\n    with buffer_size_limit(15):\n        ConjectureRunner(f).run()\n\n\ndef test_uniqueness_is_preserved_when_writing_at_beginning():\n    seen = set()\n\n    def f(data):\n        data.draw_bytes(1, 1, forced=bytes(1))\n        n = data.draw_integer(0, 2**3 - 1)\n        assert n not in seen\n        seen.add(n)\n\n    runner = ConjectureRunner(f, settings=settings(max_examples=50))\n    runner.run()\n    assert runner.valid_examples == len(seen)\n\n\n@pytest.mark.parametrize(\"skip_target\", [False, True])\n@pytest.mark.parametrize(\"initial_attempt\", [(127,), (128,)])\ndef test_clears_out_its_database_on_shrinking(\n    initial_attempt, skip_target, monkeypatch\n):\n    def generate_new_examples(self):\n        self.cached_test_function(initial_attempt)\n\n    monkeypatch.setattr(\n        ConjectureRunner, \"generate_new_examples\", generate_new_examples\n    )\n\n    key = b\"key\"\n    db = InMemoryExampleDatabase()\n\n    def f(data):\n        if data.draw_integer() >= 127:\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(\n        f,\n        settings=settings(database=db, max_examples=256),\n        database_key=key,\n        random=Random(0),\n    )\n\n    for n in range(256):\n        if n != 127 or not skip_target:\n            db.save(runner.secondary_key, choices_to_bytes([n]))\n    runner.run()\n    assert len(runner.interesting_examples) == 1\n    for b in db.fetch(runner.secondary_key):\n        assert choices_from_bytes(b)[0] >= 127\n    assert len(list(db.fetch(runner.database_key))) == 1\n\n\ndef test_shrinks_both_interesting_examples(monkeypatch):\n    def generate_new_examples(self):\n        self.cached_test_function((1,))\n\n    monkeypatch.setattr(\n        ConjectureRunner, \"generate_new_examples\", generate_new_examples\n    )\n\n    def f(data):\n        n = data.draw_integer(0, 2**8 - 1)\n        data.mark_interesting(interesting_origin(n & 1))\n\n    runner = ConjectureRunner(f)\n    runner.run()\n    assert runner.interesting_examples[interesting_origin(0)].choices == (0,)\n    assert runner.interesting_examples[interesting_origin(1)].choices == (1,)\n\n\ndef test_discarding(monkeypatch):\n    monkeypatch.setattr(Shrinker, \"shrink\", Shrinker.remove_discarded)\n    monkeypatch.setattr(\n        ConjectureRunner,\n        \"generate_new_examples\",\n        lambda runner: runner.cached_test_function((False, True) * 10),\n    )\n\n    @run_to_nodes\n    def nodes(data):\n        count = 0\n        while count < 10:\n            data.start_span(SOME_LABEL)\n            b = data.draw_boolean()\n            if b:\n                count += 1\n            data.stop_span(discard=not b)\n        data.mark_interesting(interesting_origin())\n\n    assert tuple(n.value for n in nodes) == (True,) * 10\n\n\ndef test_can_remove_discarded_data():\n    @shrinking_from((0,) * 10 + (11,))\n    def shrinker(data: ConjectureData):\n        while True:\n            data.start_span(SOME_LABEL)\n            b = data.draw_integer(0, 2**8 - 1)\n            data.stop_span(discard=(b == 0))\n            if b == 11:\n                break\n        data.mark_interesting(interesting_origin())\n\n    shrinker.remove_discarded()\n    assert shrinker.choices == (11,)\n\n\ndef test_discarding_iterates_to_fixed_point():\n    @shrinking_from(list(range(100, -1, -1)))\n    def shrinker(data: ConjectureData):\n        data.start_span(0)\n        data.draw_integer(0, 2**8 - 1)\n        data.stop_span(discard=True)\n        while data.draw_integer(0, 2**8 - 1):\n            pass\n        data.mark_interesting(interesting_origin())\n\n    shrinker.remove_discarded()\n    assert shrinker.choices == (1, 0)\n\n\ndef test_discarding_is_not_fooled_by_empty_discards():\n    @shrinking_from((1, 1))\n    def shrinker(data: ConjectureData):\n        data.draw_integer(0, 2**1 - 1)\n        data.start_span(0)\n        data.stop_span(discard=True)\n        data.draw_integer(0, 2**1 - 1)\n        data.mark_interesting(interesting_origin())\n\n    shrinker.remove_discarded()\n    assert shrinker.shrink_target.has_discards\n\n\ndef test_discarding_can_fail():\n    @shrinking_from((1,))\n    def shrinker(data: ConjectureData):\n        data.start_span(0)\n        data.draw_boolean()\n        data.stop_span(discard=True)\n        data.mark_interesting(interesting_origin())\n\n    shrinker.remove_discarded()\n    assert any(e.discarded and e.choice_count > 0 for e in shrinker.shrink_target.spans)\n\n\ndef test_shrinking_from_mostly_zero(monkeypatch):\n    monkeypatch.setattr(\n        ConjectureRunner,\n        \"generate_new_examples\",\n        lambda self: self.cached_test_function((0,) * 5 + (2,)),\n    )\n\n    @run_to_nodes\n    def nodes(data):\n        s = [data.draw_integer(0, 2**8 - 1) for _ in range(6)]\n        if any(s):\n            data.mark_interesting(interesting_origin())\n\n    assert tuple(n.value for n in nodes) == (0,) * 5 + (1,)\n\n\ndef test_handles_nesting_of_discard_correctly(monkeypatch):\n    monkeypatch.setattr(Shrinker, \"shrink\", Shrinker.remove_discarded)\n    monkeypatch.setattr(\n        ConjectureRunner,\n        \"generate_new_examples\",\n        lambda runner: runner.cached_test_function((False, False, True, True)),\n    )\n\n    @run_to_nodes\n    def nodes(data):\n        while True:\n            data.start_span(SOME_LABEL)\n            succeeded = data.draw_boolean()\n            data.start_span(SOME_LABEL)\n            data.draw_boolean()\n            data.stop_span(discard=not succeeded)\n            data.stop_span(discard=not succeeded)\n            if succeeded:\n                data.mark_interesting(interesting_origin())\n\n    assert tuple(n.value for n in nodes) == (True, True)\n\n\ndef test_database_clears_secondary_key():\n    key = b\"key\"\n    database = InMemoryExampleDatabase()\n\n    def f(data):\n        if data.draw_integer() == 10:\n            data.mark_interesting(interesting_origin())\n        else:\n            data.mark_invalid()\n\n    runner = ConjectureRunner(\n        f,\n        settings=settings(\n            max_examples=1, database=database, suppress_health_check=list(HealthCheck)\n        ),\n        database_key=key,\n    )\n\n    for i in range(10):\n        database.save(runner.secondary_key, choices_to_bytes([i]))\n\n    runner.cached_test_function((10,))\n    assert runner.interesting_examples\n\n    assert len(set(database.fetch(key))) == 1\n    assert len(set(database.fetch(runner.secondary_key))) == 10\n\n    runner.clear_secondary_key()\n\n    assert len(set(database.fetch(key))) == 1\n    assert len(set(database.fetch(runner.secondary_key))) == 0\n\n\ndef test_database_uses_values_from_secondary_key():\n    key = b\"key\"\n    database = InMemoryExampleDatabase()\n\n    def f(data):\n        if data.draw_integer() >= 5:\n            data.mark_interesting(interesting_origin())\n        else:\n            data.mark_invalid()\n\n    runner = ConjectureRunner(\n        f,\n        settings=settings(\n            max_examples=1, database=database, suppress_health_check=list(HealthCheck)\n        ),\n        database_key=key,\n    )\n    for i in range(10):\n        database.save(runner.secondary_key, choices_to_bytes([i]))\n\n    runner.cached_test_function((10,))\n    assert runner.interesting_examples\n    assert len(set(database.fetch(key))) == 1\n    assert len(set(database.fetch(runner.secondary_key))) == 10\n\n    runner.clear_secondary_key()\n\n    assert len(set(database.fetch(key))) == 1\n    assert {\n        choices_from_bytes(b)[0] for b in database.fetch(runner.secondary_key)\n    } == set(range(6, 11))\n\n    (v,) = runner.interesting_examples.values()\n    assert v.choices == (5,)\n\n\ndef test_exit_because_max_iterations():\n    def f(data):\n        data.draw_integer(0, 2**64 - 1)\n        data.mark_invalid()\n\n    runner = ConjectureRunner(\n        f,\n        settings=settings(\n            max_examples=1, database=None, suppress_health_check=list(HealthCheck)\n        ),\n    )\n\n    runner.run()\n\n    assert runner.call_count <= 1000\n    assert runner.exit_reason == ExitReason.max_iterations\n\n\ndef test_max_iterations_with_all_invalid():\n    # With assume(False) on every example, we stop after INVALID_THRESHOLD_BASE + 1\n    # invalid attempts (the check is > not >=).\n    def f(data):\n        data.draw_integer(0, 2**64 - 1)\n        data.mark_invalid()\n\n    runner = ConjectureRunner(\n        f,\n        settings=settings(\n            max_examples=10_000, database=None, suppress_health_check=list(HealthCheck)\n        ),\n    )\n    runner.run()\n\n    assert runner.call_count == INVALID_THRESHOLD_BASE + 1\n    assert runner.exit_reason == ExitReason.max_iterations\n\n\n@pytest.mark.parametrize(\"n_valid\", [1, 2, 5])\ndef test_max_iterations_with_some_valid(n_valid):\n    valid_count = 0\n\n    def f(data):\n        nonlocal valid_count\n        data.draw_integer(0, 2**64 - 1)\n        if valid_count < n_valid:\n            valid_count += 1\n        else:\n            data.mark_invalid()\n\n    runner = ConjectureRunner(\n        f,\n        settings=settings(\n            max_examples=10_000, database=None, suppress_health_check=list(HealthCheck)\n        ),\n    )\n    runner.run()\n\n    assert (\n        runner.call_count\n        == n_valid + INVALID_THRESHOLD_BASE + n_valid * INVALID_PER_VALID + 1\n    )\n    assert runner.exit_reason == ExitReason.max_iterations\n\n\ndef test_exit_because_shrink_phase_timeout(monkeypatch):\n    val = 0\n\n    def fast_time():\n        nonlocal val\n        val += 1000\n        return val\n\n    def f(data):\n        if data.draw_integer(0, 2**64 - 1) > 2**33:\n            data.mark_interesting(interesting_origin())\n\n    monkeypatch.setattr(time, \"perf_counter\", fast_time)\n    runner = ConjectureRunner(f, settings=settings(database=None, max_examples=100_000))\n    runner.run()\n    assert runner.exit_reason == ExitReason.very_slow_shrinking\n    assert runner.statistics[\"stopped-because\"] == \"shrinking was very slow\"\n\n\ndef test_dependent_block_pairs_can_lower_to_zero():\n    @shrinking_from((True, 1))\n    def shrinker(data: ConjectureData):\n        if data.draw_boolean():\n            n = data.draw_integer(0, 2**16 - 1)\n        else:\n            n = data.draw_integer(0, 2**8 - 1)\n\n        if n == 1:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.minimize_individual_choices)])\n    assert shrinker.choices == (False, 1)\n\n\ndef test_handle_size_too_large_during_dependent_lowering():\n    @shrinking_from((True, 255, 0))\n    def shrinker(data: ConjectureData):\n        if data.draw_boolean():\n            data.draw_integer(0, 2**16 - 1)\n            data.mark_interesting(interesting_origin())\n        else:\n            data.draw_integer(0, 2**8 - 1)\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.minimize_individual_choices)])\n\n\ndef test_block_may_grow_during_lexical_shrinking():\n    @shrinking_from((2, 1, 1))\n    def shrinker(data: ConjectureData):\n        n = data.draw_integer(0, 2**8 - 1)\n        if n == 2:\n            data.draw_integer(0, 2**8 - 1)\n            data.draw_integer(0, 2**8 - 1)\n        else:\n            data.draw_integer(0, 2**16 - 1)\n        data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.minimize_individual_choices)])\n    assert shrinker.choices == (0, 0)\n\n\ndef test_lower_common_node_offset_does_nothing_when_changed_blocks_are_zero():\n    @shrinking_from((True, False, True, False))\n    def shrinker(data: ConjectureData):\n        data.draw_boolean()\n        data.draw_boolean()\n        data.draw_boolean()\n        data.draw_boolean()\n        data.mark_interesting(interesting_origin())\n\n    shrinker.mark_changed(1)\n    shrinker.mark_changed(3)\n    shrinker.lower_common_node_offset()\n    assert shrinker.choices == (True, False, True, False)\n\n\ndef test_lower_common_node_offset_ignores_zeros():\n    @shrinking_from((2, 2, 0))\n    def shrinker(data: ConjectureData):\n        n = data.draw_integer(0, 2**8 - 1)\n        data.draw_integer(0, 2**8 - 1)\n        data.draw_integer(0, 2**8 - 1)\n        if n > 0:\n            data.mark_interesting(interesting_origin())\n\n    for i in range(3):\n        shrinker.mark_changed(i)\n    shrinker.lower_common_node_offset()\n    assert shrinker.choices == (1, 1, 0)\n\n\ndef test_cached_test_function_returns_right_value():\n    count = 0\n\n    def tf(data):\n        nonlocal count\n        count += 1\n        data.draw_integer(0, 3)\n        data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(tf, settings=runner_settings, random=Random(0))\n    for _ in range(2):\n        for choices in ((0,), (1,)):\n            d = runner.cached_test_function(choices)\n            assert d.status == Status.INTERESTING\n            assert d.choices == choices\n    assert count == 2\n\n\ndef test_cached_test_function_does_not_reinvoke_on_prefix():\n    call_count = 0\n\n    def test_function(data):\n        nonlocal call_count\n        call_count += 1\n        data.draw_integer(0, 2**8 - 1)\n        data.draw_bytes(1, 1, forced=bytes([7]))\n        data.draw_integer(0, 2**8 - 1)\n\n    runner = ConjectureRunner(test_function, settings=runner_settings, random=Random(0))\n\n    data = runner.cached_test_function((0, b\"\\0\", 0))\n    assert data.status == Status.VALID\n    for n in [2, 1, 0]:\n        d = runner.cached_test_function(data.choices[:n])\n        assert d is Overrun\n    assert call_count == 1\n\n\ndef test_will_evict_entries_from_the_cache(monkeypatch):\n    monkeypatch.setattr(engine_module, \"CACHE_SIZE\", 5)\n    count = 0\n\n    def tf(data):\n        nonlocal count\n        data.draw_integer(0, 2**8 - 1)\n        count += 1\n\n    runner = ConjectureRunner(tf, settings=runner_settings)\n\n    for _ in range(3):\n        for n in range(10):\n            runner.cached_test_function((n,))\n\n    # Because we exceeded the cache size, our previous\n    # calls will have been evicted, so each call to\n    # cached_test_function will have to reexecute.\n    assert count == 30\n\n\ndef test_branch_ending_in_write():\n    seen = set()\n\n    def tf(data):\n        count = 0\n        while data.draw_boolean():\n            count += 1\n\n        if count > 1:\n            data.draw_boolean(forced=False)\n\n        assert data.nodes not in seen\n        seen.add(data.nodes)\n\n    # max_examples high enough that our for loop below won't hit it\n    runner = ConjectureRunner(\n        tf, settings=settings(runner_settings, max_examples=200), random=Random(0)\n    )\n\n    for _ in range(100):\n        prefix = runner.generate_novel_prefix()\n        attempt = prefix + (False, False)\n        data = runner.cached_test_function(attempt)\n        assert data.status is Status.VALID\n        assert startswith(attempt, data.choices)\n\n\ndef test_exhaust_space():\n    runner = ConjectureRunner(\n        lambda data: data.draw_boolean(), settings=runner_settings, random=Random(0)\n    )\n    runner.run()\n    assert runner.tree.is_exhausted\n    assert runner.valid_examples == 2\n\n\nSMALL_COUNT_SETTINGS = settings(runner_settings, max_examples=500)\n\n\ndef test_discards_kill_branches():\n    seen = set()\n\n    def test(data: ConjectureData):\n        data.start_span(1)\n        n1 = data.draw_integer(0, 9)\n        data.stop_span(discard=n1 > 0)\n        n2 = data.draw_integer(0, 9)\n        n3 = data.draw_integer(0, 9)\n\n        assert (n1, n2, n3) not in seen\n        seen.add((n1, n2, n3))\n\n    runner = ConjectureRunner(test, settings=SMALL_COUNT_SETTINGS)\n    runner.run()\n    assert runner.exit_reason is ExitReason.finished\n    # 10 to explore the initial n1 = 0-9 statespace, then 100 to explore just\n    # the (0, n1, n2) statespace, because every prefix other than 0 is a discard\n    # and is not explored. Subtract the overlap, which occurs once at n1 = 0.\n    assert len(seen) == 100 + 10 - 1\n\n\n@pytest.mark.parametrize(\"n\", range(1, 32))\ndef test_number_of_examples_in_integer_range_is_bounded(n):\n    def test(data):\n        assert runner.call_count <= 2 * n\n        data.draw_integer(0, n)\n\n    runner = ConjectureRunner(test, settings=SMALL_COUNT_SETTINGS, random=Random(0))\n    runner.run()\n\n\ndef test_prefix_cannot_exceed_buffer_size(monkeypatch):\n    buffer_size = 10\n\n    with buffer_size_limit(buffer_size):\n\n        def test(data):\n            while data.draw_boolean():\n                assert data.length <= buffer_size\n            assert data.length <= buffer_size\n\n        runner = ConjectureRunner(test, settings=SMALL_COUNT_SETTINGS, random=Random(0))\n        runner.run()\n        assert runner.valid_examples == buffer_size\n\n\ndef test_does_not_shrink_multiple_bugs_when_told_not_to():\n    def test(data):\n        m = data.draw_integer(0, 2**8 - 1)\n        n = data.draw_integer(0, 2**8 - 1)\n\n        if m > 0:\n            data.mark_interesting(interesting_origin(1))\n        if n > 5:\n            data.mark_interesting(interesting_origin(2))\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(runner_settings, report_multiple_bugs=False),\n        random=Random(0),\n    )\n    runner.cached_test_function((255, 255))\n    runner.shrink_interesting_examples()\n\n    results = {d.choices for d in runner.interesting_examples.values()}\n    assert len(results.intersection({(0, 1), (1, 0)})) == 1\n\n\ndef test_does_not_keep_generating_when_multiple_bugs():\n    def test(data):\n        if data.draw_integer(0, 2**20 - 1) > 0:\n            data.draw_integer(0, 2**20 - 1)\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(\n            runner_settings, report_multiple_bugs=False, phases=[Phase.generate]\n        ),\n        random=Random(0),\n    )\n    runner.run()\n\n    assert runner.call_count == 2\n\n\ndef test_shrink_after_max_examples():\n    \"\"\"If we find a bug, keep looking for more, and then hit the valid-example\n    limit, we should still proceed to shrinking.\n    \"\"\"\n    max_examples = 100\n    fail_at = max_examples - 5\n\n    seen = set()\n    bad = set()\n    post_failure_calls = [0]\n\n    def test(data):\n        if bad:\n            post_failure_calls[0] += 1\n\n        value = data.draw_integer(0, 2**8 - 1)\n\n        if value in seen and value not in bad:\n            return\n\n        seen.add(value)\n        if len(seen) == fail_at:\n            bad.add(value)\n\n        if value in bad:\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(\n            runner_settings,\n            max_examples=max_examples,\n            phases=[Phase.generate, Phase.shrink],\n            report_multiple_bugs=True,\n        ),\n        # This shouldn't need to be deterministic, but it makes things much easier\n        # to debug if anything goes wrong.\n        random=Random(0),\n    )\n    runner.shrink_interesting_examples = Mock(name=\"shrink_interesting_examples\")\n    runner.run()\n\n    # First, verify our test assumptions: we found a bug, kept running, and\n    # then hit max-examples.\n    assert runner.interesting_examples\n    assert post_failure_calls[0] >= (max_examples - fail_at)\n    assert runner.call_count >= max_examples\n    assert runner.valid_examples == max_examples\n\n    # Now check that we still performed shrinking, even after hitting the\n    # example limit.\n    assert runner.shrink_interesting_examples.call_count == 1\n    assert runner.exit_reason == ExitReason.finished\n\n\ndef test_shrink_after_max_iterations():\n    \"\"\"If we find a bug, keep looking for more, and then hit the invalid\n    examples limit, we should still proceed to shrinking.\n    \"\"\"\n    max_examples = 10\n    max_iterations = INVALID_THRESHOLD_BASE\n    fail_at = max_iterations - 5\n\n    invalid = set()\n    bad = set()\n    post_failure_calls = [0]\n\n    def test(data):\n        if bad:\n            post_failure_calls[0] += 1\n\n        value = data.draw_integer(0, 2**16 - 1)\n\n        if value in invalid:\n            data.mark_invalid()\n\n        if value in bad or (not bad and len(invalid) == fail_at):\n            bad.add(value)\n            data.mark_interesting(interesting_origin())\n\n        invalid.add(value)\n        data.mark_invalid()\n\n    # This shouldn't need to be deterministic, but it makes things much easier\n    # to debug if anything goes wrong.\n    runner = ConjectureRunner(\n        test,\n        settings=settings(\n            runner_settings,\n            max_examples=max_examples,\n            phases=[Phase.generate, Phase.shrink],\n            report_multiple_bugs=True,\n        ),\n        random=Random(0),\n    )\n    runner.shrink_interesting_examples = Mock(name=\"shrink_interesting_examples\")\n    runner.run()\n\n    # First, verify our test assumptions: we found a bug, kept running, and\n    # then hit the test call limit.\n    assert runner.interesting_examples\n    assert post_failure_calls[0] >= (max_iterations - fail_at) - 1\n    assert runner.call_count >= max_iterations\n    assert runner.valid_examples == 0\n\n    # Now check that we still performed shrinking, even after hitting the\n    # test call limit.\n    assert runner.shrink_interesting_examples.call_count == 1\n    assert runner.exit_reason == ExitReason.finished\n\n\ndef test_populates_the_pareto_front():\n    def test(data):\n        data.target_observations[\"\"] = data.draw_integer(0, 2**4 - 1)\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(\n            max_examples=5000,\n            database=InMemoryExampleDatabase(),\n            suppress_health_check=list(HealthCheck),\n        ),\n        database_key=b\"stuff\",\n        random=Random(0),\n    )\n    runner.run()\n\n    assert len(runner.pareto_front) == 2**4\n\n\ndef test_pareto_front_contains_smallest_valid():\n    def test(data):\n        data.target_observations[\"\"] = 1\n        data.draw_integer(0, 2**4 - 1)\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(\n            max_examples=5000,\n            database=InMemoryExampleDatabase(),\n            suppress_health_check=list(HealthCheck),\n        ),\n        database_key=b\"stuff\",\n        random=Random(0),\n    )\n    runner.run()\n\n    assert len(runner.pareto_front) == 1\n\n\ndef test_replaces_all_dominated():\n    def test(data):\n        data.target_observations[\"m\"] = 3 - data.draw_integer(0, 3)\n        data.target_observations[\"n\"] = 3 - data.draw_integer(0, 3)\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(runner_settings, database=InMemoryExampleDatabase()),\n        database_key=b\"stuff\",\n    )\n\n    d1 = runner.cached_test_function((0, 1)).as_result()\n    d2 = runner.cached_test_function((1, 0)).as_result()\n\n    assert len(runner.pareto_front) == 2\n\n    assert runner.pareto_front[0] == d1\n    assert runner.pareto_front[1] == d2\n\n    d3 = runner.cached_test_function((0, 0)).as_result()\n    assert len(runner.pareto_front) == 1\n\n    assert runner.pareto_front[0] == d3\n\n\ndef test_does_not_duplicate_elements():\n    def test(data):\n        data.target_observations[\"m\"] = data.draw_integer(0, 2**8 - 1)\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(runner_settings, database=InMemoryExampleDatabase()),\n        database_key=b\"stuff\",\n    )\n    d1 = runner.cached_test_function((1,)).as_result()\n\n    assert len(runner.pareto_front) == 1\n    # This can happen in practice if we e.g. reexecute a test because it has\n    # expired from the cache. It's easier just to test it directly though\n    # rather than simulate the failure mode.\n    assert runner.pareto_front.add(d1)\n    assert len(runner.pareto_front) == 1\n\n\ndef test_includes_right_hand_side_targets_in_dominance():\n    def test(data):\n        if data.draw_integer(0, 2**8 - 1):\n            data.target_observations[\"\"] = 10\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(runner_settings, database=InMemoryExampleDatabase()),\n        database_key=b\"stuff\",\n    )\n\n    d1 = runner.cached_test_function((0,)).as_result()\n    d2 = runner.cached_test_function((1,)).as_result()\n\n    assert dominance(d1, d2) == DominanceRelation.NO_DOMINANCE\n\n\ndef test_smaller_interesting_dominates_larger_valid():\n    def test(data):\n        if data.draw_integer(0, 2**8 - 1) == 0:\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(runner_settings, database=InMemoryExampleDatabase()),\n        database_key=b\"stuff\",\n    )\n\n    d1 = runner.cached_test_function((0,)).as_result()\n    d2 = runner.cached_test_function((1,)).as_result()\n    assert dominance(d1, d2) == DominanceRelation.LEFT_DOMINATES\n\n\ndef test_runs_full_set_of_examples():\n    def test(data):\n        data.draw_integer(0, 2**64 - 1)\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(runner_settings, database=InMemoryExampleDatabase()),\n        database_key=b\"stuff\",\n    )\n\n    runner.run()\n    assert runner.valid_examples == runner_settings.max_examples\n\n\ndef test_runs_optimisation_even_if_not_generating():\n    def test(data):\n        data.target_observations[\"n\"] = data.draw_integer(0, 2**16 - 1)\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(runner_settings, phases=[Phase.target]),\n        random=Random(0),\n    )\n    runner.cached_test_function((0,))\n    runner.run()\n\n    assert runner.best_observed_targets[\"n\"] == (2**16) - 1\n\n\ndef test_runs_optimisation_once_when_generating():\n    def test(data):\n        data.target_observations[\"n\"] = data.draw_integer(0, 2**16 - 1)\n\n    runner = ConjectureRunner(\n        test, settings=settings(runner_settings, max_examples=100), random=Random(0)\n    )\n\n    runner.optimise_targets = Mock(name=\"optimise_targets\")\n    try:\n        runner.generate_new_examples()\n    except RunIsComplete:\n        pass\n    assert runner.optimise_targets.call_count == 1\n\n\ndef test_does_not_run_optimisation_when_max_examples_is_small():\n    def test(data):\n        data.target_observations[\"n\"] = data.draw_integer(0, 2**16 - 1)\n\n    runner = ConjectureRunner(\n        test, settings=settings(runner_settings, max_examples=10), random=Random(0)\n    )\n\n    runner.optimise_targets = Mock(name=\"optimise_targets\")\n    try:\n        runner.generate_new_examples()\n    except RunIsComplete:\n        pass\n    assert runner.optimise_targets.call_count == 0\n\n\ndef test_does_not_cache_extended_prefix():\n    def test(data):\n        data.draw_integer()\n        data.draw_integer()\n\n    runner = ConjectureRunner(test, settings=runner_settings, random=Random(0))\n\n    d1 = runner.cached_test_function((0,), extend=10)\n    assert runner.call_count == 1\n    d2 = runner.cached_test_function((0,), extend=10)\n    assert runner.call_count == 2\n    assert d1.status is d2.status is Status.VALID\n\n\ndef test_does_cache_if_extend_is_not_used():\n    calls = 0\n\n    def test(data):\n        nonlocal calls\n        calls += 1\n        data.draw_bytes(1, 1)\n\n    runner = ConjectureRunner(test, settings=runner_settings, random=Random(0))\n\n    d1 = runner.cached_test_function((b\"\\0\"), extend=8)\n    d2 = runner.cached_test_function((b\"\\0\"), extend=8)\n    assert d1.status == d2.status == Status.VALID\n    assert d1.choices == d2.choices\n    assert calls == 1\n\n\ndef test_does_result_for_reuse():\n    calls = 0\n\n    def test(data):\n        nonlocal calls\n        calls += 1\n        data.draw_bytes(1, 1)\n\n    runner = ConjectureRunner(test, settings=runner_settings, random=Random(0))\n\n    d1 = runner.cached_test_function((b\"\\0\"), extend=8)\n    d2 = runner.cached_test_function(d1.choices)\n    assert d1.status == d2.status == Status.VALID\n    assert d1.nodes == d2.nodes\n    assert calls == 1\n\n\ndef test_does_not_use_cached_overrun_if_extending():\n    def test(data):\n        data.draw_integer()\n        data.draw_integer()\n\n    runner = ConjectureRunner(test, settings=runner_settings, random=Random(0))\n\n    data = runner.cached_test_function((1,))\n    assert data.status == Status.OVERRUN\n    assert runner.call_count == 1\n\n    # the choice sequence of (1,) maps to an overrun in the cache, but we\n    # do not want to use this cache entry if we're extending.\n    data = runner.cached_test_function((1,), extend=1)\n    assert data.status == Status.VALID\n    assert runner.call_count == 2\n\n\ndef test_uses_cached_overrun_if_not_extending():\n    def test(data):\n        data.draw_integer()\n        data.draw_integer()\n\n    runner = ConjectureRunner(test, settings=runner_settings, random=Random(0))\n\n    data = runner.cached_test_function((1,), extend=0)\n    assert data.status is Status.OVERRUN\n    assert runner.call_count == 1\n\n    data = runner.cached_test_function((1,), extend=0)\n    assert data.status is Status.OVERRUN\n    assert runner.call_count == 1\n\n\ndef test_can_be_set_to_ignore_limits():\n    def test(data):\n        data.draw_integer(0, 2**8 - 1)\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(runner_settings, max_examples=1),\n        ignore_limits=True,\n        random=Random(0),\n    )\n    for c in range(256):\n        runner.cached_test_function((c,))\n\n    assert runner.tree.is_exhausted\n\n\ndef test_too_slow_report():\n    state = HealthCheckState()\n    assert state.timing_report() == \"\"  # no draws recorded -> no report\n    state.draw_times = {\n        \"generate:a\": [2.0, 0.356789, 0.0],\n        \"generate:b\": [0.1111111, 0.0, 0.002345678, 0.05, 0.123456, 0.1, 0.1, 0.1],\n        \"generate:c\": [0.03, 0.05, 0.2],\n        \"generate:d\": [0.04],\n        \"generate:e\": [0.05, 0.01],\n        \"generate:f\": [0.06],\n        \"generate:g\": [0.07],\n        \"generate:h\": [0.08],\n        \"generate:i\": [0.09, 0.00001],\n    }\n    expected = \"\"\"\n      count | fraction |    slowest draws (seconds)\n  a |    3  |     65%  |      --      --      --   0.357,  2.000\n  b |    8  |     16%  |   0.100,  0.100,  0.100,  0.111,  0.123\n  c |    3  |      8%  |      --      --   0.030,  0.050,  0.200\n  i |    2  |      2%  |      --      --      --      --   0.090\n  h |    1  |      2%  |      --      --      --      --   0.080\n  (skipped 4 rows of fast draws)\"\"\"\n    got = state.timing_report()\n    print(got)\n    assert expected == got\n\n\ndef _draw(cd, node):\n    return getattr(cd, f\"draw_{node.type}\")(**node.constraints)\n\n\n@given(nodes(was_forced=False))\ndef test_overruns_with_extend_are_not_cached(node):\n    assume(compute_max_children(node.type, node.constraints) > 100)\n\n    def test(cd):\n        _draw(cd, node)\n        _draw(cd, node)\n\n    runner = ConjectureRunner(test)\n    assert runner.call_count == 0\n\n    data = runner.cached_test_function([node.value])\n    assert runner.call_count == 1\n    assert data.status is Status.OVERRUN\n\n    # cache hit\n    data = runner.cached_test_function([node.value])\n    assert runner.call_count == 1\n    assert data.status is Status.OVERRUN\n\n    # cache miss\n    data = runner.cached_test_function([node.value], extend=\"full\")\n    assert runner.call_count == 2\n    assert data.status is Status.VALID\n\n\ndef test_simulate_to_evicted_data(monkeypatch):\n    # test that we do not rely on the false invariant that correctly simulating\n    # a data to a result means we have that result in the cache, due to e.g.\n    # cache evictions (but also potentially other trickery).\n    monkeypatch.setattr(engine_module, \"CACHE_SIZE\", 1)\n\n    def test(data):\n        data.draw_integer()\n\n    runner = ConjectureRunner(test)\n    runner.cached_test_function([0])\n    # cache size is 1 so this evicts [0]\n    runner.cached_test_function([1])\n    assert runner.call_count == 2\n\n    # we dont throw PreviouslyUnseenBehavior when simulating, but the result\n    # was evicted to the cache so we will still call through to the test function.\n    runner.tree.simulate_test_function(ConjectureData.for_choices([0]))\n    runner.cached_test_function([0])\n    assert runner.call_count == 3\n\n\n@pytest.mark.parametrize(\n    \"strategy, condition\",\n    [\n        (st.lists(st.integers(), min_size=5), lambda v: True),\n        (st.lists(st.text(), min_size=2, unique=True), lambda v: True),\n        (\n            st.sampled_from(\n                enum.Flag(\"LargeFlag\", {f\"bit{i}\": enum.auto() for i in range(64)})\n            ),\n            lambda f: bit_count(f.value) > 1,\n        ),\n    ],\n)\ndef test_mildly_complicated_strategies(strategy, condition):\n    # There are some code paths in engine.py and shrinker.py that are easily\n    # covered by shrinking any mildly compliated strategy and aren't worth\n    # testing explicitly for. This covers those.\n    minimal(strategy, condition)\n\n\ndef test_does_not_shrink_if_replaying_from_database():\n    db = InMemoryExampleDatabase()\n    key = b\"foo\"\n\n    def f(data):\n        if data.draw_integer(0, 255) == 123:\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(f, settings=settings(database=db), database_key=key)\n    choices = (123,)\n    runner.save_choices(choices)\n    runner.shrink_interesting_examples = None\n    runner.run()\n    (last_data,) = runner.interesting_examples.values()\n    assert last_data.choices == choices\n\n\ndef test_does_shrink_if_replaying_inexact_from_database():\n    db = InMemoryExampleDatabase()\n    key = b\"foo\"\n\n    def f(data):\n        data.draw_integer(0, 255)\n        data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(f, settings=settings(database=db), database_key=key)\n    runner.save_choices((123, 2))\n    runner.run()\n    (last_data,) = runner.interesting_examples.values()\n    assert last_data.choices == (0,)\n\n\ndef test_stops_if_hits_interesting_early_and_only_want_one_bug():\n    db = InMemoryExampleDatabase()\n    key = b\"foo\"\n\n    def f(data):\n        data.draw_integer(0, 255)\n        data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(\n        f, settings=settings(database=db, report_multiple_bugs=False), database_key=key\n    )\n    for i in range(256):\n        runner.save_choices([i])\n    runner.run()\n    assert runner.call_count == 1\n\n\ndef test_skips_secondary_if_interesting_is_found():\n    db = InMemoryExampleDatabase()\n    key = b\"foo\"\n\n    def f(data):\n        data.draw_integer(0, 255)\n        data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(\n        f,\n        settings=settings(max_examples=1000, database=db, report_multiple_bugs=True),\n        database_key=key,\n    )\n    for i in range(256):\n        db.save(\n            runner.database_key if i < 10 else runner.secondary_key,\n            choices_to_bytes([i]),\n        )\n    runner.reuse_existing_examples()\n    assert runner.call_count == 10\n\n\n@pytest.mark.parametrize(\"key_name\", [\"database_key\", \"secondary_key\"])\ndef test_discards_invalid_db_entries(key_name):\n    def test(data):\n        data.draw_integer()\n        data.mark_interesting(interesting_origin())\n\n    db = InMemoryExampleDatabase()\n    runner = ConjectureRunner(\n        test,\n        # stop IN_COVERAGE_TESTS from overriding max_examples, which changes\n        # db behavior\n        settings=settings(database=db, max_examples=100),\n        database_key=b\"stuff\",\n        random=Random(0),\n    )\n    key = getattr(runner, key_name)\n    valid = choices_to_bytes([1])\n    db.save(key, valid)\n    for n in range(5):\n        b = bytes([255, n])\n        # save a bunch of invalid entries under the database key\n        assert choices_from_bytes(b) is None\n        db.save(key, b)\n\n    assert len(set(db.fetch(key))) == 6\n    # this will clear out the invalid entries and use the valid one\n    runner.reuse_existing_examples()\n    runner.clear_secondary_key()\n\n    assert set(db.fetch(runner.database_key)) == {valid}\n    assert runner.call_count == 1\n\n\ndef test_discards_invalid_db_entries_pareto():\n    def test(data):\n        data.draw_integer()\n        data.mark_interesting(interesting_origin())\n\n    db = InMemoryExampleDatabase()\n    runner = ConjectureRunner(\n        test,\n        settings=settings(database=db, max_examples=100),\n        database_key=b\"stuff\",\n        random=Random(0),\n    )\n    for n in range(5):\n        b = bytes([255, n])\n        assert choices_from_bytes(b) is None\n        db.save(runner.pareto_key, b)\n\n    assert len(set(db.fetch(runner.pareto_key))) == 5\n    runner.reuse_existing_examples()\n\n    assert not set(db.fetch(runner.database_key))\n    assert not set(db.fetch(runner.pareto_key))\n    assert runner.call_count == 0\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_float_encoding.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nimport sys\n\nimport pytest\n\nfrom hypothesis import HealthCheck, assume, example, given, settings, strategies as st\nfrom hypothesis.internal.compat import ceil, extract_bits, floor\nfrom hypothesis.internal.conjecture import floats as flt\nfrom hypothesis.internal.conjecture.engine import ConjectureRunner\nfrom hypothesis.internal.floats import SIGNALING_NAN, float_to_int\n\nfrom tests.conjecture.common import interesting_origin\n\nEXPONENTS = list(range(flt.MAX_EXPONENT + 1))\nassert len(EXPONENTS) == 2**11\n\n\ndef assert_reordered_exponents(res):\n    res = list(res)\n    assert len(res) == len(EXPONENTS)\n    for x in res:\n        assert res.count(x) == 1\n        assert 0 <= x <= flt.MAX_EXPONENT\n\n\ndef test_encode_permutes_elements():\n    assert_reordered_exponents(map(flt.encode_exponent, EXPONENTS))\n\n\ndef test_decode_permutes_elements():\n    assert_reordered_exponents(map(flt.decode_exponent, EXPONENTS))\n\n\ndef test_decode_encode():\n    for e in EXPONENTS:\n        assert flt.decode_exponent(flt.encode_exponent(e)) == e\n\n\ndef test_encode_decode():\n    for e in EXPONENTS:\n        assert flt.decode_exponent(flt.encode_exponent(e)) == e\n\n\n@given(st.data())\ndef test_double_reverse_bounded(data):\n    n = data.draw(st.integers(1, 64))\n    i = data.draw(st.integers(0, 2**n - 1))\n    j = flt.reverse_bits(i, n)\n    assert flt.reverse_bits(j, n) == i\n\n\n@given(st.integers(0, 2**64 - 1))\ndef test_double_reverse(i):\n    j = flt.reverse64(i)\n    assert flt.reverse64(j) == i\n\n\n@example(0.0)\n@example(2.5)\n@example(8.000000000000007)\n@example(3.0)\n@example(2.0)\n@example(1.9999999999999998)\n@example(1.0)\n@given(st.floats(min_value=0.0))\ndef test_floats_round_trip(f):\n    i = flt.float_to_lex(f)\n    g = flt.lex_to_float(i)\n\n    assert float_to_int(f) == float_to_int(g)\n\n\n@settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.filter_too_much])\n@example(1, 0.5)\n@given(st.integers(1, 2**53), st.floats(0, 1).filter(lambda x: x not in (0, 1)))\ndef test_floats_order_worse_than_their_integral_part(n, g):\n    f = n + g\n    assume(int(f) != f)\n    assume(int(f) != 0)\n    i = flt.float_to_lex(f)\n    if f < 0:\n        g = ceil(f)\n    else:\n        g = floor(f)\n\n    assert flt.float_to_lex(float(g)) < i\n\n\nintegral_floats = st.floats(allow_infinity=False, allow_nan=False, min_value=0.0).map(\n    lambda x: abs(float(int(x)))\n)\n\n\n@given(integral_floats, integral_floats)\ndef test_integral_floats_order_as_integers(x, y):\n    assume(x != y)\n    x, y = sorted((x, y))\n    assert flt.float_to_lex(x) < flt.float_to_lex(y)\n\n\n@given(st.floats(0, 1))\ndef test_fractional_floats_are_worse_than_one(f):\n    assume(0 < f < 1)\n    assert flt.float_to_lex(f) > flt.float_to_lex(1)\n\n\ndef test_reverse_bits_table_reverses_bits():\n    for i, b in enumerate(flt.REVERSE_BITS_TABLE):\n        assert extract_bits(i, width=8) == list(reversed(extract_bits(b, width=8)))\n\n\ndef test_reverse_bits_table_has_right_elements():\n    assert sorted(flt.REVERSE_BITS_TABLE) == list(range(256))\n\n\ndef float_runner(start, condition, *, constraints=None):\n    constraints = {} if constraints is None else constraints\n\n    def test_function(data):\n        f = data.draw_float(**constraints)\n        if condition(f):\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(test_function)\n    runner.cached_test_function((float(start),))\n    assert runner.interesting_examples\n    return runner\n\n\ndef minimal_from(start, condition, *, constraints=None):\n    runner = float_runner(start, condition, constraints=constraints)\n    runner.shrink_interesting_examples()\n    (v,) = runner.interesting_examples.values()\n    f = v.choices[0]\n    assert condition(f)\n    return f\n\n\nINTERESTING_FLOATS = [0.0, 1.0, 2.0, sys.float_info.max, float(\"inf\"), float(\"nan\")]\n\n\n@pytest.mark.parametrize(\n    (\"start\", \"end\"),\n    [\n        (a, b)\n        for a in INTERESTING_FLOATS\n        for b in INTERESTING_FLOATS\n        if flt.float_to_lex(a) > flt.float_to_lex(b)\n    ],\n)\ndef test_can_shrink_downwards(start, end):\n    assert minimal_from(start, lambda x: not (x < end)) == end\n\n\n@pytest.mark.parametrize(\n    \"f\", [1, 2, 4, 8, 10, 16, 32, 64, 100, 128, 256, 500, 512, 1000, 1024]\n)\n@pytest.mark.parametrize(\"mul\", [1.1, 1.5, 9.99, 10])\ndef test_shrinks_downwards_to_integers(f, mul):\n    g = minimal_from(f * mul, lambda x: x >= f)\n    assert g == f\n\n\ndef test_shrink_to_integer_upper_bound():\n    assert minimal_from(1.1, lambda x: 1 < x <= 2) == 2\n\n\ndef test_shrink_up_to_one():\n    assert minimal_from(0.5, lambda x: 0.5 <= x <= 1.5) == 1\n\n\ndef test_shrink_down_to_half():\n    assert minimal_from(0.75, lambda x: 0 < x < 1) == 0.5\n\n\ndef test_shrink_fractional_part():\n    assert minimal_from(2.5, lambda x: divmod(x, 1)[1] == 0.5) == 1.5\n\n\ndef test_does_not_shrink_across_one():\n    # This is something of an odd special case. Because of our encoding we\n    # prefer all numbers >= 1 to all numbers in 0 < x < 1. For the most part\n    # this is the correct thing to do, but there are some low negative exponent\n    # cases where we get odd behaviour like this.\n\n    # This test primarily exists to validate that we don't try to subtract one\n    # from the starting point and trigger an internal exception.\n    assert minimal_from(1.1, lambda x: x == 1.1 or 0 < x < 1) == 1.1\n\n\ndef test_reject_out_of_bounds_floats_while_shrinking():\n    # coverage test for rejecting out of bounds floats while shrinking\n    constraints = {\"min_value\": 103.0}\n    g = minimal_from(103.1, lambda x: x >= 100, constraints=constraints)\n    assert g == 103.0\n\n\n@pytest.mark.parametrize(\"nan\", [-math.nan, SIGNALING_NAN, -SIGNALING_NAN])\ndef test_shrinks_to_canonical_nan(nan):\n    shrunk = minimal_from(nan, math.isnan)\n    assert float_to_int(shrunk) == float_to_int(math.nan)\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_forced.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\n\nimport pytest\n\nimport hypothesis.strategies as st\nfrom hypothesis import HealthCheck, example, given, settings\nfrom hypothesis.internal.conjecture import utils as cu\nfrom hypothesis.internal.conjecture.choice import choice_equal\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.floats import SIGNALING_NAN, SMALLEST_SUBNORMAL\n\nfrom tests.conjecture.common import choice_types_constraints, fresh_data\n\n\n@given(st.data())\n@settings(\n    database=None,\n    suppress_health_check=[HealthCheck.filter_too_much, HealthCheck.too_slow],\n)\ndef test_forced_many(data):\n    forced = data.draw(st.integers(0, 100))\n    min_size = data.draw(st.integers(0, forced))\n    max_size = data.draw(st.integers(forced, 100))\n    assert min_size <= forced <= max_size  # by construction\n\n    data = fresh_data()\n    many = cu.many(\n        data,\n        min_size=min_size,\n        average_size=(min_size + max_size) / 2,\n        max_size=max_size,\n        forced=forced,\n    )\n    for _ in range(forced):\n        assert many.more()\n\n    assert not many.more()\n\n    # ensure values written to the buffer do in fact generate the forced value\n    data = ConjectureData.for_choices(data.choices)\n    many = cu.many(\n        data,\n        min_size=min_size,\n        average_size=(min_size + max_size) / 2,\n        max_size=max_size,\n    )\n    for _ in range(forced):\n        assert many.more()\n\n    assert not many.more()\n\n\n@example((\"boolean\", {\"p\": 1e-19, \"forced\": True}))  # 64 bit p\n@example((\"boolean\", {\"p\": 3e-19, \"forced\": True}))  # 62 bit p\n@example(\n    (\n        \"integer\",\n        {\n            \"min_value\": -1,\n            \"max_value\": 1,\n            \"shrink_towards\": 1,\n            \"weights\": {-1: 0.2, 0: 0.2, 1: 0.2},\n            \"forced\": 0,\n        },\n    )\n)\n@example(\n    (\n        \"integer\",\n        {\n            \"min_value\": -1,\n            \"max_value\": 1,\n            \"shrink_towards\": -1,\n            \"weights\": {-1: 0.2, 0: 0.2, 1: 0.2},\n            \"forced\": 0,\n        },\n    )\n)\n@example(\n    (\n        \"integer\",\n        {\n            \"min_value\": 10,\n            \"max_value\": 1_000,\n            \"shrink_towards\": 17,\n            \"weights\": {20: 0.1},\n            \"forced\": 15,\n        },\n    )\n)\n@example(\n    (\n        \"integer\",\n        {\n            \"min_value\": -1_000,\n            \"max_value\": -10,\n            \"shrink_towards\": -17,\n            \"weights\": {-20: 0.1},\n            \"forced\": -15,\n        },\n    )\n)\n@example((\"float\", {\"forced\": 0.0}))\n@example((\"float\", {\"forced\": -0.0}))\n@example((\"float\", {\"forced\": 1.0}))\n@example((\"float\", {\"forced\": 1.2345}))\n@example((\"float\", {\"forced\": SMALLEST_SUBNORMAL}))\n@example((\"float\", {\"forced\": -SMALLEST_SUBNORMAL}))\n@example((\"float\", {\"forced\": 100 * SMALLEST_SUBNORMAL}))\n@example((\"float\", {\"forced\": math.nan}))\n@example((\"float\", {\"forced\": -math.nan}))\n@example((\"float\", {\"forced\": SIGNALING_NAN}))\n@example((\"float\", {\"forced\": -SIGNALING_NAN}))\n@example((\"float\", {\"forced\": 1e999}))\n@example((\"float\", {\"forced\": -1e999}))\n# previously errored on our {pos, neg}_clamper logic not considering nans.\n@example(\n    (\n        \"float\",\n        {\"min_value\": -1 * math.inf, \"max_value\": -1 * math.inf, \"forced\": math.nan},\n    )\n)\n@given(choice_types_constraints(use_forced=True))\ndef test_forced_values(choice_type_and_constraints):\n    (choice_type, constraints) = choice_type_and_constraints\n    constraints = constraints.copy()\n    forced = constraints[\"forced\"]\n    data = fresh_data()\n    assert choice_equal(getattr(data, f\"draw_{choice_type}\")(**constraints), forced)\n\n    # now make sure the written buffer reproduces the forced value, even without\n    # specifying forced=.\n    del constraints[\"forced\"]\n    data = ConjectureData.for_choices(data.choices)\n    assert choice_equal(getattr(data, f\"draw_{choice_type}\")(**constraints), forced)\n\n\n@pytest.mark.parametrize(\"sign\", [1, -1])\n@pytest.mark.parametrize(\n    \"min_value, max_value\",\n    [\n        (0.0, 0.0),\n        (-0.0, -0.0),\n        (0.0, 100.0),\n        (-100.0, -0.0),\n        (5.0, 10.0),\n        (-10.0, -5.0),\n    ],\n)\n@given(random=st.randoms())\ndef test_forced_floats_with_nan(random, sign, min_value, max_value):\n    # nans with a sign opposite of both bounds previously gave us trouble\n    # trying to use float clampers that didn't exist when drawing.\n    data = fresh_data(random=random)\n    data.draw_float(min_value=min_value, max_value=max_value, forced=sign * math.nan)\n\n\n@given(st.data())\ndef test_forced_with_large_magnitude_integers(data):\n    bound_offset = data.draw(st.integers(min_value=0))\n    # forced_offset = bound_offset + st.integers(min_value=0) may look cleaner, but\n    # has subtly different maximum value semantics as it is twice the range of a\n    # single draw\n    forced_offset = data.draw(st.integers(min_value=bound_offset))\n\n    half_range = 2**127 + 1\n    cd = fresh_data()\n    cd.draw_integer(\n        min_value=half_range + bound_offset, forced=half_range + forced_offset\n    )\n\n    cd = fresh_data()\n    cd.draw_integer(\n        max_value=-(half_range + bound_offset), forced=-(half_range + forced_offset)\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_inquisitor.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport traceback\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\n\nfrom tests.common.utils import fails_with\n\n\ndef fails_with_output(expected):\n    def _inner(f):\n        def _new():\n            with pytest.raises(AssertionError) as err:\n                f()\n\n            if not hasattr(err.value, \"__notes__\"):\n                traceback.print_exception(err.value)\n                raise Exception(\n                    \"err.value does not have __notes__, something has gone \"\n                    \"deeply wrong in the internals\"\n                )\n\n            got = \"\\n\".join(err.value.__notes__).strip() + \"\\n\"\n            assert got == expected.strip() + \"\\n\"\n\n        return _new\n\n    return _inner\n\n\n@fails_with_output(\n    \"\"\"\nFalsifying example: test_inquisitor_comments_basic_fail_if_either(\n    # The test always failed when commented parts were varied together.\n    a=False,  # or any other generated value\n    b=True,\n    c=[],  # or any other generated value\n    d=True,\n    e=False,  # or any other generated value\n)\n\"\"\"\n)\n@settings(print_blob=False, derandomize=True)\n@given(st.booleans(), st.booleans(), st.lists(st.none()), st.booleans(), st.booleans())\ndef test_inquisitor_comments_basic_fail_if_either(a, b, c, d, e):\n    assert not (b and d)\n\n\n@fails_with_output(\n    \"\"\"\nFalsifying example: test_inquisitor_comments_basic_fail_if_not_all(\n    # The test sometimes passed when commented parts were varied together.\n    a='',  # or any other generated value\n    b='',  # or any other generated value\n    c='',  # or any other generated value\n)\n\"\"\"\n)\n@settings(print_blob=False, derandomize=True)\n@given(st.text(), st.text(), st.text())\ndef test_inquisitor_comments_basic_fail_if_not_all(a, b, c):\n    condition = a and b and c\n    assert condition\n\n\n@fails_with_output(\n    \"\"\"\nFalsifying example: test_inquisitor_no_together_comment_if_single_argument(\n    a='',\n    b='',  # or any other generated value\n)\n\"\"\"\n)\n@settings(print_blob=False, derandomize=True)\n@given(st.text(), st.text())\ndef test_inquisitor_no_together_comment_if_single_argument(a, b):\n    assert a\n\n\n@st.composite\ndef ints_with_forced_draw(draw):\n    data = draw(st.data())\n    n = draw(st.integers())\n    data.conjecture_data.draw_boolean(forced=True)\n    return n\n\n\n@fails_with_output(\n    \"\"\"\nFalsifying example: test_inquisitor_doesnt_break_on_varying_forced_nodes(\n    n1=100,\n    n2=0,  # or any other generated value\n)\n\"\"\"\n)\n@settings(print_blob=False, derandomize=True)\n@given(st.integers(), ints_with_forced_draw())\ndef test_inquisitor_doesnt_break_on_varying_forced_nodes(n1, n2):\n    assert n1 < 100\n\n\n@fails_with(ZeroDivisionError)\n@settings(database=None)\n@given(start_date=st.datetimes(), data=st.data())\ndef test_issue_3755_regression(start_date, data):\n    data.draw(st.datetimes(min_value=start_date))\n    raise ZeroDivisionError\n\n\n# Tests for sub-argument explanations\n\n\nclass MyClass:\n    def __init__(self, x, y):\n        self.x = x\n        self.y = y\n\n\n@fails_with_output(\n    \"\"\"\nFalsifying example: test_inquisitor_builds_subargs(\n    obj=MyClass(\n        0,  # or any other generated value\n        True,\n    ),\n)\n\"\"\"\n)\n@settings(print_blob=False, derandomize=True)\n@given(st.builds(MyClass, st.integers(), st.booleans()))\ndef test_inquisitor_builds_subargs(obj):\n    assert not obj.y\n\n\n@fails_with_output(\n    \"\"\"\nFalsifying example: test_inquisitor_builds_kwargs_subargs(\n    obj=MyClass(\n        x=0,  # or any other generated value\n        y=True,\n    ),\n)\n\"\"\"\n)\n@settings(print_blob=False, derandomize=True)\n@given(st.builds(MyClass, x=st.integers(), y=st.booleans()))\ndef test_inquisitor_builds_kwargs_subargs(obj):\n    assert not obj.y\n\n\n@fails_with_output(\n    \"\"\"\nFalsifying example: test_inquisitor_tuple_subargs(\n    t=(\n        0,  # or any other generated value\n        True,\n    ),\n)\n\"\"\"\n)\n@settings(print_blob=False, derandomize=True)\n@given(st.tuples(st.integers(), st.booleans()))\ndef test_inquisitor_tuple_subargs(t):\n    assert not t[1]\n\n\n@fails_with_output(\n    \"\"\"\nFalsifying example: test_inquisitor_fixeddict_subargs(\n    d={\n        'x': 0,  # or any other generated value\n        'y': True,\n    },\n)\n\"\"\"\n)\n@settings(print_blob=False, derandomize=True)\n@given(st.fixed_dictionaries({\"x\": st.integers(), \"y\": st.booleans()}))\ndef test_inquisitor_fixeddict_subargs(d):\n    assert not d[\"y\"]\n\n\n@fails_with_output(\n    \"\"\"\nFalsifying example: test_inquisitor_tuple_multiple_varying(\n    t=(\n        0,  # or any other generated value\n        '',  # or any other generated value\n        True,\n    ),\n)\n\"\"\"\n)\n@settings(print_blob=False, derandomize=True)\n@given(st.tuples(st.integers(), st.text(), st.booleans()))\ndef test_inquisitor_tuple_multiple_varying(t):\n    # Multiple sub-arguments can vary, but the \"together\" comment only applies\n    # to top-level test arguments, not to sub-arguments within composites.\n    assert not t[2]\n\n\n@fails_with_output(\n    \"\"\"\nFalsifying example: test_inquisitor_skip_subset_slices(\n    obj=MyClass(\n        (0, False),  # or any other generated value\n        y=False,\n    ),\n)\n\"\"\"\n)\n@settings(print_blob=False, derandomize=True)\n@given(st.builds(MyClass, st.tuples(st.integers(), st.booleans()), y=st.booleans()))\ndef test_inquisitor_skip_subset_slices(obj):\n    # The tuple can vary freely, but the booleans inside it shouldn't\n    # get individual comments since they're part of a larger varying slice.\n    assert obj.y\n\n\n# Test for duplicate param names at different nesting levels\n@fails_with_output(\n    \"\"\"\nFalsifying example: test_inquisitor_duplicate_param_names(\n    kw=0,  # or any other generated value\n    b={\n        'kw': '',  # or any other generated value\n        'c': True,\n    },\n)\n\"\"\"\n)\n@settings(print_blob=False, derandomize=True)\n@given(kw=st.integers(), b=st.fixed_dictionaries({\"kw\": st.text(), \"c\": st.booleans()}))\ndef test_inquisitor_duplicate_param_names(kw, b):\n    # Both \"kw\" (top-level) and \"b['kw']\" can vary - they get separate comments\n    # even though they have the same name at different nesting levels.\n    # b['c'] is the critical value that determines the failure.\n    assert not b[\"c\"]\n\n\n# Test for multi-level nesting: bare, nested, and double-nested\nclass Outer:\n    def __init__(self, inner, value):\n        self.inner = inner\n        self.value = value\n\n\nclass Inner:\n    def __init__(self, x):\n        self.x = x\n\n\n@fails_with_output(\n    \"\"\"\nFalsifying example: test_inquisitor_multi_level_nesting(\n    bare=0,  # or any other generated value\n    outer=Outer(\n        inner=Inner(x=0),  # or any other generated value\n        value=True,\n    ),\n)\n\"\"\"\n)\n@settings(print_blob=False, derandomize=True)\n@given(\n    bare=st.integers(),\n    outer=st.builds(\n        Outer, inner=st.builds(Inner, x=st.integers()), value=st.booleans()\n    ),\n)\ndef test_inquisitor_multi_level_nesting(bare, outer):\n    # Comments on: bare (top-level) and outer.inner (nested). The inner.x slice\n    # is the same as inner's slice since Inner has only one argument, so the\n    # comment appears only once on inner. outer.value doesn't get a comment\n    # because it's the critical value that determines the failure.\n    assert not outer.value\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_intlist.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import assume, given, strategies as st\nfrom hypothesis.internal.conjecture.junkdrawer import IntList\n\nnon_neg_lists = st.lists(st.integers(min_value=0, max_value=2**63 - 1))\n\n\n@given(non_neg_lists)\ndef test_intlist_is_equal_to_itself(ls):\n    assert IntList(ls) == IntList(ls)\n\n\n@given(non_neg_lists, non_neg_lists)\ndef test_distinct_int_lists_are_not_equal(x, y):\n    assume(x != y)\n    assert IntList(x) != IntList(y)\n\n\ndef test_basic_equality():\n    x = IntList([1, 2, 3])\n    assert x == x\n    t = x != x\n    assert not t\n    assert x != \"foo\"\n\n    s = x == \"foo\"\n    assert not s\n\n\ndef test_error_on_invalid_value():\n    with pytest.raises(ValueError):\n        IntList([-1])\n\n\ndef test_extend_by_too_large():\n    x = IntList()\n    ls = [1, 10**6]\n    x.extend(ls)\n    assert list(x) == ls\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_junkdrawer.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport copy\nimport inspect\nimport sys\nimport warnings\n\nimport pytest\n\nfrom hypothesis import example, given, strategies as st\nfrom hypothesis.errors import HypothesisWarning\nfrom hypothesis.internal.conjecture import junkdrawer\nfrom hypothesis.internal.conjecture.junkdrawer import (\n    IntList,\n    LazySequenceCopy,\n    binary_search,\n    endswith,\n    ensure_free_stackframes,\n    replace_all,\n    stack_depth_of_caller,\n    startswith,\n)\nfrom hypothesis.internal.floats import clamp, float_to_int, sign_aware_lte\n\nfrom tests.common.utils import restore_recursion_limit\n\n\ndef test_out_of_range():\n    x = LazySequenceCopy([1, 2, 3])\n\n    with pytest.raises(IndexError):\n        x[3]\n\n    with pytest.raises(IndexError):\n        x[-4]\n\n\ndef test_pass_through():\n    x = LazySequenceCopy([1, 2, 3])\n    assert x[0] == 1\n    assert x[1] == 2\n    assert x[2] == 3\n\n\ndef test_can_assign_without_changing_underlying():\n    underlying = [1, 2, 3]\n    x = LazySequenceCopy(underlying)\n    x[1] = 10\n    assert x[1] == 10\n    assert underlying[1] == 2\n\n\ndef test_pop():\n    x = LazySequenceCopy([2, 3])\n    assert x.pop() == 3\n    assert x.pop() == 2\n\n    with pytest.raises(IndexError):\n        x.pop()\n\n\n@st.composite\ndef clamp_inputs(draw):\n    lower = draw(st.floats(allow_nan=False))\n    value = draw(st.floats(allow_nan=False))\n    upper = draw(st.floats(min_value=lower, allow_nan=False))\n    return (lower, value, upper)\n\n\n@example((1, 5, 10))\n@example((1, 10, 5))\n@example((5, 10, 5))\n@example((5, 1, 10))\n@example((-5, 0.0, -0.0))\n@example((0.0, -0.0, 5))\n@example((-0.0, 0.0, 0.0))\n@example((-0.0, -0.0, 0.0))\n@given(clamp_inputs())\ndef test_clamp(input):\n    lower, value, upper = input\n    clamped = clamp(lower, value, upper)\n\n    assert sign_aware_lte(lower, clamped)\n    assert sign_aware_lte(clamped, upper)\n    if sign_aware_lte(lower, value) and sign_aware_lte(value, upper):\n        assert float_to_int(value) == float_to_int(clamped)\n    if lower > value:\n        assert float_to_int(clamped) == float_to_int(lower)\n    if value > upper:\n        assert float_to_int(clamped) == float_to_int(upper)\n\n\n# this would be more robust as a stateful test, where each rule is a list operation\n# on (1) the canonical python list and (2) its LazySequenceCopy. We would assert\n# that the return values and lists match after each rule, and the original list\n# is unmodified.\n@pytest.mark.parametrize(\"should_mask\", [True, False])\n@given(lst=st.lists(st.integers(), min_size=1), data=st.data())\ndef test_pop_sequence_copy(lst, data, should_mask):\n    original = copy.copy(lst)\n    pop_i = data.draw(st.integers(0, len(lst) - 1))\n    if should_mask:\n        mask_i = data.draw(st.integers(0, len(lst) - 1))\n        mask_value = data.draw(st.integers())\n\n    def pop(l):\n        if should_mask:\n            l[mask_i] = mask_value\n        return l.pop(pop_i)\n\n    expected = copy.copy(lst)\n    l = LazySequenceCopy(lst)\n\n    assert pop(expected) == pop(l)\n    assert list(l) == expected\n    # modifications to the LazySequenceCopy should not modify the original list\n    assert original == lst\n\n\ndef test_assignment():\n    y = [1, 2, 3]\n    x = LazySequenceCopy(y)\n    x[-1] = 5\n    assert list(x) == [1, 2, 5]\n    x[-1] = 7\n    assert list(x) == [1, 2, 7]\n\n\ndef test_replacement():\n    result = replace_all([1, 1, 1, 1], [(1, 3, [3, 4])])\n    assert result == [1, 3, 4, 1]\n\n\ndef test_int_list_cannot_contain_negative():\n    with pytest.raises(ValueError):\n        IntList([-1])\n\n\ndef test_int_list_can_contain_arbitrary_size():\n    n = 2**65\n    assert list(IntList([n])) == [n]\n\n\ndef test_int_list_of_length():\n    assert list(IntList.of_length(10)) == [0] * 10\n\n\ndef test_int_list_equality():\n    ls = [1, 2, 3]\n    x = IntList(ls)\n    y = IntList(ls)\n\n    assert ls != x\n    assert x != ls\n    assert not (x == ls)  # noqa\n    assert x == x\n    assert x == y\n\n\ndef test_int_list_extend():\n    x = IntList.of_length(3)\n    n = 2**64 - 1\n    x.extend([n])\n    assert list(x) == [0, 0, 0, n]\n\n\ndef test_int_list_slice():\n    x = IntList([1, 2])\n    assert list(x[:1]) == [1]\n    assert list(x[0:2]) == [1, 2]\n    assert list(x[1:]) == [2]\n\n\ndef test_int_list_del():\n    x = IntList([1, 2])\n    del x[0]\n    assert x == IntList([2])\n\n\ndef test_int_list_insert():\n    x = IntList([1, 3])\n    x.insert(1, 2)\n    assert x == IntList([1, 2, 3])\n\n\n@pytest.mark.parametrize(\"n\", [0, 1, 30, 70])\ndef test_binary_search(n):\n    i = binary_search(0, 100, lambda i: i <= n)\n    assert i == n\n\n\ndef recur(i):\n    assert len(inspect.stack(0)) == stack_depth_of_caller()\n    if i >= 1:\n        recur(i - 1)\n\n\ndef test_stack_size_detection():\n    recur(100)\n\n\n@given(st.binary(), st.binary())\ndef test_startswith(b1, b2):\n    assert b1.startswith(b2) == startswith(b1, b2)\n\n\n@given(st.binary(), st.binary())\ndef test_endswith(b1, b2):\n    assert b1.endswith(b2) == endswith(b1, b2)\n\n\ndef test_stackframes_warns_when_recursion_limit_is_changed():\n    match = (\n        \"The recursion limit will not be reset, since it was changed during \"\n        \"test execution.\"\n    )\n    with (\n        restore_recursion_limit(),\n        pytest.warns(HypothesisWarning, match=match) as warnings,\n        ensure_free_stackframes(),\n    ):\n        sys.setrecursionlimit(100)\n\n    # we only got the warning once\n    assert len(warnings) == 1\n\n\ndef test_stackframes_cleans_up_on_werror():\n    limiter = junkdrawer._stackframe_limiter\n    with restore_recursion_limit(), warnings.catch_warnings():\n        warnings.simplefilter(\"error\")\n        assert limiter._active_contexts == 0\n\n        # the code for this cleanup case only triggers when the warning is raised\n        # on __enter__. set that up by entering one context, changing the limit,\n        # then entering another.\n        with pytest.raises(HypothesisWarning), ensure_free_stackframes():\n            assert limiter._active_contexts == 1\n            sys.setrecursionlimit(101)\n\n            with ensure_free_stackframes():\n                assert limiter._active_contexts == 2\n                sys.setrecursionlimit(102)\n\n            assert limiter._active_contexts == 1\n\n        assert limiter._active_contexts == 0\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_local_constants.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nimport sys\nfrom types import SimpleNamespace\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis.internal.conjecture import providers\nfrom hypothesis.internal.conjecture.choice import choice_equal\nfrom hypothesis.internal.conjecture.providers import CONSTANTS_CACHE\nfrom hypothesis.internal.constants_ast import Constants\n\nfrom tests.common.debug import find_any\nfrom tests.common.utils import Why, xfail_on_crosshair\n\n\n# I tried using @given(st.integers()) here, but I think there is a bad interaction\n# with CONSTANTS_CACHE when testing it inside of a hypothesis test.\n@pytest.mark.parametrize(\"value\", [2**20 - 50, 2**10 - 10, 129387123, -19827321, 0])\ndef test_can_draw_local_constants_integers(monkeypatch, value):\n    # _get_local_constants normally invalidates this cache for us, but we're\n    # monkeypatching it.\n    CONSTANTS_CACHE.cache.clear()\n    monkeypatch.setattr(\n        providers, \"_get_local_constants\", lambda: Constants(integers={value})\n    )\n    find_any(st.integers(), lambda v: choice_equal(v, value))\n\n\n@xfail_on_crosshair(Why.undiscovered)  # I think float_to_int is difficult for crosshair\n@pytest.mark.parametrize(\"value\", [1.2938, -1823.0239, 1e999, math.nan])\ndef test_can_draw_local_constants_floats(monkeypatch, value):\n    CONSTANTS_CACHE.cache.clear()\n    monkeypatch.setattr(\n        providers, \"_get_local_constants\", lambda: Constants(floats={value})\n    )\n    find_any(st.floats(), lambda v: choice_equal(v, value))\n\n\n@pytest.mark.parametrize(\"value\", [b\"abdefgh\", b\"a\" * 50])\ndef test_can_draw_local_constants_bytes(monkeypatch, value):\n    CONSTANTS_CACHE.cache.clear()\n    monkeypatch.setattr(\n        providers, \"_get_local_constants\", lambda: Constants(bytes={value})\n    )\n    find_any(st.binary(), lambda v: choice_equal(v, value))\n\n\n@pytest.mark.parametrize(\"value\", [\"abdefgh\", \"a\" * 50])\ndef test_can_draw_local_constants_string(monkeypatch, value):\n    CONSTANTS_CACHE.cache.clear()\n    monkeypatch.setattr(\n        providers, \"_get_local_constants\", lambda: Constants(strings={value})\n    )\n    # we have a bunch of strings in GLOBAL_CONSTANTS, so it might take a while\n    # to generate our local constant.\n    find_any(\n        st.text(),\n        lambda v: choice_equal(v, value),\n        settings=settings(max_examples=5_000),\n    )\n\n\ndef test_actual_collection(monkeypatch, tmp_path):\n    # covering test for doing some real work collecting constants. We'll fake\n    # hypothesis as being the \"local\" module, just to get some real constant\n    # collection going.\n\n    # reset cache checks\n    monkeypatch.setattr(providers, \"_sys_modules_len\", None)\n    monkeypatch.setattr(providers, \"_seen_modules\", set())\n    monkeypatch.setattr(providers, \"is_local_module_file\", lambda f: \"hypothesis\" in f)\n    # Without monkeypatching this, this test only covers all the right lines the\n    # first time it's executed, since it falls back to the cache the second time.\n    # Reset to a guaranteed-empty storage directory to ensure consistent coverage.\n    monkeypatch.setattr(\n        \"hypothesis.internal.constants_ast.storage_directory\",\n        lambda *names, **kwargs: tmp_path.joinpath(*names),\n    )\n\n    @given(st.integers())\n    @settings(max_examples=100)\n    def f(n):\n        pass\n\n    f()\n\n\ndef test_unhashable_sys_modules_entry(monkeypatch):\n    # Regression test for https://github.com/HypothesisWorks/hypothesis/issues/4660\n    # Some packages (e.g. cog) place unhashable objects like SimpleNamespace\n    # in sys.modules. This should not crash _get_local_constants.\n    monkeypatch.setattr(providers, \"_sys_modules_len\", None)\n    monkeypatch.setattr(providers, \"_seen_modules\", set())\n    monkeypatch.setitem(sys.modules, \"_unhashable_test_mod\", SimpleNamespace())\n\n    providers._get_local_constants()\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_minimizer.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections import Counter\n\nimport pytest\n\nfrom hypothesis.internal.conjecture.shrinking import (\n    Bytes,\n    Collection,\n    Integer,\n    Ordering,\n    String,\n)\nfrom hypothesis.internal.intervalsets import IntervalSet\n\n\ndef test_shrink_to_zero():\n    assert Integer.shrink(2**16, lambda n: True) == 0\n\n\ndef test_shrink_to_smallest():\n    assert Integer.shrink(2**16, lambda n: n > 10) == 11\n\n\ndef test_can_sort_bytes_by_reordering():\n    start = bytes([5, 4, 3, 2, 1, 0])\n    finish = Ordering.shrink(start, lambda x: set(x) == set(start))\n    assert bytes(finish) == bytes([0, 1, 2, 3, 4, 5])\n\n\ndef test_can_sort_bytes_by_reordering_partially():\n    start = bytes([5, 4, 3, 2, 1, 0])\n    finish = Ordering.shrink(start, lambda x: set(x) == set(start) and x[0] > x[-1])\n    assert bytes(finish) == bytes([1, 2, 3, 4, 5, 0])\n\n\ndef test_can_sort_bytes_by_reordering_partially2():\n    start = bytes([5, 4, 3, 2, 1, 0])\n    finish = Ordering.shrink(\n        start,\n        lambda x: Counter(x) == Counter(start) and x[0] > x[2],\n        full=True,\n    )\n    assert bytes(finish) == bytes([1, 2, 0, 3, 4, 5])\n\n\ndef test_can_sort_bytes_by_reordering_partially_not_cross_stationary_element():\n    start = bytes([5, 3, 0, 2, 1, 4])\n    finish = Ordering.shrink(start, lambda x: set(x) == set(start) and x[3] == 2)\n    assert bytes(finish) == bytes([0, 1, 3, 2, 4, 5])\n\n\n@pytest.mark.parametrize(\n    \"initial, predicate, intervals, expected\",\n    [\n        (\"f\" * 10, lambda s: True, IntervalSet.from_string(\"abcdefg\"), \"\"),\n        (\"f\" * 10, lambda s: len(s) >= 3, IntervalSet.from_string(\"abcdefg\"), \"aaa\"),\n        (\n            \"f\" * 10,\n            lambda s: len(s) >= 3 and \"a\" not in s,\n            IntervalSet.from_string(\"abcdefg\"),\n            \"bbb\",\n        ),\n    ],\n)\ndef test_shrink_strings(initial, predicate, intervals, expected):\n    assert String.shrink(\n        initial, predicate, intervals=intervals, min_size=len(expected)\n    ) == tuple(expected)\n\n\n@pytest.mark.parametrize(\n    \"initial, predicate, expected\",\n    [\n        (b\"\\x18\\x12\", lambda v: len(v) == 2, b\"\\x00\\x00\"),\n        (b\"\\x18\\x12\", lambda v: True, b\"\"),\n        (b\"\\x01\\x10\", lambda v: len(v) > 0 and v[0] == 1, b\"\\x01\"),\n        (b\"\\x01\\x10\\x01\\x92\", lambda v: sum(v) >= 9, b\"\\x09\"),\n    ],\n)\ndef test_shrink_bytes(initial, predicate, expected):\n    assert bytes(Bytes.shrink(initial, predicate, min_size=len(expected))) == expected\n\n\ndef test_collection_left_is_better():\n    shrinker = Collection(\n        [1, 2, 3], lambda v: True, ElementShrinker=Integer, min_size=3\n    )\n    assert not shrinker.left_is_better([1, 2, 3], [1, 2, 3])\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_mutations.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import strategies as st\n\nfrom tests.common.debug import find_any\n\ntree = st.deferred(lambda: st.tuples(st.integers(), tree, tree)) | st.just(None)\n\n\ndef test_can_find_duplicated_subtree():\n    # look for an example of the form\n    #\n    #                  ┌─────┐\n    #           ┌──────┤  a  ├──────┐\n    #           │      └─────┘      │\n    #        ┌──┴──┐             ┌──┴──┐\n    #        │  b  │             │  a  │\n    #        └──┬──┘             └──┬──┘\n    #      ┌────┴────┐         ┌────┴────┐\n    #   ┌──┴──┐   ┌──┴──┐   ┌──┴──┐   ┌──┴──┐\n    #   │  c  │   │  d  │   │  b  │   │ ... │\n    #   └─────┘   └─────┘   └──┬──┘   └─────┘\n    #                     ┌────┴────┐\n    #                  ┌──┴──┐   ┌──┴──┐\n    #                  │  c  │   │  d  │\n    #                  └─────┘   └─────┘\n    #\n    # If we just checked that (b, c, d) was duplicated somewhere, this could have\n    # happened as a result of normal mutation. Checking for the a parent node as\n    # well is unlikely to have been generated without tree mutation, however.\n    find_any(\n        tree,\n        (\n            lambda v: v is not None\n            and v[1] is not None\n            and v[2] is not None\n            and v[0] == v[2][0]\n            and v[1] == v[2][1]\n        ),\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_optimiser.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nfrom random import Random\n\nimport pytest\n\nfrom hypothesis import HealthCheck, assume, example, given, settings\nfrom hypothesis.internal.conjecture.choice import ChoiceNode\nfrom hypothesis.internal.conjecture.data import Status\nfrom hypothesis.internal.conjecture.datatree import compute_max_children\nfrom hypothesis.internal.conjecture.engine import ConjectureRunner, RunIsComplete\nfrom hypothesis.internal.intervalsets import IntervalSet\n\nfrom tests.conjecture.common import (\n    buffer_size_limit,\n    integer_constr,\n    nodes,\n)\n\nrunner_settings = settings(\n    max_examples=100, database=None, suppress_health_check=list(HealthCheck)\n)\n\n\ndef test_optimises_to_maximum():\n    def test(data):\n        data.target_observations[\"m\"] = data.draw_integer(0, 2**8 - 1)\n\n    runner = ConjectureRunner(test, settings=runner_settings, random=Random(0))\n    runner.cached_test_function((0,))\n\n    try:\n        runner.optimise_targets()\n    except RunIsComplete:\n        pass\n\n    assert runner.best_observed_targets[\"m\"] == 255\n\n\ndef test_optimises_multiple_targets():\n    def test(data):\n        n = data.draw_integer(0, 2**8 - 1)\n        m = data.draw_integer(0, 2**8 - 1)\n        if n + m > 256:\n            data.mark_invalid()\n        data.target_observations[\"m\"] = m\n        data.target_observations[\"n\"] = n\n        data.target_observations[\"m + n\"] = m + n\n\n    runner = ConjectureRunner(test, settings=runner_settings, random=Random(0))\n    runner.cached_test_function((200, 0))\n    runner.cached_test_function((0, 200))\n\n    try:\n        runner.optimise_targets()\n    except RunIsComplete:\n        pass\n\n    assert runner.best_observed_targets[\"m\"] == 255\n    assert runner.best_observed_targets[\"n\"] == 255\n    assert runner.best_observed_targets[\"m + n\"] == 256\n\n\ndef test_optimises_when_last_element_is_empty():\n    def test(data):\n        data.target_observations[\"n\"] = data.draw_integer(0, 2**8 - 1)\n        data.start_span(label=1)\n        data.stop_span()\n\n    runner = ConjectureRunner(test, settings=runner_settings, random=Random(0))\n    runner.cached_test_function((250,))\n\n    try:\n        runner.optimise_targets()\n    except RunIsComplete:\n        pass\n\n    assert runner.best_observed_targets[\"n\"] == 255\n\n\ndef test_can_optimise_last_with_following_empty():\n    def test(data):\n        for _ in range(100):\n            data.draw_integer(0, 3)\n        data.target_observations[\"\"] = data.draw_integer(0, 2**8 - 1)\n        data.start_span(1)\n        data.stop_span()\n\n    runner = ConjectureRunner(\n        test, settings=settings(runner_settings, max_examples=100), random=Random(0)\n    )\n    runner.cached_test_function((0,) * 101)\n\n    with pytest.raises(RunIsComplete):\n        runner.optimise_targets()\n    assert runner.best_observed_targets[\"\"] == 255\n\n\n@pytest.mark.parametrize(\"lower, upper\", [(0, 1000), (13, 100), (1000, 2**16 - 1)])\n@pytest.mark.parametrize(\"score_up\", [False, True])\ndef test_can_find_endpoints_of_a_range(lower, upper, score_up):\n    def test(data):\n        n = data.draw_integer(0, 2**16 - 1)\n        if n < lower or n > upper:\n            data.mark_invalid()\n        if not score_up:\n            n = -n\n        data.target_observations[\"n\"] = n\n\n    runner = ConjectureRunner(\n        test, settings=settings(runner_settings, max_examples=1000), random=Random(0)\n    )\n    runner.cached_test_function(((lower + upper) // 2,))\n\n    try:\n        runner.optimise_targets()\n    except RunIsComplete:\n        pass\n    if score_up:\n        assert runner.best_observed_targets[\"n\"] == upper\n    else:\n        assert runner.best_observed_targets[\"n\"] == -lower\n\n\ndef test_targeting_can_drive_length_very_high():\n    def test(data):\n        count = 0\n        while data.draw_boolean(0.25):\n            count += 1\n        data.target_observations[\"\"] = min(count, 100)\n\n    runner = ConjectureRunner(test, settings=runner_settings, random=Random(0))\n    # extend here to ensure we get a valid (non-overrun) test case. The\n    # outcome of the test case doesn't really matter as long as we have\n    # something for the runner to optimize.\n    runner.cached_test_function([], extend=50)\n\n    try:\n        runner.optimise_targets()\n    except RunIsComplete:\n        pass\n\n    assert runner.best_observed_targets[\"\"] == 100\n\n\ndef test_optimiser_when_test_grows_buffer_to_invalid():\n    def test(data):\n        m = data.draw_integer(0, 2**8 - 1)\n        data.target_observations[\"m\"] = m\n        if m > 100:\n            data.draw_integer(0, 2**16 - 1)\n            data.mark_invalid()\n\n    runner = ConjectureRunner(test, settings=runner_settings, random=Random(0))\n    runner.cached_test_function((0,) * 10)\n\n    try:\n        runner.optimise_targets()\n    except RunIsComplete:\n        pass\n\n    assert runner.best_observed_targets[\"m\"] == 100\n\n\ndef test_can_patch_up_examples():\n    def test(data):\n        data.start_span(42)\n        m = data.draw_integer(0, 2**6 - 1)\n        data.target_observations[\"m\"] = m\n        for _ in range(m):\n            data.draw_boolean()\n        data.stop_span()\n        for i in range(4):\n            if i != data.draw_integer(0, 2**8 - 1):\n                data.mark_invalid()\n\n    runner = ConjectureRunner(\n        test, settings=settings(runner_settings, max_examples=1000), random=Random(0)\n    )\n    d = runner.cached_test_function((0, 0, 1, 2, 3, 4))\n    assert d.status == Status.VALID\n\n    try:\n        runner.optimise_targets()\n    except RunIsComplete:\n        pass\n\n    assert runner.best_observed_targets[\"m\"] == 63\n\n\ndef test_optimiser_when_test_grows_buffer_to_overflow():\n    def test(data):\n        m = data.draw_integer(0, 2**8 - 1)\n        data.target_observations[\"m\"] = m\n        if m > 100:\n            data.draw_integer(0, 2**64 - 1)\n            data.mark_invalid()\n\n    runner = ConjectureRunner(test, settings=runner_settings, random=Random(0))\n\n    with buffer_size_limit(2):\n        runner.cached_test_function((0,) * 10)\n\n        try:\n            runner.optimise_targets()\n        except RunIsComplete:\n            pass\n\n    assert runner.best_observed_targets[\"m\"] == 100\n\n\n@given(nodes())\n@example(\n    ChoiceNode(\n        type=\"bytes\",\n        value=b\"\\xb1\",\n        constraints={\"min_size\": 1, \"max_size\": 1},\n        was_forced=False,\n    )\n)\n@example(\n    ChoiceNode(\n        type=\"string\",\n        value=\"aaaa\",\n        constraints={\n            \"min_size\": 0,\n            \"max_size\": 10,\n            \"intervals\": IntervalSet.from_string(\"abcd\"),\n        },\n        was_forced=False,\n    )\n)\n@example(\n    ChoiceNode(\n        type=\"integer\", value=1, constraints=integer_constr(0, 200), was_forced=False\n    )\n)\ndef test_optimising_all_nodes(node):\n    assume(compute_max_children(node.type, node.constraints) > 50)\n    size_function = {\n        \"integer\": lambda n: n,\n        \"float\": lambda f: f if math.isfinite(f) else 0,\n        \"string\": lambda s: len(s),\n        \"bytes\": lambda b: len(b),\n        \"boolean\": lambda b: int(b),\n    }\n\n    def test(data):\n        v = getattr(data, f\"draw_{node.type}\")(**node.constraints)\n        data.target_observations[\"v\"] = size_function[node.type](v)\n\n    runner = ConjectureRunner(\n        test, settings=settings(runner_settings, max_examples=50), random=Random(0)\n    )\n    runner.cached_test_function([node.value])\n\n    try:\n        runner.optimise_targets()\n    except RunIsComplete:\n        pass\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_order_shrinking.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import example, given, strategies as st\nfrom hypothesis.internal.conjecture.shrinking import Ordering\n\n\n@example([0, 1, 1, 1, 1, 1, 1, 0])\n@example([0, 0])\n@example([0, 1, -1])\n@given(st.lists(st.integers()))\ndef test_shrinks_down_to_sorted_the_slow_way(ls):\n    # We normally would short-circuit and find that we can sort this\n    # automatically, but here we test that a single run_step could put the\n    # list in sorted order anyway if it had to, and that that is just an\n    # optimisation.\n    shrinker = Ordering(ls, lambda ls: True, full=False)\n    shrinker.run_step()\n    assert list(shrinker.current) == sorted(ls)\n\n\ndef test_can_partially_sort_a_list():\n    finish = Ordering.shrink([5, 4, 3, 2, 1, 0], lambda x: x[0] > x[-1])\n    assert finish == (1, 2, 3, 4, 5, 0)\n\n\ndef test_can_partially_sort_a_list_2():\n    finish = Ordering.shrink([5, 4, 3, 2, 1, 0], lambda x: x[0] > x[2], full=True)\n    assert finish <= (1, 2, 0, 3, 4, 5)\n\n\ndef test_adaptively_shrinks_around_hole():\n    initial = list(range(1000, 0, -1))\n    initial[500] = 2000\n\n    intended_result = sorted(initial)\n    intended_result.insert(500, intended_result.pop())\n\n    shrinker = Ordering(initial, lambda ls: ls[500] == 2000, full=True)\n    shrinker.run()\n\n    assert shrinker.current[500] == 2000\n\n    assert list(shrinker.current) == intended_result\n    assert shrinker.calls <= 60\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_pareto.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport contextlib\nimport itertools\nfrom random import Random\n\nimport pytest\n\nfrom hypothesis import HealthCheck, Phase, settings, strategies as st\nfrom hypothesis.database import (\n    InMemoryExampleDatabase,\n    choices_from_bytes,\n    choices_to_bytes,\n)\nfrom hypothesis.errors import StopTest\nfrom hypothesis.internal.conjecture.data import ConjectureData, Status\nfrom hypothesis.internal.conjecture.engine import ConjectureRunner, RunIsComplete\nfrom hypothesis.internal.conjecture.pareto import ParetoFront\n\nfrom tests.conjecture.common import interesting_origin\n\n\ndef test_pareto_front_contains_different_interesting_reasons():\n    def test(data):\n        data.target_observations[\"\"] = 1\n        n = data.draw_integer(0, 2**4 - 1)\n        data.mark_interesting(interesting_origin(n))\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(\n            max_examples=5000,\n            database=InMemoryExampleDatabase(),\n            suppress_health_check=list(HealthCheck),\n        ),\n        database_key=b\"stuff\",\n        random=Random(0),\n    )\n\n    runner.run()\n    assert len(runner.pareto_front) == 2**4\n\n\ndef test_pareto_front_omits_invalid_examples():\n    def test(data):\n        x = data.draw_integer(0, 2**4 - 1)\n        if x % 2:\n            data.target_observations[\"\"] = 1\n            data.mark_invalid()\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(\n            max_examples=5000,\n            database=InMemoryExampleDatabase(),\n            suppress_health_check=list(HealthCheck),\n        ),\n        database_key=b\"stuff\",\n        random=Random(0),\n    )\n\n    runner.run()\n    assert len(runner.pareto_front) == 0\n\n\ndef test_database_contains_only_pareto_front():\n    def test(data):\n        data.target_observations[\"1\"] = data.draw(st.integers(0, 2**4))\n        data.draw(st.integers(0, 2**64))\n        data.target_observations[\"2\"] = data.draw(st.integers(0, 2**8))\n\n        assert len(set(db.fetch(b\"stuff.pareto\"))) == len(runner.pareto_front)\n\n    db = InMemoryExampleDatabase()\n    runner = ConjectureRunner(\n        test,\n        settings=settings(\n            max_examples=500, database=db, suppress_health_check=list(HealthCheck)\n        ),\n        database_key=b\"stuff\",\n        random=Random(0),\n    )\n    runner.run()\n\n    assert len(runner.pareto_front) <= 500\n    for v in runner.pareto_front:\n        assert v.status >= Status.VALID\n\n    values = set(db.fetch(b\"stuff.pareto\"))\n    assert len(values) == len(runner.pareto_front), {\n        choices_to_bytes(data.choices) for data in runner.pareto_front\n    }.symmetric_difference(values)\n\n    for data in runner.pareto_front:\n        assert choices_to_bytes(data.choices) in values\n        assert data in runner.pareto_front\n\n    for b in values:\n        choices = choices_from_bytes(b)\n        assert runner.cached_test_function(choices) in runner.pareto_front\n\n\ndef test_clears_defunct_pareto_front():\n    def test(data):\n        data.target_observations[\"\"] = 1\n        data.draw_integer(0, 2**8 - 1)\n        data.draw_integer(0, 2**8 - 1)\n\n    db = InMemoryExampleDatabase()\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(\n            max_examples=10000,\n            database=db,\n            suppress_health_check=list(HealthCheck),\n            phases=[Phase.reuse],\n        ),\n        database_key=b\"stuff\",\n        random=Random(0),\n    )\n\n    for i in range(256):\n        db.save(runner.pareto_key, choices_to_bytes((i, 0)))\n\n    runner.run()\n    assert len(list(db.fetch(runner.pareto_key))) == 1\n\n\ndef test_down_samples_the_pareto_front():\n    def test(data):\n        data.draw_integer(0, 2**8 - 1)\n        data.draw_integer(0, 2**8 - 1)\n\n    db = InMemoryExampleDatabase()\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(\n            max_examples=1000,\n            database=db,\n            suppress_health_check=list(HealthCheck),\n            phases=[Phase.reuse],\n        ),\n        database_key=b\"stuff\",\n        random=Random(0),\n    )\n\n    for n1, n2 in itertools.product(range(256), range(256)):\n        db.save(runner.pareto_key, choices_to_bytes((n1, n2)))\n\n    with pytest.raises(RunIsComplete):\n        runner.reuse_existing_examples()\n\n    assert runner.valid_examples == 1000\n\n\ndef test_stops_loading_pareto_front_if_interesting():\n    def test(data):\n        data.draw_integer()\n        data.draw_integer()\n        data.mark_interesting(interesting_origin())\n\n    db = InMemoryExampleDatabase()\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(\n            max_examples=1000,\n            database=db,\n            suppress_health_check=list(HealthCheck),\n            phases=[Phase.reuse],\n        ),\n        database_key=b\"stuff\",\n        random=Random(0),\n    )\n\n    for n1, n2 in itertools.product(range(256), range(256)):\n        db.save(runner.pareto_key, choices_to_bytes((n1, n2)))\n\n    runner.reuse_existing_examples()\n    assert runner.call_count == 1\n\n\ndef test_uses_tags_in_calculating_pareto_front():\n    def test(data):\n        data.target_observations[\"\"] = 1\n        if data.draw_boolean():\n            data.start_span(11)\n            data.draw_integer(0, 2**8 - 1)\n            data.stop_span()\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(max_examples=10, database=InMemoryExampleDatabase()),\n        database_key=b\"stuff\",\n        random=Random(0),\n    )\n\n    runner.run()\n    assert len(runner.pareto_front) == 2\n\n\ndef test_optimises_the_pareto_front():\n    def test(data):\n        count = 0\n        while data.draw_integer(0, 2**8 - 1):\n            count += 1\n\n        data.target_observations[\"\"] = min(count, 5)\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(max_examples=10000, database=InMemoryExampleDatabase()),\n        database_key=b\"stuff\",\n    )\n    runner.cached_test_function([255] * 20 + [0])\n    runner.pareto_optimise()\n\n    assert len(runner.pareto_front) == 6\n    for i, data in enumerate(runner.pareto_front):\n        assert data.choices == (1,) * i + (0,)\n\n\ndef test_does_not_optimise_the_pareto_front_if_interesting():\n    def test(data):\n        n = data.draw_integer(0, 2**8 - 1)\n        data.target_observations[\"\"] = n\n        if n == 255:\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(max_examples=10000, database=InMemoryExampleDatabase()),\n        database_key=b\"stuff\",\n    )\n\n    runner.cached_test_function([0])\n    runner.pareto_optimise = None\n    runner.optimise_targets()\n\n    assert runner.interesting_examples\n\n\ndef test_stops_optimising_once_interesting():\n    hi = 2**16 - 1\n\n    def test(data):\n        n = data.draw_integer(0, 2**16 - 1)\n        data.target_observations[\"\"] = n\n        if n < hi:\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(max_examples=10000, database=InMemoryExampleDatabase()),\n        database_key=b\"stuff\",\n    )\n\n    data = runner.cached_test_function([hi])\n    assert data.status == Status.VALID\n    runner.pareto_optimise()\n    assert runner.call_count <= 20\n    assert runner.interesting_examples\n\n\ndef test_pareto_contains():\n    front = ParetoFront(random=Random())\n    assert \"not a data\" not in front\n\n    data = ConjectureData.for_choices([])\n    with contextlib.suppress(StopTest):\n        data.mark_overrun()\n    # check a data which turns into an Overrun when .as_result is called\n    assert data not in front\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_provider.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport dataclasses\nimport itertools\nimport math\nimport sys\nimport time\nimport warnings\nfrom contextlib import contextmanager, nullcontext\nfrom random import Random\nfrom threading import RLock\n\nimport pytest\n\nfrom hypothesis import (\n    HealthCheck,\n    Verbosity,\n    assume,\n    errors,\n    given,\n    settings,\n    strategies as st,\n)\nfrom hypothesis.control import current_build_context\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.errors import (\n    BackendCannotProceed,\n    Flaky,\n    FlakyBackendFailure,\n    HypothesisException,\n    HypothesisWarning,\n    InvalidArgument,\n    Unsatisfiable,\n)\nfrom hypothesis.internal.compat import WINDOWS, int_to_bytes\nfrom hypothesis.internal.conjecture.data import ConjectureData, PrimitiveProvider\nfrom hypothesis.internal.conjecture.engine import ConjectureRunner\nfrom hypothesis.internal.conjecture.provider_conformance import run_conformance_test\nfrom hypothesis.internal.conjecture.providers import (\n    AVAILABLE_PROVIDERS,\n    COLLECTION_DEFAULT_MAX_SIZE,\n    HypothesisProvider,\n    with_register_backend,\n)\nfrom hypothesis.internal.floats import SIGNALING_NAN, clamp\nfrom hypothesis.internal.intervalsets import IntervalSet\nfrom hypothesis.internal.observability import Observation, _callbacks\n\nfrom tests.common.debug import minimal\nfrom tests.common.utils import (\n    capture_observations,\n    capture_out,\n)\nfrom tests.conjecture.common import nodes\n\n\nclass PrngProvider(PrimitiveProvider):\n    # A test-only implementation of the PrimitiveProvider interface, which uses\n    # a very simple PRNG to choose each value. Dumb but efficient, and entirely\n    # independent of our real backend\n\n    def __init__(self, conjecturedata: \"ConjectureData | None\", /) -> None:\n        super().__init__(conjecturedata)\n        self.prng = Random(0)\n\n    def draw_boolean(\n        self,\n        p: float = 0.5,\n    ) -> bool:\n        return self.prng.random() < p\n\n    def draw_integer(\n        self,\n        min_value: int | None = None,\n        max_value: int | None = None,\n        *,\n        weights: dict[int, float] | None = None,\n        shrink_towards: int = 0,\n    ) -> int:\n        # shrink_towards is fully ignored here. It would be nice to implement\n        # weights, but it's tricky to fully conform it to our\n        # provider_conformance test.\n        assert isinstance(shrink_towards, int)\n        assert weights is None or isinstance(weights, dict)\n\n        if min_value is None and max_value is None:\n            min_value = -(2**127)\n            max_value = 2**127 - 1\n        elif min_value is None:\n            min_value = max_value - 2**64\n        elif max_value is None:\n            max_value = min_value + 2**64\n        return self.prng.randint(min_value, max_value)\n\n    def draw_float(\n        self,\n        *,\n        min_value: float = -math.inf,\n        max_value: float = math.inf,\n        allow_nan: bool = True,\n        smallest_nonzero_magnitude: float,\n    ) -> float:\n        if allow_nan and self.prng.random() < 1 / 32:\n            nans = [math.nan, -math.nan, SIGNALING_NAN, -SIGNALING_NAN]\n            return self.prng.choice(nans)\n\n        # small chance of inf values, if they are in bounds\n        if min_value <= math.inf <= max_value and self.prng.random() < 1 / 32:\n            return math.inf\n        if min_value <= -math.inf <= max_value and self.prng.random() < 1 / 32:\n            return -math.inf\n\n        # get rid of infs, they cause nans if we pass them to prng.uniform\n        min_value_bound = min_value\n        max_value_bound = max_value\n        if min_value in [-math.inf, math.inf]:\n            min_value_bound = math.copysign(1, min_value) * sys.float_info.max\n            # being too close to the bounds causes prng.uniform to only return\n            # inf.\n            min_value_bound /= 2\n        if max_value in [-math.inf, math.inf]:\n            max_value_bound = math.copysign(1, max_value) * sys.float_info.max\n            max_value_bound /= 2\n\n        value = self.prng.uniform(min_value_bound, max_value_bound)\n        # random.uniform can in fact provide out of bounds values, e.g.\n        #   random.uniform(-8.98846567431158e+307, 8.98846567431158e+307)\n        # can produce math.inf, which is strictly greater than 8.98846567431158e+307\n        value = clamp(min_value, value, max_value)\n        if value and abs(value) < smallest_nonzero_magnitude:\n            return (\n                smallest_nonzero_magnitude\n                if min_value <= smallest_nonzero_magnitude <= max_value\n                else -smallest_nonzero_magnitude\n            )\n        return value\n\n    def draw_string(\n        self,\n        intervals: IntervalSet,\n        *,\n        min_size: int = 0,\n        max_size: int = COLLECTION_DEFAULT_MAX_SIZE,\n    ) -> str:\n        size = self.prng.randint(\n            min_size, max(min_size, min(100 if max_size is None else max_size, 100))\n        )\n        if len(intervals) == 0:\n            return \"\"\n        return \"\".join(map(chr, self.prng.choices(intervals, k=size)))\n\n    def draw_bytes(\n        self,\n        min_size: int = 0,\n        max_size: int = COLLECTION_DEFAULT_MAX_SIZE,\n    ) -> bytes:\n        # cap max size for performance\n        max_size = 100 if max_size is None else min(max_size, 100)\n        size = self.prng.randint(min_size, max_size)\n        return self.prng.randbytes(size)\n\n\n_temp_register_backend_lock = RLock()\n\n\n# same as with_register_backend, but adds a lock for our threading tests.\n@contextmanager\ndef temp_register_backend(name, provider_cls):\n    with _temp_register_backend_lock, with_register_backend(name, provider_cls):\n        yield\n\n\n@pytest.mark.parametrize(\n    \"strategy\",\n    [\n        st.booleans(),\n        st.integers(0, 3),\n        st.floats(0, 1),\n        st.text(max_size=3),\n        st.binary(max_size=3),\n    ],\n    ids=repr,\n)\ndef test_find_with_backend_then_convert_to_buffer_shrink_and_replay(strategy):\n    db = InMemoryExampleDatabase()\n    assert not db.data\n\n    with temp_register_backend(\"prng\", PrngProvider):\n\n        @settings(database=db, backend=\"prng\")\n        @given(strategy)\n        def test(value):\n            if isinstance(value, float):\n                assert value >= 0.5\n            else:\n                assert value\n\n        with pytest.raises(AssertionError):\n            test()\n\n    assert db.data\n    buffers = {x for x in db.data[next(iter(db.data))] if x}\n    assert buffers, db.data\n\n\ndef test_backend_can_shrink_integers():\n    with temp_register_backend(\"prng\", PrngProvider):\n        n = minimal(\n            st.integers(),\n            lambda n: n >= 123456,\n            settings=settings(backend=\"prng\", database=None),\n        )\n\n    assert n == 123456\n\n\ndef test_backend_can_shrink_bytes():\n    with temp_register_backend(\"prng\", PrngProvider):\n        b = minimal(\n            # this test doubles as coverage for popping draw_bytes ir nodes,\n            # and that path is only taken with fixed size for the moment. can\n            # be removed when we support variable length binary at the ir level.\n            st.binary(min_size=2, max_size=2),\n            lambda b: len(b) >= 2 and b[1] >= 10,\n            settings=settings(backend=\"prng\", database=None),\n        )\n\n    assert b == int_to_bytes(10, size=2)\n\n\ndef test_backend_can_shrink_strings():\n    with temp_register_backend(\"prng\", PrngProvider):\n        s = minimal(\n            st.text(),\n            lambda s: len(s) >= 10,\n            settings=settings(backend=\"prng\", database=None),\n        )\n\n    assert len(s) == 10\n\n\ndef test_backend_can_shrink_booleans():\n    with temp_register_backend(\"prng\", PrngProvider):\n        b = minimal(\n            st.booleans(), lambda b: b, settings=settings(backend=\"prng\", database=None)\n        )\n\n    assert b\n\n\ndef test_backend_can_shrink_floats():\n    with temp_register_backend(\"prng\", PrngProvider):\n        f = minimal(\n            st.floats(),\n            lambda f: f >= 100.5,\n            settings=settings(backend=\"prng\", database=None),\n        )\n\n    assert f == 101.0\n\n\n# mostly a shoehorned coverage test until the shrinker is migrated to the ir\n# and calls cached_test_function with backends consistently.\n@given(nodes())\ndef test_new_conjecture_data_with_backend(node):\n    def test(data):\n        getattr(data, f\"draw_{node.type}\")(**node.constraints)\n\n    with temp_register_backend(\"prng\", PrngProvider):\n        runner = ConjectureRunner(test, settings=settings(backend=\"prng\"))\n        runner.cached_test_function([node.value])\n\n\n# trivial provider for tests which don't care about drawn distributions.\nclass TrivialProvider(PrimitiveProvider):\n    def draw_integer(self, *args, **constraints):\n        return 1\n\n    def draw_boolean(self, *args, **constraints):\n        return True\n\n    def draw_float(self, *args, **constraints):\n        return 1.0\n\n    def draw_bytes(self, *args, **constraints):\n        return b\"\"\n\n    def draw_string(self, *args, **constraints):\n        return \"\"\n\n\nclass InvalidLifetime(TrivialProvider):\n\n    lifetime = \"forever and a day\"\n\n\ndef test_invalid_lifetime():\n    with (\n        temp_register_backend(\"invalid_lifetime\", InvalidLifetime),\n        pytest.raises(InvalidArgument),\n    ):\n        ConjectureRunner(lambda: True, settings=settings(backend=\"invalid_lifetime\"))\n\n\nfunction_lifetime_init_count = 0\n\n\nclass LifetimeTestFunction(TrivialProvider):\n    lifetime = \"test_function\"\n\n    def __init__(self, conjecturedata):\n        super().__init__(conjecturedata)\n        # hacky, but no easy alternative.\n        global function_lifetime_init_count\n        function_lifetime_init_count += 1\n\n\ndef test_function_lifetime():\n    with temp_register_backend(\"lifetime_function\", LifetimeTestFunction):\n\n        @given(st.integers())\n        @settings(backend=\"lifetime_function\")\n        def test_function(n):\n            pass\n\n        assert function_lifetime_init_count == 0\n        test_function()\n        assert function_lifetime_init_count == 1\n        test_function()\n        assert function_lifetime_init_count == 2\n\n\ntest_case_lifetime_init_count = 0\n\n\nclass LifetimeTestCase(TrivialProvider):\n    lifetime = \"test_case\"\n\n    def __init__(self, conjecturedata):\n        super().__init__(conjecturedata)\n        global test_case_lifetime_init_count\n        test_case_lifetime_init_count += 1\n\n\ndef test_case_lifetime():\n    test_function_count = 0\n\n    with temp_register_backend(\"lifetime_case\", LifetimeTestCase):\n\n        @given(st.integers())\n        @settings(backend=\"lifetime_case\", database=InMemoryExampleDatabase())\n        def test_function(n):\n            nonlocal test_function_count\n            test_function_count += 1\n\n        assert test_case_lifetime_init_count == 0\n        test_function()\n\n        # we create a new provider each time we *try* to generate an input to the\n        # test function, but this could be filtered out, discarded as duplicate,\n        # etc. We also sometimes try predetermined inputs to the test function,\n        # such as ChoiceTemplate(type=\"simplest\"), which does not entail creating\n        # providers. These two facts combined mean that the number of inits could be\n        # anywhere reasonably close to the number of function calls.\n        assert (\n            test_function_count - 10\n            <= test_case_lifetime_init_count\n            <= test_function_count + 10\n        )\n\n\ndef test_flaky_with_backend():\n    with temp_register_backend(\"trivial\", TrivialProvider), capture_observations():\n\n        calls = 0\n\n        @given(st.integers())\n        @settings(backend=\"trivial\", database=None)\n        def test_function(n):\n            nonlocal calls\n            calls += 1\n            assert n != calls % 2\n\n        with pytest.raises(Flaky):\n            test_function()\n\n\nclass BadRealizeProvider(TrivialProvider):\n    def realize(self, value, *, for_failure=False):\n        return None\n\n\ndef test_bad_realize():\n    with temp_register_backend(\"bad_realize\", BadRealizeProvider):\n\n        @given(st.integers())\n        @settings(backend=\"bad_realize\")\n        def test_function(n):\n            pass\n\n        with pytest.raises(\n            HypothesisException,\n            match=r\"expected .* from BadRealizeProvider.realize\",\n        ):\n            test_function()\n\n\nclass RealizeProvider(TrivialProvider):\n    # self-documenting constant\n    REALIZED = 42\n    avoid_realization = True\n\n    def realize(self, value, *, for_failure=False):\n        if isinstance(value, int):\n            return self.REALIZED\n        return value\n\n\ndef test_realize():\n    with temp_register_backend(\"realize\", RealizeProvider):\n        values = []\n\n        @given(st.integers())\n        @settings(backend=\"realize\")\n        def test_function(n):\n            values.append(current_build_context().data.provider.realize(n))\n\n        test_function()\n\n        # first draw is 0 from ChoiceTemplate(type=\"simplest\")\n        assert values[0] == 0\n        assert all(n == RealizeProvider.REALIZED for n in values[1:])\n\n\ndef test_realize_dependent_draw():\n    with temp_register_backend(\"realize\", RealizeProvider):\n\n        @given(st.data())\n        @settings(backend=\"realize\")\n        def test_function(data):\n            n1 = data.draw(st.integers())\n            n2 = data.draw(st.integers(n1, n1 + 10))\n            assert n1 <= n2\n\n        test_function()\n\n\n@pytest.mark.parametrize(\"verbosity\", [Verbosity.verbose, Verbosity.debug])\ndef test_realization_with_verbosity(verbosity):\n    with temp_register_backend(\"realize\", RealizeProvider):\n\n        @given(st.floats())\n        @settings(backend=\"realize\", verbosity=verbosity)\n        def test_function(f):\n            pass\n\n        with capture_out() as out:\n            test_function()\n        assert \"Trying example: test_function(\\n    f=<symbolic>,\\n)\" in out.getvalue()\n\n\n@pytest.mark.parametrize(\"verbosity\", [Verbosity.verbose, Verbosity.debug])\ndef test_realization_with_verbosity_draw(verbosity):\n    with temp_register_backend(\"realize\", RealizeProvider):\n\n        @given(st.data())\n        @settings(backend=\"realize\", verbosity=verbosity)\n        def test_function(data):\n            data.draw(st.integers())\n\n        with capture_out() as out:\n            test_function()\n        assert \"Draw 1: <symbolic>\" in out.getvalue()\n\n\ndef test_realization_with_observability():\n    with temp_register_backend(\"realize\", RealizeProvider):\n\n        @given(st.data())\n        @settings(backend=\"realize\")\n        def test_function(data):\n            data.draw(st.integers())\n\n        with capture_observations() as observations:\n            test_function()\n\n    test_cases = [tc for tc in observations if tc.type == \"test_case\"]\n    assert {tc.representation for tc in test_cases} == {\n        # from the first ChoiceTemplate(type=\"simplest\") example\n        \"test_function(\\n    data=data(...),\\n)\\nDraw 1: 0\",\n        # from all other examples. data=<symbolic> isn't ideal; we should special\n        # case this as data=data(...).\n        f\"test_function(\\n    data=<symbolic>,\\n)\\nDraw 1: {RealizeProvider.REALIZED}\",\n    }\n\n\nclass ObservableProvider(TrivialProvider):\n    def observe_test_case(self):\n        return {\"msg_key\": \"some message\", \"data_key\": [1, \"2\", {}]}\n\n    def observe_information_messages(self, *, lifetime):\n        if lifetime == \"test_case\":\n            yield {\"type\": \"info\", \"title\": \"trivial-data\", \"content\": {\"k2\": \"v2\"}}\n        else:\n            assert lifetime == \"test_function\"\n            yield {\"type\": \"alert\", \"title\": \"Trivial alert\", \"content\": \"message here\"}\n            yield {\"type\": \"info\", \"title\": \"trivial-data\", \"content\": {\"k2\": \"v2\"}}\n\n\ndef test_custom_observations_from_backend():\n    with temp_register_backend(\"observable\", ObservableProvider):\n\n        @given(st.booleans())\n        @settings(backend=\"observable\", database=None)\n        def test_function(_):\n            pass\n\n        with capture_observations() as ls:\n            test_function()\n\n    assert len(ls) >= 3\n    cases = [t.metadata.backend for t in ls if t.type == \"test_case\"]\n    assert {\"msg_key\": \"some message\", \"data_key\": [1, \"2\", {}]} in cases\n\n    infos = [\n        {k: v for k, v in dataclasses.asdict(t).items() if k in (\"title\", \"content\")}\n        for t in ls\n        if t.type != \"test_case\"\n    ]\n    assert {\"title\": \"Trivial alert\", \"content\": \"message here\"} in infos\n    assert {\"title\": \"trivial-data\", \"content\": {\"k2\": \"v2\"}} in infos\n\n\nclass NeverProceedsObservable(ObservableProvider):\n    def realize(self, value, *, for_failure=False):\n        raise BackendCannotProceed\n\n\ndef test_custom_observations_cannot_realize():\n    with temp_register_backend(\"never_proceeds\", NeverProceedsObservable):\n\n        @given(st.integers())\n        @settings(backend=\"never_proceeds\", database=None)\n        def test_function(_):\n            pass\n\n        with capture_observations() as ls:\n            test_function()\n\n    assert \"<backend failed to realize symbolic arguments>\" in repr(ls)\n\n\ndef test_backend_realize_cannot_proceed_increments_invalid():\n    def test(data):\n        data.draw_integer()\n\n    with with_register_backend(\"never_proceeds\", NeverProceedsObservable):\n        runner = ConjectureRunner(\n            test,\n            settings=settings(backend=\"never_proceeds\", database=None),\n        )\n        assert runner.invalid_examples == 0\n        runner.cached_test_function([1])\n        assert runner.invalid_examples == 1\n\n\ndef test_backend_realize_cannot_proceed_exception_increments_invalid():\n    # test the alternative code path where the test is interesting and we realize\n    # the values with for_failure=True\n    def test(data):\n        data.draw_integer()\n        raise ValueError\n\n    with with_register_backend(\"never_proceeds\", NeverProceedsObservable):\n        runner = ConjectureRunner(\n            test,\n            settings=settings(backend=\"never_proceeds\", database=None),\n        )\n        assert runner.invalid_examples == 0\n        runner.cached_test_function([1])\n        assert runner.invalid_examples == 1\n\n\nclass FallibleProvider(TrivialProvider):\n    def __init__(self, conjecturedata: \"ConjectureData\", /) -> None:\n        super().__init__(conjecturedata)\n        self._it = itertools.cycle([1, 1, \"discard_test_case\", \"other\"])\n\n    def draw_integer(self, *args, **constraints):\n        x = next(self._it)\n        if isinstance(x, str):\n            raise BackendCannotProceed(x)\n        return x\n\n\ndef test_falls_back_to_default_backend():\n    with temp_register_backend(\"fallible\", FallibleProvider):\n        seen_other_ints = False\n\n        @given(st.integers())\n        @settings(backend=\"fallible\", database=None, max_examples=100)\n        def test_function(x):\n            nonlocal seen_other_ints\n            seen_other_ints |= x != 1\n\n        test_function()\n        assert seen_other_ints  # must have swapped backends then\n\n\ndef test_can_raise_unsatisfiable_after_falling_back():\n    with temp_register_backend(\"fallible\", FallibleProvider):\n\n        @given(st.integers())\n        @settings(\n            backend=\"fallible\",\n            database=None,\n            max_examples=100,\n            suppress_health_check=[HealthCheck.filter_too_much],\n        )\n        def test_function(x):\n            assume(x == \"unsatisfiable\")\n\n        with pytest.raises(Unsatisfiable):\n            test_function()\n\n\nclass ExhaustibleProvider(TrivialProvider):\n    scope = \"exhausted\"\n\n    def __init__(self, conjecturedata: \"ConjectureData\", /) -> None:\n        super().__init__(conjecturedata)\n        self._calls = 0\n\n    def draw_integer(self, *args, **constraints):\n        self._calls += 1\n        if self._calls > 20:\n            # This is complete nonsense of course, so we'll see Hypothesis complain\n            # that we found a problem after the backend reported verification.\n            raise BackendCannotProceed(self.scope)\n        return self._calls\n\n\nclass UnsoundVerifierProvider(ExhaustibleProvider):\n    scope = \"verified\"\n\n\n@pytest.mark.parametrize(\"provider\", [ExhaustibleProvider, UnsoundVerifierProvider])\ndef test_notes_incorrect_verification(provider):\n    msg = \"backend='p' claimed to verify this test passes - please send them a bug report!\"\n    with temp_register_backend(\"p\", provider):\n\n        @given(st.integers())\n        @settings(backend=\"p\", database=None, max_examples=100)\n        def test_function(x):\n            assert x >= 0  # True from this backend, false in general!\n\n        with pytest.raises(AssertionError) as ctx:\n            test_function()\n        assert (msg in ctx.value.__notes__) == (provider is UnsoundVerifierProvider)\n\n\ndef test_invalid_provider_kw():\n    with pytest.raises(InvalidArgument, match=\"got an instance instead\"):\n        ConjectureData(\n            random=None,\n            provider=TrivialProvider(None),\n            provider_kw={\"one\": \"two\"},\n        )\n\n\ndef test_available_providers_deprecation():\n    with pytest.warns(errors.HypothesisDeprecationWarning):\n        from hypothesis.internal.conjecture.data import AVAILABLE_PROVIDERS  # noqa\n\n    with pytest.raises(ImportError):\n        from hypothesis.internal.conjecture.data import does_not_exist  # noqa\n\n\n@pytest.mark.parametrize(\"backend\", AVAILABLE_PROVIDERS.keys())\n@pytest.mark.parametrize(\n    \"strategy\", [st.integers(), st.text(), st.floats(), st.booleans(), st.binary()]\n)\ndef test_can_generate_from_all_available_providers(backend, strategy):\n    # note: database=InMemoryExampleDatabase() is for compatibility with HypoFuzz\n    # here.\n    @given(strategy)\n    @settings(backend=backend, database=InMemoryExampleDatabase())\n    def f(x):\n        raise ValueError\n\n    with (\n        pytest.raises(ValueError),\n        (\n            pytest.warns(\n                HypothesisWarning, match=\"/dev/urandom is not available on windows\"\n            )\n            if backend == \"hypothesis-urandom\" and WINDOWS\n            else nullcontext()\n        ),\n    ):\n        f()\n\n\ndef test_saves_on_fatal_error_with_backend():\n    with temp_register_backend(\"trivial\", TrivialProvider):\n        db = InMemoryExampleDatabase()\n\n        @given(st.integers())\n        @settings(backend=\"trivial\", database=db)\n        def test_function(n):\n            raise BaseException(\"marker\")\n\n        with pytest.raises(BaseException, match=\"marker\"):\n            test_function()\n\n        assert len(db.data) == 1\n\n\nclass SoundnessTestProvider(TrivialProvider):\n    def __init__(self, conjecturedata):\n        super().__init__(conjecturedata)\n        self.n = 0\n\n    def draw_integer(self, **constraints):\n        self.n += 1\n        if self.n == 1:\n            return 1\n\n        raise BackendCannotProceed(\"verified\")\n\n\ndef test_raising_verified_after_failure_is_sound():\n    # see https://github.com/pschanely/hypothesis-crosshair/issues/31#issuecomment-2852940574\n\n    with temp_register_backend(\"soundness_test\", SoundnessTestProvider):\n\n        @given(st.integers())\n        @settings(backend=\"soundness_test\", database=None)\n        def f(n):\n            assert n != 1\n\n        with pytest.raises(AssertionError) as e:\n            f()\n        # full message as of writing: \"backend='soundness_test' claimed to\n        # verify this test passes - please send them a bug report!\"\n        assert all(\"backend\" not in note for note in e.value.__notes__)\n\n\ndef test_replay_choices():\n    # trivial covering test\n    provider = TrivialProvider(None)\n    provider.replay_choices([1])\n\n\nclass ObservationProvider(TrivialProvider):\n    add_observability_callback = True\n\n    def __init__(self, conjecturedata: \"ConjectureData\", /) -> None:\n        super().__init__(conjecturedata)\n        # calls to per_test_case_context_manager and on_observation alternate,\n        # starting with per_test_case_context_manager\n        self.expected = \"per_test_case_context_manager\"\n\n    @contextmanager\n    def per_test_case_context_manager(self):\n        assert self.expected == \"per_test_case_context_manager\"\n        self.expected = \"on_observation\"\n        yield\n\n    def on_observation(self, observation: Observation) -> None:\n        assert self.expected == \"on_observation\"\n        self.expected = \"per_test_case_context_manager\"\n\n\n@temp_register_backend(\"observation\", ObservationProvider)\ndef test_on_observation_alternates():\n    @given(st.integers())\n    @settings(backend=\"observation\")\n    def f(n):\n        pass\n\n    f()\n\n\n@temp_register_backend(\"observation\", ObservationProvider)\ndef test_on_observation_alternates_on_failure():\n    @given(st.integers())\n    @settings(backend=\"observation\")\n    def f(n):\n        # Hypothesis tries n == 0 first, and if that fails then we don't exercise\n        # any provider-specific paths.\n        if n == 1:\n            raise ValueError(\"unique identifier\")\n\n    with pytest.raises(ValueError, match=\"unique identifier\"):\n        f()\n\n\n@temp_register_backend(\"observation\", TrivialProvider)\ndef test_on_observation_no_override():\n    @given(st.integers())\n    @settings(backend=\"observation\")\n    def f(n):\n        assert _callbacks == {}\n\n    f()\n\n\n@pytest.mark.parametrize(\"provider\", [HypothesisProvider, PrngProvider])\ndef test_provider_conformance(provider):\n    with warnings.catch_warnings():\n        # emitted by available_timezones() from st.timezone_keys() on 3.11+\n        # with tzdata installed. see https://github.com/python/cpython/issues/137841.\n        # Once cpython fixes this, we can remove this.\n        if sys.version_info >= (3, 11):\n            warnings.simplefilter(\"ignore\", EncodingWarning)\n        run_conformance_test(\n            provider, settings=settings(max_examples=20, stateful_step_count=20)\n        )\n\n\n# see https://github.com/HypothesisWorks/hypothesis/issues/4462 and discussion\n# in https://github.com/HypothesisWorks/hypothesis/pull/4470\ndef test_backend_deadline_exceeded_raised_as_flaky_backend_failure():\n    with temp_register_backend(\"trivial\", TrivialProvider):\n\n        @given(st.integers())\n        @settings(backend=\"trivial\", database=None)\n        def f(n):\n            if isinstance(current_build_context().data.provider, TrivialProvider):\n                time.sleep(1)\n\n        with pytest.raises(FlakyBackendFailure):\n            f()\n\n\ndef test_backend_cannot_proceed_raises_on_invalid_scope():\n    with pytest.raises(InvalidArgument):\n        BackendCannotProceed(\"not a valid scope\")\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_provider_contract.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import example, given, strategies as st\nfrom hypothesis.errors import StopTest\nfrom hypothesis.internal.compat import WINDOWS\nfrom hypothesis.internal.conjecture.choice import (\n    choice_equal,\n    choice_from_index,\n    choice_permitted,\n)\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.conjecture.providers import (\n    BytestringProvider,\n    HypothesisProvider,\n    URandomProvider,\n)\nfrom hypothesis.internal.intervalsets import IntervalSet\n\nfrom tests.conjecture.common import (\n    choice_types_constraints,\n    float_constr,\n    integer_constr,\n    nodes,\n    string_constr,\n)\n\n\n@example(b\"\\x00\" * 100, [(\"integer\", integer_constr())])\n@example(b\"\\x00\" * 100, [(\"integer\", integer_constr(0, 2))])\n@example(b\"\\x00\" * 100, [(\"integer\", integer_constr(0, 0))])\n@example(b\"\\x00\" * 100, [(\"integer\", integer_constr(min_value=0))])\n@example(b\"\\x00\" * 100, [(\"integer\", integer_constr(max_value=2))])\n@example(b\"\\x00\" * 100, [(\"integer\", integer_constr(0, 2, weights={0: 0.1}))])\n@example(b\"\\x00\" * 100, [(\"boolean\", {\"p\": 1.0})])\n@example(b\"\\x00\" * 100, [(\"boolean\", {\"p\": 0.0})])\n@example(b\"\\x00\" * 100, [(\"boolean\", {\"p\": 1e-99})])\n@example(b\"\\x00\" * 100, [(\"string\", string_constr(IntervalSet.from_string(\"a\")))])\n@example(b\"\\x00\" * 100, [(\"float\", float_constr())])\n@example(b\"\\x00\" * 100, [(\"bytes\", {\"min_size\": 0, \"max_size\": 10})])\n@example(b\"\\x00\", [(\"integer\", integer_constr())])\n@given(st.binary(min_size=200), st.lists(choice_types_constraints()))\ndef test_provider_contract_bytestring(bytestring, choice_type_and_constraints):\n    data = ConjectureData(\n        random=None,\n        observer=None,\n        provider=BytestringProvider,\n        provider_kw={\"bytestring\": bytestring},\n    )\n\n    for choice_type, constraints in choice_type_and_constraints:\n        # for the threading ci tests\n        constraints = constraints.copy()\n        try:\n            value = getattr(data, f\"draw_{choice_type}\")(**constraints)\n        except StopTest:\n            return\n\n        assert choice_permitted(value, constraints)\n        constraints[\"forced\"] = choice_from_index(0, choice_type, constraints)\n        assert choice_equal(\n            constraints[\"forced\"], getattr(data, f\"draw_{choice_type}\")(**constraints)\n        )\n\n\n@pytest.mark.parametrize(\n    \"provider\",\n    [\n        pytest.param(\n            URandomProvider,\n            marks=pytest.mark.skipif(\n                WINDOWS, reason=\"/dev/urandom not available on windows\"\n            ),\n        ),\n        HypothesisProvider,\n    ],\n)\n@given(st.lists(nodes()), st.randoms())\ndef test_provider_contract(provider, nodes, random):\n    data = ConjectureData(random=random, provider=provider)\n    for node in nodes:\n        value = getattr(data, f\"draw_{node.type}\")(**node.constraints)\n        assert choice_permitted(value, node.constraints)\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_shrinker.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport time\n\nimport pytest\n\nfrom hypothesis import HealthCheck, assume, example, given, settings, strategies as st\nfrom hypothesis.internal.conjecture.data import ChoiceNode, ConjectureData\nfrom hypothesis.internal.conjecture.datatree import compute_max_children\nfrom hypothesis.internal.conjecture.engine import ConjectureRunner\nfrom hypothesis.internal.conjecture.shrinker import Shrinker, ShrinkPass, StopShrinking\nfrom hypothesis.internal.conjecture.shrinking.common import Shrinker as ShrinkerPass\nfrom hypothesis.internal.conjecture.utils import Sampler\nfrom hypothesis.internal.floats import MAX_PRECISE_INTEGER\n\nfrom tests.common.utils import skipif_time_unpatched\nfrom tests.conjecture.common import (\n    SOME_LABEL,\n    float_constr,\n    interesting_origin,\n    nodes,\n    nodes_inline,\n    run_to_nodes,\n    shrinking_from,\n)\n\n\n@pytest.mark.parametrize(\"n\", [1, 5, 8, 15])\ndef test_can_shrink_variable_draws_with_just_deletion(n):\n    @shrinking_from((n,) + (0,) * (n - 1) + (1,))\n    def shrinker(data: ConjectureData):\n        n = data.draw_integer(0, 2**4 - 1)\n        b = [data.draw_integer(0, 2**8 - 1) for _ in range(n)]\n        if any(b):\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.minimize_individual_choices)])\n    assert shrinker.choices == (1, 1)\n\n\ndef test_deletion_and_lowering_fails_to_shrink(monkeypatch):\n    monkeypatch.setattr(\n        Shrinker,\n        \"shrink\",\n        lambda self: self.fixate_shrink_passes(\n            [ShrinkPass(self.minimize_individual_choices)]\n        ),\n    )\n    monkeypatch.setattr(\n        ConjectureRunner,\n        \"generate_new_examples\",\n        lambda runner: runner.cached_test_function((b\"\\0\",) * 10),\n    )\n\n    @run_to_nodes\n    def nodes(data):\n        for _ in range(10):\n            data.draw_bytes(1, 1)\n        data.mark_interesting(interesting_origin())\n\n    assert tuple(n.value for n in nodes) == (b\"\\0\",) * 10\n\n\ndef test_duplicate_nodes_that_go_away():\n    @shrinking_from((1234567, 1234567) + (b\"\\1\",) * (1234567 & 255))\n    def shrinker(data: ConjectureData):\n        x = data.draw_integer(min_value=0)\n        y = data.draw_integer(min_value=0)\n        if x != y:\n            data.mark_invalid()\n        b = [data.draw_bytes(1, 1) for _ in range(x & 255)]\n        if len(set(b)) <= 1:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.minimize_duplicated_choices)])\n    assert shrinker.shrink_target.choices == (0, 0)\n\n\ndef test_accidental_duplication():\n    @shrinking_from((12, 12) + (b\"\\2\",) * 12)\n    def shrinker(data: ConjectureData):\n        x = data.draw_integer(0, 2**8 - 1)\n        y = data.draw_integer(0, 2**8 - 1)\n        if x != y:\n            data.mark_invalid()\n        if x < 5:\n            data.mark_invalid()\n        b = [data.draw_bytes(1, 1) for _ in range(x)]\n        if len(set(b)) == 1:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.minimize_duplicated_choices)])\n    print(shrinker.choices)\n    assert shrinker.choices == (5, 5, *([b\"\\x00\"] * 5))\n\n\ndef test_can_zero_subintervals():\n    @shrinking_from((3, 0, 0, 0, 1) * 10)\n    def shrinker(data: ConjectureData):\n        for _ in range(10):\n            data.start_span(SOME_LABEL)\n            n = data.draw_integer(0, 2**8 - 1)\n            for _ in range(n):\n                data.draw_integer(0, 2**8 - 1)\n            data.stop_span()\n            if data.draw_integer(0, 2**8 - 1) != 1:\n                return\n        data.mark_interesting(interesting_origin())\n\n    shrinker.shrink()\n    assert shrinker.choices == (0, 1) * 10\n\n\ndef test_can_pass_to_an_indirect_descendant():\n    def tree(data):\n        data.start_span(label=1)\n        n = data.draw_integer(0, 1)\n        data.draw_integer(0, 2**8 - 1)\n        if n:\n            tree(data)\n            tree(data)\n        data.stop_span(discard=True)\n\n    initial = (1, 10, 0, 0, 1, 0, 0, 10, 0, 0)\n    target = (0, 10)\n    good = {initial, target}\n\n    @shrinking_from(initial)\n    def shrinker(data: ConjectureData):\n        tree(data)\n        if data.choices in good:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.pass_to_descendant)])\n    assert shrinker.choices == target\n\n\ndef test_shrinking_blocks_from_common_offset():\n    @shrinking_from((11, 10))\n    def shrinker(data: ConjectureData):\n        m = data.draw_integer(0, 2**8 - 1)\n        n = data.draw_integer(0, 2**8 - 1)\n        if abs(m - n) <= 1 and max(m, n) > 0:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.mark_changed(0)\n    shrinker.mark_changed(1)\n    shrinker.lower_common_node_offset()\n    assert shrinker.choices in {(0, 1), (1, 0)}\n\n\ndef test_handle_empty_draws():\n    @run_to_nodes\n    def nodes(data):\n        while True:\n            data.start_span(SOME_LABEL)\n            n = data.draw_integer(0, 1)\n            data.start_span(SOME_LABEL)\n            data.stop_span()\n            data.stop_span(discard=n > 0)\n            if not n:\n                break\n        data.mark_interesting(interesting_origin())\n\n    assert tuple(n.value for n in nodes) == (0,)\n\n\ndef test_can_reorder_spans():\n    # grouped by iteration: (1, 1) (1, 1) (0) (0) (0)\n    @shrinking_from((1, 1, 1, 1, 0, 0, 0))\n    def shrinker(data: ConjectureData):\n        total = 0\n        for _ in range(5):\n            data.start_span(label=0)\n            if data.draw_integer(0, 2**8 - 1):\n                total += data.draw_integer(0, 2**9 - 1)\n            data.stop_span()\n        if total == 2:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.reorder_spans)])\n    assert shrinker.choices == (0, 0, 0, 1, 1, 1, 1)\n\n\ndef test_permits_but_ignores_raising_order(monkeypatch):\n    monkeypatch.setattr(\n        ConjectureRunner,\n        \"generate_new_examples\",\n        lambda runner: runner.cached_test_function((1,)),\n    )\n\n    monkeypatch.setattr(\n        Shrinker, \"shrink\", lambda self: self.consider_new_nodes(nodes_inline(2))\n    )\n\n    @run_to_nodes\n    def nodes(data):\n        data.draw_integer(0, 3)\n        data.mark_interesting(interesting_origin())\n\n    assert tuple(n.value for n in nodes) == (1,)\n\n\ndef test_node_deletion_can_delete_short_ranges():\n    @shrinking_from([v for i in range(5) for _ in range(i + 1) for v in [i]])\n    def shrinker(data: ConjectureData):\n        while True:\n            n = data.draw_integer(0, 2**16 - 1)\n            for _ in range(n):\n                if data.draw_integer(0, 2**16 - 1) != n:\n                    data.mark_invalid()\n            if n == 4:\n                data.mark_interesting(interesting_origin())\n\n    passes = [shrinker.node_program(\"X\" * i) for i in range(1, 5)]\n    shrinker.fixate_shrink_passes(passes)\n    assert shrinker.choices == (4,) * 5\n\n\ndef test_dependent_block_pairs_is_up_to_shrinking_integers():\n    # Unit test extracted from a failure in tests/nocover/test_integers.py\n    distribution = Sampler([4.0, 8.0, 1.0, 1.0, 0.5])\n    sizes = [8, 16, 32, 64, 128]\n\n    @shrinking_from((3, True, 65538, 1))\n    def shrinker(data: ConjectureData):\n        size = sizes[distribution.sample(data)]\n        result = data.draw_integer(0, 2**size - 1)\n        sign = (-1) ** (result & 1)\n        result = (result >> 1) * sign\n        cap = data.draw_integer(0, 2**8 - 1)\n\n        if result >= 32768 and cap == 1:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.minimize_individual_choices)])\n    assert shrinker.choices == (1, True, 65536, 1)\n\n\ndef test_finding_a_minimal_balanced_binary_tree():\n    # Tests iteration while the shape of the thing being iterated over can\n    # change. In particular the current example can go from trivial to non\n    # trivial.\n\n    def tree(data):\n        # Returns height of a binary tree and whether it is height balanced.\n        data.start_span(label=0)\n        if not data.draw_boolean():\n            result = (1, True)\n        else:\n            h1, b1 = tree(data)\n            h2, b2 = tree(data)\n            result = (1 + max(h1, h2), b1 and b2 and abs(h1 - h2) <= 1)\n        data.stop_span()\n        return result\n\n    # Starting from an unbalanced tree of depth six\n    @shrinking_from((True,) * 5 + (False,) * 6)\n    def shrinker(data: ConjectureData):\n        _, b = tree(data)\n        if not b:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.shrink()\n    assert shrinker.choices == (True, False, True, False, True, False, False)\n\n\ndef test_node_programs_are_adaptive():\n    @shrinking_from((False,) * 1000 + (True,))\n    def shrinker(data: ConjectureData):\n        while not data.draw_boolean():\n            pass\n        data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([shrinker.node_program(\"X\")])\n\n    assert len(shrinker.choices) == 1\n    assert shrinker.calls <= 60\n\n\ndef test_zero_examples_with_variable_min_size():\n    @shrinking_from((255,) * 100)\n    def shrinker(data: ConjectureData):\n        any_nonzero = False\n        for i in range(1, 10):\n            any_nonzero |= data.draw_integer(0, 2**i - 1) > 0\n        if not any_nonzero:\n            data.mark_invalid()\n        data.mark_interesting(interesting_origin())\n\n    shrinker.shrink()\n    assert shrinker.choices == (0,) * 8 + (1,)\n\n\ndef test_zero_contained_examples():\n    @shrinking_from((1,) * 8)\n    def shrinker(data: ConjectureData):\n        for _ in range(4):\n            data.start_span(1)\n            if data.draw_integer(0, 2**8 - 1) == 0:\n                data.mark_invalid()\n            data.start_span(1)\n            data.draw_integer(0, 2**8 - 1)\n            data.stop_span()\n            data.stop_span()\n        data.mark_interesting(interesting_origin())\n\n    shrinker.shrink()\n    assert shrinker.choices == (1, 0) * 4\n\n\ndef test_zig_zags_quickly():\n    @shrinking_from((255,) * 4)\n    def shrinker(data: ConjectureData):\n        m = data.draw_integer(0, 2**16 - 1)\n        n = data.draw_integer(0, 2**16 - 1)\n        if m == 0 or n == 0:\n            data.mark_invalid()\n        if abs(m - n) <= 1:\n            data.mark_interesting(interesting_origin(0))\n        # Two different interesting origins for avoiding slipping in the\n        # shrinker.\n        if abs(m - n) <= 10:\n            data.mark_interesting(interesting_origin(1))\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.minimize_individual_choices)])\n    assert shrinker.engine.valid_examples <= 100\n    assert shrinker.choices == (1, 1)\n\n\n@pytest.mark.parametrize(\n    \"min_value, max_value, forced, shrink_towards, expected\",\n    [\n        # this test disallows interesting values in radius 10 interval around shrink_towards\n        # to avoid trivial shrinks messing with things, which is why the expected\n        # values are ±10 from shrink_towards.\n        (-100, 0, -100, 0, (-10, -10)),\n        (-100, 0, -100, -35, (-25, -25)),\n        (0, 100, 100, 0, (10, 10)),\n        (0, 100, 100, 65, (75, 75)),\n    ],\n)\ndef test_zig_zags_quickly_with_shrink_towards(\n    min_value, max_value, forced, shrink_towards, expected\n):\n    # we should be able to efficiently incorporate shrink_towards when dealing\n    # with zig zags.\n\n    @shrinking_from((forced,) * 2)\n    def shrinker(data: ConjectureData):\n        m = data.draw_integer(min_value, max_value, shrink_towards=shrink_towards)\n        n = data.draw_integer(min_value, max_value, shrink_towards=shrink_towards)\n        # avoid trivial counterexamples\n        if abs(m - shrink_towards) < 10 or abs(n - shrink_towards) < 10:\n            data.mark_invalid()\n        if abs(m - n) <= 1:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.minimize_individual_choices)])\n    assert shrinker.engine.valid_examples <= 40\n    assert shrinker.choices == expected\n\n\ndef test_zero_irregular_examples():\n    @shrinking_from((255,) * 6)\n    def shrinker(data: ConjectureData):\n        data.start_span(1)\n        data.draw_integer(0, 2**8 - 1)\n        data.draw_integer(0, 2**16 - 1)\n        data.stop_span()\n        data.start_span(1)\n        interesting = (\n            data.draw_integer(0, 2**8 - 1) > 0 and data.draw_integer(0, 2**16 - 1) > 0\n        )\n        data.stop_span()\n        if interesting:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.shrink()\n    assert shrinker.choices == (0,) * 2 + (1, 1)\n\n\ndef test_retain_end_of_buffer():\n    @shrinking_from((1, 2, 3, 4, 5, 6, 0))\n    def shrinker(data: ConjectureData):\n        interesting = False\n        while True:\n            n = data.draw_integer(0, 2**8 - 1)\n            if n == 6:\n                interesting = True\n            if n == 0:\n                break\n        if interesting:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.shrink()\n    assert shrinker.choices == (6, 0)\n\n\ndef test_can_expand_zeroed_region():\n    @shrinking_from((255,) * 5)\n    def shrinker(data: ConjectureData):\n        seen_non_zero = False\n        for _ in range(5):\n            if data.draw_integer(0, 2**8 - 1) == 0:\n                if seen_non_zero:\n                    data.mark_invalid()\n            else:\n                seen_non_zero = True\n        data.mark_interesting(interesting_origin())\n\n    shrinker.shrink()\n    assert shrinker.choices == (0,) * 5\n\n\ndef test_can_expand_deleted_region():\n    @shrinking_from((1, 2, 3, 4, 0, 0))\n    def shrinker(data: ConjectureData):\n        def t():\n            data.start_span(1)\n\n            data.start_span(1)\n            m = data.draw_integer(0, 2**8 - 1)\n            data.stop_span()\n\n            data.start_span(1)\n            n = data.draw_integer(0, 2**8 - 1)\n            data.stop_span()\n\n            data.stop_span()\n            return (m, n)\n\n        v1 = t()\n        if v1 == (1, 2):\n            if t() != (3, 4):\n                data.mark_invalid()\n        if v1 == (0, 0) or t() == (0, 0):\n            data.mark_interesting(interesting_origin())\n\n    shrinker.shrink()\n    assert shrinker.choices == (0, 0)\n\n\n@skipif_time_unpatched\ndef test_will_terminate_stalled_shrinks():\n    # Suppress the time based slow shrinking check - we only want\n    # the one that checks if we're in a stall where we've shrunk\n    # as far as we're going to get.\n    time.freeze()\n\n    @shrinking_from((255,) * 100)\n    def shrinker(data: ConjectureData):\n        count = 0\n\n        for _ in range(100):\n            if data.draw_integer(0, 2**8 - 1) != 255:\n                count += 1\n                if count >= 10:\n                    return\n        data.mark_interesting(interesting_origin())\n\n    shrinker.shrink()\n    assert shrinker.calls <= 1 + 2 * shrinker.max_stall\n\n\ndef test_will_let_fixate_shrink_passes_do_a_full_run_through():\n    @shrinking_from(list(range(50)))\n    def shrinker(data: ConjectureData):\n        for i in range(50):\n            if data.draw_integer(0, 2**8 - 1) != i:\n                data.mark_invalid()\n        data.mark_interesting(interesting_origin())\n\n    shrinker.max_stall = 5\n    passes = [shrinker.node_program(\"X\" * i) for i in range(1, 11)]\n    with pytest.raises(StopShrinking):\n        shrinker.fixate_shrink_passes(passes)\n\n    assert passes[-1].calls > 0\n\n\n@pytest.mark.parametrize(\"n_gap\", [0, 1, 2])\ndef test_can_simultaneously_lower_non_duplicated_nearby_integers(n_gap):\n    @shrinking_from((1, 1) + (0,) * n_gap + (2,))\n    def shrinker(data: ConjectureData):\n        # Block off lowering the whole buffer\n        if data.draw_integer(0, 2**1 - 1) == 0:\n            data.mark_invalid()\n        m = data.draw_integer(0, 2**8 - 1)\n        for _ in range(n_gap):\n            data.draw_integer(0, 2**8 - 1)\n        n = data.draw_integer(0, 2**16 - 1)\n\n        if n == m + 1:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.lower_integers_together)])\n    assert shrinker.choices == (1, 0) + (0,) * n_gap + (1,)\n\n\ndef test_redistribute_with_forced_node_integer():\n    @shrinking_from((15, 10))\n    def shrinker(data: ConjectureData):\n        n1 = data.draw_integer(0, 100)\n        n2 = data.draw_integer(0, 100, forced=10)\n        if n1 + n2 > 20:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.redistribute_numeric_pairs)])\n    # redistribute_numeric_pairs shouldn't try modifying forced nodes while\n    # shrinking. Since the second draw is forced, this isn't possible to shrink\n    # with just this pass.\n    assert shrinker.choices == (15, 10)\n\n\n@pytest.mark.parametrize(\"n\", [10, 50, 100, 200])\ndef test_can_quickly_shrink_to_trivial_collection(n):\n    @shrinking_from([b\"\\x01\" * n])\n    def shrinker(data: ConjectureData):\n        b = data.draw_bytes()\n        if len(b) >= n:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.minimize_individual_choices)])\n    assert shrinker.choices == (b\"\\x00\" * n,)\n    assert shrinker.calls < 10\n\n\ndef test_alternative_shrinking_will_lower_to_alternate_value():\n    # We want to reject the first integer value we see when shrinking\n    # this alternative, because it will be the result of transmuting the\n    # bytes value, and we want to ensure that we can find other values\n    # there when we detect the shape change.\n    seen_int = None\n\n    @shrinking_from((1, b\"hello world\"))\n    def shrinker(data: ConjectureData):\n        nonlocal seen_int\n        i = data.draw_integer(min_value=0, max_value=1)\n        if i == 1:\n            if data.draw_bytes():\n                data.mark_interesting(interesting_origin())\n        else:\n            n = data.draw_integer(0, 100)\n            if n == 0:\n                return\n            if seen_int is None:\n                seen_int = n\n            elif n != seen_int:\n                data.mark_interesting(interesting_origin())\n\n    shrinker.initial_coarse_reduction()\n    assert shrinker.choices[0] == 0\n\n\nclass BadShrinker(ShrinkerPass):\n    \"\"\"\n    A shrinker that really doesn't do anything at all. This is mostly a covering\n    test for the shrinker interface methods.\n    \"\"\"\n\n    def run_step(self):\n        return\n\n\ndef test_silly_shrinker_subclass():\n    assert BadShrinker.shrink(10, lambda _: True) == 10\n\n\nnumeric_nodes = nodes(choice_types=[\"integer\", \"float\"])\n\n\n@given(numeric_nodes, numeric_nodes, st.integers() | st.floats(allow_nan=False))\n@example(\n    ChoiceNode(\n        type=\"float\",\n        value=float(MAX_PRECISE_INTEGER - 1),\n        constraints=float_constr(),\n        was_forced=False,\n    ),\n    ChoiceNode(\n        type=\"float\",\n        value=float(MAX_PRECISE_INTEGER - 1),\n        constraints=float_constr(),\n        was_forced=False,\n    ),\n    0,\n)\n@settings(suppress_health_check=[HealthCheck.filter_too_much])\ndef test_redistribute_numeric_pairs(node1, node2, stop):\n    assume(node1.value + node2.value > stop)\n    # don't test extreme shrink_towards values, which lead to this test flaking\n    # from floating point errors\n    assume(abs(node1.constraints.get(\"shrink_towards\", 0)) <= 1e10)\n    assume(abs(node2.constraints.get(\"shrink_towards\", 0)) <= 1e10)\n    # avoid exhausting the tree while generating, which causes @shrinking_from's\n    # runner to raise\n    assume(\n        compute_max_children(node1.type, node1.constraints)\n        + compute_max_children(node2.type, node2.constraints)\n        > 2\n    )\n\n    @shrinking_from([node1.value, node2.value])\n    def shrinker(data: ConjectureData):\n        v1 = getattr(data, f\"draw_{node1.type}\")(**node1.constraints)\n        v2 = getattr(data, f\"draw_{node2.type}\")(**node2.constraints)\n        if v1 + v2 > stop:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.redistribute_numeric_pairs)])\n    assert len(shrinker.choices) == 2\n\n    shrink_towards = (\n        node1.constraints[\"shrink_towards\"] if node1.type == \"integer\" else 0\n    )\n    # we should always have brought the first choice closer to shrink_towards,\n    # or left the choices the same. And the values should sum to where they started.\n    assert abs(shrinker.choices[0] - shrink_towards) <= abs(\n        node1.value - shrink_towards\n    )\n    assert (\n        # pytest.approx for differences in floating-point summations\n        pytest.approx(shrinker.choices[0] + shrinker.choices[1], rel=0.001)\n        == node1.value + node2.value\n    )\n\n\n@pytest.mark.parametrize(\n    \"start, expected\",\n    [\n        ((\"1\" * 5, \"1\" * 5), (\"0\" * 5, \"0\" * 5)),\n        ((\"1222344\", \"1222344\"), (\"0\" * 7, \"0\" * 7)),\n    ],\n)\n@pytest.mark.parametrize(\"gap\", [0, 1, 2, 3])\ndef test_lower_duplicated_characters_across_choices(start, expected, gap):\n    # the draws from `gap` are irrelevant and only test that we can still shrink\n    # duplicated characters from nearby choices even when the choices are not\n    # consecutive.\n    @shrinking_from([start[0], *([0] * gap), start[1]])\n    def shrinker(data: ConjectureData):\n        s1 = data.draw(st.text())\n\n        for _ in range(gap):\n            data.draw(st.integers())\n\n        s2 = data.draw(st.text())\n        if s1 == s2:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.lower_duplicated_characters)])\n    assert shrinker.choices == (expected[0],) + (0,) * gap + (expected[1],)\n\n\ndef test_shrinking_one_of_with_same_shape():\n    # This is a covering test for our one_of shrinking logic for the case when\n    # the choice sequence *doesn't* change shape in the newly chosen one_of branch.\n    @shrinking_from([1, 0])\n    def shrinker(data: ConjectureData):\n        n = data.draw_integer(0, 1)\n        data.draw_integer()\n        if n == 1:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.initial_coarse_reduction()\n    assert shrinker.choices == (1, 0)\n\n\n@pytest.mark.parametrize(\"invert\", [False, True])  # cover the negative case\n@pytest.mark.parametrize(\n    \"min_value, max_value\", [(None, None), (None, 15), (-15, None), (-15, 15)]\n)\n@pytest.mark.parametrize(\n    \"shrink_towards, start\",\n    [\n        # straddles shrink_towards\n        (5, (2, 10)),\n        # both below shrink_towards\n        (5, (2, 4)),\n        # both above shrink_towards\n        (5, (8, 10)),\n        # exactly shrink_towards\n        (5, (5, 5)),\n    ],\n)\ndef test_redistribute_numeric_pairs_shrink_towards_explicit_integer(\n    min_value, max_value, shrink_towards, start, invert\n):\n    if invert:\n        shrink_towards = -shrink_towards\n        start = (-start[1], -start[0])\n\n    # redistributing should redistribute towards shrink_towards, not 0\n    target = start[0] + start[1]\n\n    @shrinking_from(start)\n    def shrinker(data: ConjectureData):\n        v1 = data.draw_integer(\n            shrink_towards=shrink_towards, min_value=min_value, max_value=max_value\n        )\n        v2 = data.draw_integer(\n            shrink_towards=shrink_towards, min_value=min_value, max_value=max_value\n        )\n        if v1 + v2 == target:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.redistribute_numeric_pairs)])\n    assert shrinker.choices == (shrink_towards, target - shrink_towards)\n\n\n@pytest.mark.parametrize(\"invert\", [False, True])\n@pytest.mark.parametrize(\n    \"start\",\n    [\n        (2.0, 10.0),\n        (2.0, 4.0),\n        (8.0, 10.0),\n        (5.0, 5.0),\n    ],\n)\ndef test_redistribute_numeric_pairs_shrink_towards_explicit_float(start, invert):\n    if invert:\n        start = (-start[1], -start[0])\n\n    target = start[0] + start[1]\n\n    @shrinking_from(start)\n    def shrinker(data: ConjectureData):\n        v1 = data.draw_float()\n        v2 = data.draw_float()\n        if v1 + v2 == target:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.redistribute_numeric_pairs)])\n    assert shrinker.choices == (0, target)\n\n\n@pytest.mark.parametrize(\n    \"shrink_towards, start\",\n    [\n        (5, (2, 10.0)),\n        (5, (2, 4.0)),\n        (5, (8, 10.0)),\n        (5, (5, 5.0)),\n    ],\n)\ndef test_redistribute_numeric_pairs_shrink_towards_explicit_combined(\n    shrink_towards, start\n):\n    # test case for one integer and one float draw. No `invert` parametrization\n    # because it moderately complicates things\n    target = start[0] + start[1]\n\n    @shrinking_from(start)\n    def shrinker(data: ConjectureData):\n        v1 = data.draw_integer(shrink_towards=shrink_towards)\n        v2 = data.draw_float()\n        if v1 + v2 == target:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.redistribute_numeric_pairs)])\n    assert shrinker.choices == (shrink_towards, target - shrink_towards)\n\n\n@given(st.data(), st.integers(), st.integers())\ndef test_redistribute_numeric_pairs_shrink_towards_integer(\n    data, target, shrink_towards\n):\n    start = data.draw(st.integers(max_value=target))\n    end = target - start\n\n    @shrinking_from([start, end])\n    def shrinker(data: ConjectureData):\n        v1 = data.draw_integer(shrink_towards=shrink_towards)\n        v2 = data.draw_integer(shrink_towards=shrink_towards)\n        if v1 + v2 == target:\n            data.mark_interesting(interesting_origin())\n\n    shrinker.fixate_shrink_passes([ShrinkPass(shrinker.redistribute_numeric_pairs)])\n    assert shrinker.choices == (shrink_towards, target - shrink_towards)\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_shrinking_interface.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom random import Random\n\nfrom hypothesis.internal.conjecture.shrinking import Integer\n\nfrom tests.common.utils import capture_out\n\n\ndef test_debug_output():\n    with capture_out() as o:\n        Integer.shrink(10, lambda x: True, debug=True, random=Random(0))\n\n    assert \"initial=10\" in o.getvalue()\n    assert \"shrinking to 0\" in o.getvalue()\n\n\ndef test_includes_name_in_repr_if_set():\n    assert (\n        repr(Integer(10, lambda x: True, name=\"hi there\", random=Random(0)))\n        == \"Integer('hi there', initial=10, current=10)\"\n    )\n\n\ndef test_normally_contains_no_space_for_name():\n    assert (\n        repr(Integer(10, lambda x: True, random=Random(0)))\n        == \"Integer(initial=10, current=10)\"\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_test_data.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport itertools\n\nimport pytest\n\nfrom hypothesis import strategies as st\nfrom hypothesis.errors import Frozen\nfrom hypothesis.internal.conjecture.data import (\n    MAX_DEPTH,\n    ConjectureData,\n    DataObserver,\n    Overrun,\n    Status,\n    StopTest,\n    structural_coverage,\n)\nfrom hypothesis.strategies import SearchStrategy\n\nfrom tests.conjecture.common import buffer_size_limit, interesting_origin\n\n\ndef test_cannot_draw_after_freeze():\n    d = ConjectureData.for_choices((True,))\n    d.draw_boolean()\n    d.freeze()\n    with pytest.raises(Frozen):\n        d.draw_boolean()\n\n\ndef test_can_double_freeze():\n    d = ConjectureData.for_choices([])\n    d.freeze()\n    assert d.frozen\n    d.freeze()\n    assert d.frozen\n\n\ndef test_draw_past_end_sets_overflow():\n    d = ConjectureData.for_choices((True,))\n\n    d.draw_boolean()\n    with pytest.raises(StopTest) as e:\n        d.draw_boolean()\n\n    assert e.value.testcounter == d.testcounter\n    assert d.frozen\n    assert d.status == Status.OVERRUN\n\n\ndef test_notes_repr():\n    d = ConjectureData.for_choices([])\n    d.note(b\"hi\")\n    assert repr(b\"hi\") in d.output\n\n\ndef test_can_mark_interesting():\n    d = ConjectureData.for_choices([])\n    with pytest.raises(StopTest):\n        d.mark_interesting(interesting_origin())\n    assert d.frozen\n    assert d.status == Status.INTERESTING\n\n\ndef test_can_mark_invalid():\n    d = ConjectureData.for_choices([])\n    with pytest.raises(StopTest):\n        d.mark_invalid()\n    assert d.frozen\n    assert d.status == Status.INVALID\n\n\ndef test_can_mark_invalid_with_why():\n    d = ConjectureData.for_choices([])\n    with pytest.raises(StopTest):\n        d.mark_invalid(\"some reason\")\n    assert d.frozen\n    assert d.status == Status.INVALID\n    assert d.events == {\"invalid because\": \"some reason\"}\n\n\nclass BoomStrategy(SearchStrategy):\n    def do_draw(self, data):\n        data.draw_boolean()\n        raise ValueError\n\n\ndef test_closes_interval_on_error_in_strategy():\n    d = ConjectureData.for_choices((True,))\n    with pytest.raises(ValueError):\n        d.draw(BoomStrategy())\n    d.freeze()\n    assert not any(eg.end is None for eg in d.spans)\n\n\nclass BigStrategy(SearchStrategy):\n    def do_draw(self, data):\n        data.draw_bytes(10**6, 10**6)\n\n\ndef test_does_not_double_freeze_in_interval_close():\n    d = ConjectureData.for_choices((b\"hi\",))\n    with pytest.raises(StopTest):\n        d.draw(BigStrategy())\n    assert d.frozen\n    assert not any(eg.end is None for eg in d.spans)\n\n\ndef test_triviality():\n    d = ConjectureData.for_choices((True, False, b\"1\"))\n\n    d.start_span(label=1)\n    d.draw(st.booleans())\n    d.draw(st.booleans())\n    d.stop_span()\n\n    d.start_span(label=2)\n    d.draw_bytes(1, 1, forced=bytes([2]))\n    d.stop_span()\n\n    d.freeze()\n\n    def trivial(u, v):\n        ex = next(ex for ex in d.spans if ex.start == u and ex.end == v)\n        return all(node.trivial for node in d.nodes[ex.start : ex.end])\n\n    assert not trivial(0, 2)\n    assert not trivial(0, 1)\n    assert trivial(1, 2)\n    assert trivial(2, 3)\n\n\ndef test_example_depth_marking():\n    d = ConjectureData.for_choices((0,) * 6)\n    d.draw(st.integers())  # v1\n    d.start_span(0)\n    d.draw(st.integers())  # v2\n    d.draw(st.integers())  # v3\n    d.stop_span()\n    d.draw(st.integers())  # v4\n    d.freeze()\n\n    assert len(d.spans) == 6\n\n    depths = [(ex.choice_count, ex.depth) for ex in d.spans]\n    assert depths == [\n        (4, 0),  # top\n        (1, 1),  # v1\n        (2, 1),  # inner\n        (1, 2),  # v2\n        (1, 2),  # v3\n        (1, 1),  # v4\n    ]\n\n\ndef test_has_examples_even_when_empty():\n    d = ConjectureData.for_choices([])\n    d.draw(st.just(False))\n    d.freeze()\n    assert d.spans\n\n\ndef test_has_cached_examples_even_when_overrun():\n    d = ConjectureData.for_choices((False,))\n    d.start_span(3)\n    d.draw_boolean()\n    d.stop_span()\n    try:\n        d.draw_boolean()\n    except StopTest:\n        pass\n    assert d.status == Status.OVERRUN\n    assert any(ex.label == 3 and ex.choice_count == 1 for ex in d.spans)\n    assert d.spans is d.spans\n\n\ndef test_can_observe_draws():\n    class LoggingObserver(DataObserver):\n        def __init__(self):\n            self.log = []\n\n        def draw_boolean(self, value: bool, *, was_forced: bool, constraints: dict):\n            self.log.append((\"draw_boolean\", value, was_forced))\n\n        def draw_integer(self, value: int, *, was_forced: bool, constraints: dict):\n            self.log.append((\"draw_integer\", value, was_forced))\n\n        def conclude_test(self, *args):\n            assert d.frozen\n            self.log.append((\"concluded\", *args))\n\n    observer = LoggingObserver()\n    d = ConjectureData.for_choices((True, 1, 3), observer=observer)\n\n    origin = interesting_origin()\n    d.draw_boolean()\n    d.draw_integer(0, 2**7 - 1, forced=10)\n    d.draw_integer(0, 2**8 - 1)\n    with pytest.raises(StopTest):\n        d.conclude_test(Status.INTERESTING, interesting_origin=origin)\n\n    assert observer.log == [\n        (\"draw_boolean\", True, False),\n        (\"draw_integer\", 10, True),\n        (\"draw_integer\", 3, False),\n        (\"concluded\", Status.INTERESTING, origin),\n    ]\n\n\ndef test_calls_concluded_implicitly():\n    class NoteConcluded(DataObserver):\n        def conclude_test(self, status, reason):\n            assert d.frozen\n            self.conclusion = (status, reason)\n\n    observer = NoteConcluded()\n\n    d = ConjectureData.for_choices((True,), observer=observer)\n    d.draw_boolean()\n    d.freeze()\n\n    assert observer.conclusion == (Status.VALID, None)\n\n\ndef test_examples_show_up_as_discarded():\n    d = ConjectureData.for_choices((True, False, True))\n\n    d.start_span(1)\n    d.draw_boolean()\n    d.stop_span(discard=True)\n    d.start_span(1)\n    d.draw_boolean()\n    d.stop_span()\n    d.freeze()\n\n    assert len([ex for ex in d.spans if ex.discarded]) == 1\n\n\ndef test_examples_support_negative_indexing():\n    d = ConjectureData.for_choices((True, True))\n    d.draw(st.booleans())\n    d.draw(st.booleans())\n    d.freeze()\n    assert d.spans[-1].choice_count == 1\n\n\ndef test_examples_out_of_bounds_index():\n    d = ConjectureData.for_choices((False,))\n    d.draw(st.booleans())\n    d.freeze()\n    with pytest.raises(IndexError):\n        d.spans[10]\n\n\ndef test_can_override_label():\n    d = ConjectureData.for_choices((False,))\n    d.draw(st.booleans(), label=7)\n    d.freeze()\n    assert any(ex.label == 7 for ex in d.spans)\n\n\ndef test_will_mark_too_deep_examples_as_invalid():\n    d = ConjectureData.for_choices((0,))\n\n    s = st.integers()\n    for _ in range(MAX_DEPTH + 1):\n        s = s.map(lambda x: None)\n\n    with pytest.raises(StopTest):\n        d.draw(s)\n    assert d.status == Status.INVALID\n\n\ndef test_empty_strategy_is_invalid():\n    d = ConjectureData.for_choices([])\n    with pytest.raises(StopTest):\n        d.draw(st.nothing())\n    assert d.status == Status.INVALID\n\n\ndef test_can_note_non_str():\n    d = ConjectureData.for_choices([])\n    x = object()\n    d.note(x)\n    assert repr(x) in d.output\n\n\ndef test_can_note_str_as_non_repr():\n    d = ConjectureData.for_choices([])\n    d.note(\"foo\")\n    assert d.output == \"foo\"\n\n\ndef test_result_is_overrun():\n    d = ConjectureData.for_choices([])\n    with pytest.raises(StopTest):\n        d.draw_boolean()\n    assert d.as_result() is Overrun\n\n\ndef test_trivial_before_force_agrees_with_trivial_after():\n    d = ConjectureData.for_choices((False, True, True))\n    d.draw_boolean()\n    d.draw_boolean(forced=True)\n    d.draw_boolean()\n\n    t1 = [d.nodes[i].trivial for i in range(3)]\n    d.freeze()\n    r = d.as_result()\n    t2 = [n.trivial for n in r.nodes]\n    t3 = [r.nodes[i].trivial for i in range(3)]\n\n    assert t1 == t2 == t3\n\n\ndef test_events_are_noted():\n    d = ConjectureData.for_choices([])\n    d.events[\"hello\"] = \"\"\n    assert \"hello\" in d.events\n\n\ndef test_child_indices():\n    d = ConjectureData.for_choices((True,) * 4)\n\n    d.start_span(0)  # examples[1]\n    d.start_span(1)  # examples[2]\n    d.draw(st.booleans())  # examples[3] (st.booleans)\n    d.draw(st.booleans())  # examples[4] (st.booleans)\n    d.stop_span()\n    d.stop_span()\n    d.draw(st.booleans())  # examples[5] (st.booleans)\n    d.draw(st.booleans())  # examples[6] (st.booleans)\n    d.freeze()\n\n    assert list(d.spans.children[0]) == [1, 5, 6]\n    assert list(d.spans.children[1]) == [2]\n    assert list(d.spans.children[2]) == [3, 4]\n\n    assert d.spans[0].parent is None\n    for ex in list(d.spans)[1:]:\n        assert ex in d.spans[ex.parent].children\n\n\ndef test_example_equality():\n    d = ConjectureData.for_choices((False, False))\n\n    d.start_span(0)\n    d.draw_boolean()\n    d.stop_span()\n    d.start_span(0)\n    d.draw_boolean()\n    d.stop_span()\n    d.freeze()\n\n    examples = list(d.spans)\n    for ex1, ex2 in itertools.combinations(examples, 2):\n        assert ex1 != ex2\n        assert not (ex1 == ex2)  # noqa\n\n    for ex in examples:\n        assert ex == ex\n        assert not (ex != ex)  # noqa\n\n        assert not (ex == \"hello\")  # noqa\n        assert ex != \"hello\"\n\n\ndef test_structural_coverage_is_cached():\n    assert structural_coverage(50) is structural_coverage(50)\n\n\ndef test_examples_create_structural_coverage():\n    data = ConjectureData.for_choices([])\n    data.start_span(42)\n    data.stop_span()\n    data.freeze()\n    assert structural_coverage(42) in data.tags\n\n\ndef test_discarded_examples_do_not_create_structural_coverage():\n    data = ConjectureData.for_choices([])\n    data.start_span(42)\n    data.stop_span(discard=True)\n    data.freeze()\n    assert structural_coverage(42) not in data.tags\n\n\ndef test_children_of_discarded_examples_do_not_create_structural_coverage():\n    data = ConjectureData.for_choices([])\n    data.start_span(10)\n    data.start_span(42)\n    data.stop_span()\n    data.stop_span(discard=True)\n    data.freeze()\n    assert structural_coverage(42) not in data.tags\n    assert structural_coverage(10) not in data.tags\n\n\ndef test_overruns_at_exactly_max_length():\n    with buffer_size_limit(1):\n        data = ConjectureData(prefix=[True], random=None, max_choices=1)\n        data.draw_boolean()\n        try:\n            data.draw_boolean()\n        except StopTest:\n            pass\n        assert data.status is Status.OVERRUN\n"
  },
  {
    "path": "hypothesis-python/tests/conjecture/test_utils.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom fractions import Fraction\n\nimport pytest\n\nfrom hypothesis import (\n    HealthCheck,\n    Phase,\n    assume,\n    example,\n    given,\n    settings,\n    strategies as st,\n)\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.conjecture import utils as cu\nfrom hypothesis.internal.conjecture.data import ConjectureData, Status, StopTest\nfrom hypothesis.internal.coverage import IN_COVERAGE_TESTS\n\ntry:\n    import numpy as np\nexcept ImportError:\n    np = None\n\n\ndef test_drawing_certain_coin_still_writes():\n    data = ConjectureData.for_choices([True])\n    assert data.draw_boolean(1)\n    assert data.choices == (True,)\n\n\ndef test_drawing_impossible_coin_still_writes():\n    data = ConjectureData.for_choices([False])\n    assert not data.draw_boolean(0)\n    assert data.choices == (False,)\n\n\ndef test_draws_extremely_small_p():\n    data = ConjectureData.for_choices((True,))\n    assert data.draw_boolean(0.5**65)\n\n\n@example([Fraction(1, 3), Fraction(1, 3), Fraction(1, 3)])\n@example([Fraction(1, 1), Fraction(1, 2)])\n@example([Fraction(1, 2), Fraction(4, 10)])\n@example([Fraction(1, 1), Fraction(3, 5), Fraction(1, 1)])\n@example([Fraction(2, 257), Fraction(2, 5), Fraction(1, 11)])\n@example([0, 2, 47])\n@settings(\n    deadline=None,\n    suppress_health_check=list(HealthCheck),\n    phases=[Phase.explicit] if IN_COVERAGE_TESTS else settings.default.phases,\n)\n@given(st.lists(st.fractions(min_value=0, max_value=1), min_size=1))\ndef test_sampler_distribution(weights):\n    total = sum(weights)\n    n = len(weights)\n\n    assume(total > 0)\n\n    probabilities = [w / total for w in weights]\n\n    sampler = cu.Sampler(weights)\n\n    calculated = [Fraction(0)] * n\n    for base, alternate, p_alternate in sampler.table:\n        calculated[base] += (1 - p_alternate) / n\n        calculated[alternate] += p_alternate / n\n\n    for expected, actual in zip(probabilities, calculated, strict=True):\n        if isinstance(actual, Fraction):\n            assert expected == actual\n        else:\n            assert abs(expected - actual) < 0.001\n\n\ndef test_sampler_does_not_draw_minimum_if_zero():\n    sampler = cu.Sampler([0, 2, 47])\n    assert sampler.sample(ConjectureData.for_choices([0, 0])) != 0\n\n\ndef test_sampler_shrinks():\n    sampler = cu.Sampler([4.0, 8.0, 1.0, 1.0, 0.5])\n    assert sampler.sample(ConjectureData.for_choices([0] * 3)) == 0\n\n\ndef test_can_force_sampler():\n    sampler = cu.Sampler([0.5, 0.5])\n    cd = ConjectureData.for_choices([0] * 100)\n    assert sampler.sample(cd, forced=0) == 0\n    assert sampler.sample(cd, forced=1) == 1\n\n\ndef test_combine_labels_is_distinct():\n    x = 10\n    y = 100\n    assert cu.combine_labels(x, y) not in (x, y)\n\n\n@given(st.integers())\ndef test_combine_labels_is_identity_for_single_argument(n):\n    assert cu.combine_labels(n) == n\n\n\n@pytest.mark.skipif(np is None, reason=\"requires Numpy\")\ndef test_invalid_numpy_sample():\n    with pytest.raises(InvalidArgument):\n        cu.check_sample(np.array([[1, 1], [1, 1]]), \"array\")\n\n\n@pytest.mark.skipif(np is None, reason=\"requires Numpy\")\ndef test_valid_numpy_sample():\n    cu.check_sample(np.array([1, 2, 3]), \"array\")\n\n\ndef test_invalid_set_sample():\n    with pytest.raises(InvalidArgument):\n        cu.check_sample({1, 2, 3}, \"array\")\n\n\ndef test_valid_list_sample():\n    cu.check_sample([1, 2, 3], \"array\")\n\n\ndef test_choice():\n    assert ConjectureData.for_choices([1]).choice([1, 2, 3]) == 2\n\n\ndef test_fixed_size_draw_many():\n    many = cu.many(\n        ConjectureData.for_choices([]), min_size=3, max_size=3, average_size=3\n    )\n    assert many.more()\n    assert many.more()\n    assert many.more()\n    assert not many.more()\n\n\ndef test_astronomically_unlikely_draw_many():\n    # Our internal helper doesn't underflow to zero or negative, but nor\n    # will we ever generate an element for such a low average size.\n    data = ConjectureData.for_choices((True,) * 1000)\n    many = cu.many(data, min_size=0, max_size=10, average_size=1e-5)\n    assert many.more()\n\n\ndef test_rejection_eventually_terminates_many():\n    many = cu.many(\n        ConjectureData.for_choices((True,) * 1000),\n        min_size=0,\n        max_size=1000,\n        average_size=100,\n    )\n    count = 0\n\n    while many.more():\n        count += 1\n        many.reject()\n\n    assert count <= 100\n\n\ndef test_rejection_eventually_terminates_many_invalid_for_min_size():\n    data = ConjectureData.for_choices((True,) * 1000)\n    many = cu.many(data, min_size=1, max_size=1000, average_size=100)\n\n    with pytest.raises(StopTest):\n        while many.more():\n            many.reject()\n\n    assert data.status == Status.INVALID\n\n\ndef test_many_with_min_size():\n    many = cu.many(\n        ConjectureData.for_choices((False,) * 5),\n        min_size=2,\n        average_size=10,\n        max_size=1000,\n    )\n    assert many.more()\n    assert many.more()\n    assert not many.more()\n\n\ndef test_many_with_max_size():\n    many = cu.many(\n        ConjectureData.for_choices((True,) * 5), min_size=0, average_size=1, max_size=2\n    )\n    assert many.more()\n    assert many.more()\n    assert not many.more()\n\n\ndef test_samples_from_a_range_directly():\n    s = cu.check_sample(range(10**1000), \"\")\n    assert isinstance(s, range)\n\n\ndef test_p_continue_to_average_saturates():\n    assert cu._p_continue_to_avg(1.1, 100) == 100\n\n\ndef test_unhashable_calc_label():\n\n    class Unhashable:\n        def __call__(self):\n            return None\n\n        def __hash__(self):\n            raise TypeError\n\n    c1 = Unhashable()\n    c2 = Unhashable()\n\n    with pytest.raises(TypeError):\n        assert cu.calc_label_from_hash(c1) == cu.calc_label_from_hash(c2)\n    assert cu.calc_label_from_callable(c1) == cu.calc_label_from_callable(c2)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_annotations.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom inspect import Parameter as P, signature\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.internal.reflection import (\n    convert_positional_arguments,\n    define_function_signature,\n    get_pretty_function_description,\n)\n\n\n@given(st.integers())\ndef test_has_an_annotation(i: int):\n    pass\n\n\ndef universal_acceptor(*args, **kwargs):\n    return args, kwargs\n\n\ndef has_annotation(a: int, *b, c=2) -> None:\n    pass\n\n\n@pytest.mark.parametrize(\"f\", [has_annotation, lambda *, a: a, lambda *, a=1: a])\ndef test_copying_preserves_signature(f):\n    af = signature(f)\n    t = define_function_signature(\"foo\", \"docstring\", af)(universal_acceptor)\n    at = signature(t)\n    assert af.parameters == at.parameters\n\n\n@pytest.mark.parametrize(\n    \"lam,source\",\n    [\n        ((lambda *z, a: a), \"lambda *z, a: a\"),\n        ((lambda *z, a=1: a), \"lambda *z, a=1: a\"),\n        ((lambda *, a: a), \"lambda *, a: a\"),\n        ((lambda *, a=1: a), \"lambda *, a=1: a\"),\n        ((lambda **kw: kw), \"lambda **kw: kw\"),\n    ],\n)\ndef test_kwonly_lambda_formatting(lam, source):\n    # Testing kwonly lambdas, with and without varargs and default values\n    assert get_pretty_function_description(lam) == source\n\n\ndef test_given_notices_missing_kwonly_args():\n    @given(a=st.none())\n    def reqs_kwonly(*, a, b):\n        pass\n\n    with pytest.raises(TypeError):\n        reqs_kwonly()\n    reqs_kwonly(b=None)\n\n\ndef test_converter_handles_kwonly_args():\n    def f(*, a, b=2):\n        pass\n\n    out = convert_positional_arguments(f, (), {\"a\": 1})\n    assert out == ((), {\"a\": 1})\n\n\ndef test_converter_notices_missing_kwonly_args():\n    def f(*, a, b=2):\n        pass\n\n    with pytest.raises(TypeError):\n        assert convert_positional_arguments(f, (), {})\n\n\ndef to_wrap_with_composite(draw: None, strat: float, nothing: list) -> int:\n    return draw(st.none())\n\n\ndef return_annot() -> int:\n    return 4  # per RFC 1149.5 / xckd 221\n\n\ndef first_annot(draw: None):\n    pass\n\n\ndef test_composite_edits_annotations():\n    sig_comp = signature(st.composite(to_wrap_with_composite))\n    assert sig_comp.return_annotation == st.SearchStrategy[int]\n    assert sig_comp.parameters[\"nothing\"].annotation is not P.empty\n    assert \"draw\" not in sig_comp.parameters\n\n\n@pytest.mark.parametrize(\"nargs\", [1, 2, 3])\ndef test_given_edits_annotations(nargs):\n    sig_given = signature(given(*(nargs * [st.none()]))(to_wrap_with_composite))\n    assert sig_given.return_annotation is None\n    assert len(sig_given.parameters) == 3 - nargs\n    assert all(p.annotation is not P.empty for p in sig_given.parameters.values())\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_arbitrary_data.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\nfrom pytest import raises\n\nfrom hypothesis import find, given, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument\n\n\n@given(st.integers(), st.data())\ndef test_conditional_draw(x, data):\n    y = data.draw(st.integers(min_value=x))\n    assert y >= x\n\n\ndef test_prints_on_failure():\n    @given(st.data())\n    def test(data):\n        x = data.draw(st.lists(st.integers(0, 10), min_size=2))\n        y = data.draw(st.sampled_from(x))\n        x.remove(y)\n        if y in x:\n            raise ValueError\n\n    with raises(ValueError) as err:\n        test()\n    assert \"Draw 1: [0, 0]\" in err.value.__notes__\n    assert \"Draw 2: 0\" in err.value.__notes__\n\n\ndef test_prints_labels_if_given_on_failure():\n    @given(st.data())\n    def test(data):\n        x = data.draw(st.lists(st.integers(0, 10), min_size=2), label=\"Some numbers\")\n        y = data.draw(st.sampled_from(x), label=\"A number\")\n        assert y in x\n        x.remove(y)\n        assert y not in x\n\n    with raises(AssertionError) as err:\n        test()\n    assert \"Draw 1 (Some numbers): [0, 0]\" in err.value.__notes__\n    assert \"Draw 2 (A number): 0\" in err.value.__notes__\n\n\ndef test_given_twice_is_same():\n    @given(st.data(), st.data())\n    def test(data1, data2):\n        data1.draw(st.integers())\n        data2.draw(st.integers())\n        raise ValueError\n\n    with raises(ValueError) as err:\n        test()\n    assert \"Draw 1: 0\" in err.value.__notes__\n    assert \"Draw 2: 0\" in err.value.__notes__\n\n\n# `find` doesn't seem to be thread-safe, though I don't actually see why not\n@pytest.mark.xfail(\n    settings._current_profile == \"threading\", strict=False, reason=\"not thread-safe?\"\n)\ndef test_data_supports_find():\n    data = find(st.data(), lambda data: data.draw(st.integers()) >= 10)\n    assert data.conjecture_data.choices == (10,)\n\n\n@pytest.mark.parametrize(\"f\", [\"filter\", \"map\", \"flatmap\"])\ndef test_errors_when_normal_strategy_functions_are_used(f):\n    with raises(InvalidArgument):\n        getattr(st.data(), f)(lambda x: 1)\n\n\ndef test_nice_repr():\n    assert repr(st.data()) == \"data()\"\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_asyncio.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport asyncio\nimport warnings\nfrom unittest import TestCase\n\nimport pytest\n\nfrom hypothesis import assume, given, settings, strategies as st\nfrom hypothesis.internal.compat import PYPY\n\nfrom tests.common.utils import skipif_emscripten\n\npytestmark = pytest.mark.skipif(\n    settings.get_current_profile_name() == \"threading\",\n    reason=\"bad interactions when mixing threads and asyncio\",\n)\n\n\ndef coro_decorator(f):\n    with warnings.catch_warnings():\n        warnings.simplefilter(action=\"ignore\", category=DeprecationWarning)\n        try:\n            return asyncio.coroutine(f)\n        except AttributeError:\n            pytest.skip(\"needs fixing for asyncio version\", allow_module_level=True)\n\n\nclass TestAsyncio(TestCase):\n    timeout = 5\n\n    def setUp(self):\n        self.loop = asyncio.new_event_loop()\n        asyncio.set_event_loop(self.loop)\n\n    def tearDown(self):\n        self.loop.close()\n\n    def execute_example(self, f):\n        error = None\n\n        def g():\n            nonlocal error\n            try:\n                x = f()\n                if x is not None:\n                    yield from x\n            except BaseException as e:\n                error = e\n\n        coro = coro_decorator(g)\n        future = asyncio.wait_for(coro(), timeout=self.timeout)\n        self.loop.run_until_complete(future)\n        if error is not None:\n            raise error\n\n    @pytest.mark.skipif(PYPY, reason=\"Error in asyncio.new_event_loop()\")\n    @given(x=st.text())\n    @coro_decorator\n    def test_foo(self, x):\n        assume(x)\n        yield from asyncio.sleep(0.001)\n        assert x\n\n\nclass TestAsyncioRun(TestCase):\n    # In principle, these tests could indeed run on emscripten if we grab the existing\n    # event loop and run them there.  However, that seems to have hit an infinite loop\n    # and so we're just skipping them for now and will revisit later.\n\n    def execute_example(self, f):\n        asyncio.run(f())\n\n    @skipif_emscripten\n    @given(x=st.text())\n    @coro_decorator\n    def test_foo_yield_from(self, x):\n        assume(x)\n        yield from asyncio.sleep(0.001)\n        assert x\n\n    @skipif_emscripten\n    @given(st.text())\n    async def test_foo_await(self, x):\n        assume(x)\n        await asyncio.sleep(0.001)\n        assert x\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_cache_implementation.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport threading\nfrom functools import partial\nfrom random import Random\n\nimport pytest\n\nfrom hypothesis import (\n    HealthCheck,\n    assume,\n    example,\n    given,\n    note,\n    settings,\n    strategies as st,\n)\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.cache import GenericCache, LRUCache, LRUReusedCache\n\nfrom tests.common.utils import Why, skipif_emscripten, xfail_on_crosshair\n\n\nclass LRUCacheAlternative(GenericCache):\n    __slots__ = (\"__tick\",)\n\n    def __init__(self, max_size):\n        super().__init__(max_size)\n        self.__tick = 0\n\n    def new_entry(self, key, value):\n        return self.tick()\n\n    def on_access(self, key, value, score):\n        return self.tick()\n\n    def tick(self):\n        self.__tick += 1\n        return self.__tick\n\n\nclass LFUCache(GenericCache):\n    def new_entry(self, key, value):\n        return 1\n\n    def on_access(self, key, value, score):\n        return score + 1\n\n\n@st.composite\ndef write_pattern(draw, min_distinct_keys=0):\n    keys = draw(\n        st.lists(st.integers(0, 1000), unique=True, min_size=max(min_distinct_keys, 1))\n    )\n    values = draw(st.lists(st.integers(), unique=True, min_size=1))\n    s = st.lists(\n        st.tuples(st.sampled_from(keys), st.sampled_from(values)),\n        min_size=min_distinct_keys,\n    )\n    if min_distinct_keys > 0:\n        s = s.filter(lambda ls: len({k for k, _ in ls}) >= min_distinct_keys)\n    return draw(s)\n\n\nclass ValueScored(GenericCache):\n    def new_entry(self, key, value):\n        return value\n\n\nclass RandomCache(GenericCache):\n    def __init__(self, max_size):\n        super().__init__(max_size)\n        self.random = Random(0)\n\n    def new_entry(self, key, value):\n        return self.random.random()\n\n    def on_access(self, key, value, score):\n        return self.random.random()\n\n\n@pytest.mark.parametrize(\n    \"implementation\",\n    [LRUCache, LFUCache, LRUReusedCache, ValueScored, RandomCache, LRUCacheAlternative],\n)\n@example(writes=[(0, 0), (3, 0), (1, 0), (2, 0), (2, 0), (1, 0)], size=4)\n@example(writes=[(0, 0)], size=1)\n@example(writes=[(1, 0), (2, 0), (0, -1), (1, 0)], size=3)\n@given(write_pattern(), st.integers(1, 10))\ndef test_behaves_like_a_dict_with_losses(implementation, writes, size):\n    model = {}\n    target = implementation(max_size=size)\n\n    for k, v in writes:\n        try:\n            assert model[k] == target[k]\n        except KeyError:\n            pass\n        model[k] = v\n        target[k] = v\n        target.check_valid()\n        assert target[k] == v\n        for r, s in model.items():\n            try:\n                assert s == target[r]\n            except KeyError:\n                pass\n        assert len(target) <= min(len(model), size)\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)\n@settings(\n    suppress_health_check={HealthCheck.too_slow}\n    | set(settings().suppress_health_check),\n    deadline=None,\n)\n@given(write_pattern(min_distinct_keys=2), st.data())\ndef test_always_evicts_the_lowest_scoring_value(writes, data):\n    scores = {}\n\n    n_keys = len({k for k, _ in writes})\n\n    assume(n_keys > 1)\n\n    size = data.draw(st.integers(1, n_keys - 1))\n\n    evicted = set()\n\n    def new_score(key):\n        scores[key] = data.draw(st.integers(0, 1000), label=f\"scores[{key!r}]\")\n        return scores[key]\n\n    last_entry = None\n\n    class Cache(GenericCache):\n        def new_entry(self, key, value):\n            nonlocal last_entry\n            last_entry = key\n            evicted.discard(key)\n            assert key not in scores\n            return new_score(key)\n\n        def on_access(self, key, value, score):\n            assert key in scores\n            return new_score(key)\n\n        def on_evict(self, key, value, score):\n            note(f\"Evicted {key!r}\")\n            assert score == scores[key]\n            del scores[key]\n            if len(scores) > 1:\n                assert score <= min(v for k, v in scores.items() if k != last_entry)\n            evicted.add(key)\n\n    target = Cache(max_size=size)\n    model = {}\n\n    for k, v in writes:\n        target[k] = v\n        model[k] = v\n\n    assert evicted\n    assert len(evicted) + len(target) == len(model)\n    assert len(scores) == len(target)\n\n    for k, v in model.items():\n        try:\n            assert target[k] == v\n            assert k not in evicted\n        except KeyError:\n            assert k in evicted\n\n\ndef test_basic_access():\n    cache = ValueScored(max_size=2)\n    cache[1] = 0\n    cache[1] = 0\n    cache[0] = 1\n    cache[2] = 0\n    assert cache[2] == 0\n    assert cache[0] == 1\n    assert len(cache) == 2\n\n\ndef test_can_clear_a_cache():\n    x = ValueScored(1)\n    x[0] = 1\n    assert len(x) == 1\n    x.clear()\n    assert len(x) == 0\n\n\ndef test_max_size_must_be_positive():\n    with pytest.raises(InvalidArgument):\n        ValueScored(max_size=0)\n\n\ndef test_pinning_prevents_eviction():\n    cache = LRUReusedCache(max_size=10)\n    cache.pin(20, 1)\n    for i in range(20):\n        cache[i] = 0\n    assert cache[20] == 1\n\n\ndef test_unpinning_allows_eviction():\n    cache = LRUReusedCache(max_size=10)\n    cache.pin(20, True)\n    for i in range(20):\n        cache[i] = False\n\n    assert 20 in cache\n\n    cache.unpin(20)\n    cache[21] = False\n\n    assert 20 not in cache\n\n\ndef test_unpins_must_match_pins():\n    cache = LRUReusedCache(max_size=2)\n    cache.pin(1, 1)\n    assert cache.is_pinned(1)\n    assert cache[1] == 1\n    cache.pin(1, 2)\n    assert cache.is_pinned(1)\n    assert cache[1] == 2\n    cache.unpin(1)\n    assert cache.is_pinned(1)\n    assert cache[1] == 2\n    cache.unpin(1)\n    assert not cache.is_pinned(1)\n\n\ndef test_will_error_instead_of_evicting_pin():\n    cache = LRUReusedCache(max_size=1)\n    cache.pin(1, 1)\n    with pytest.raises(ValueError):\n        cache[2] = 2\n\n    assert 1 in cache\n    assert 2 not in cache\n\n\ndef test_will_error_for_bad_unpin():\n    cache = LRUReusedCache(max_size=1)\n    cache[1] = 1\n    with pytest.raises(ValueError):\n        cache.unpin(1)\n\n\ndef test_still_inserts_if_score_is_worse():\n    class TC(GenericCache):\n        def new_entry(self, key, value):\n            return key\n\n    cache = TC(1)\n\n    cache[0] = 1\n    cache[1] = 1\n\n    assert 0 not in cache\n    assert 1 in cache\n    assert len(cache) == 1\n\n\ndef test_does_insert_if_score_is_better():\n    class TC(GenericCache):\n        def new_entry(self, key, value):\n            return value\n\n    cache = TC(1)\n\n    cache[0] = 1\n    cache[1] = 0\n\n    assert 0 not in cache\n    assert 1 in cache\n    assert len(cache) == 1\n\n\ndef test_double_pinning_does_not_add_entry():\n    cache = LRUReusedCache(2)\n    cache.pin(0, 0)\n    cache.pin(0, 1)\n    cache[1] = 1\n    assert len(cache) == 2\n\n\ndef test_can_add_new_keys_after_unpinning():\n    cache = LRUReusedCache(1)\n    cache.pin(0, 0)\n    cache.unpin(0)\n    cache[1] = 1\n    assert len(cache) == 1\n    assert 1 in cache\n\n\ndef test_iterates_over_remaining_keys():\n    cache = LRUReusedCache(2)\n    for i in range(3):\n        cache[i] = \"hi\"\n    assert sorted(cache) == [1, 2]\n\n\ndef test_lru_cache_is_actually_lru():\n    cache = LRUCache(2)\n    cache[1] = 1  # [1]\n    cache[2] = 2  # [1, 2]\n    cache[1]  # [2, 1]\n    cache[3] = 2  # [2, 1, 3] -> drop least recently used -> [1, 3]\n    assert list(cache) == [1, 3]\n\n\n@skipif_emscripten\ndef test_cache_is_threadsafe_issue_2433_regression():\n    errors = []\n\n    def target():\n        for _ in range(1000):\n            try:\n                st.builds(partial(str))\n            except Exception as exc:\n                errors.append(exc)\n\n    workers = [threading.Thread(target=target) for _ in range(4)]\n    for worker in workers:\n        worker.start()\n    for worker in workers:\n        worker.join()\n\n    assert not errors\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_caching.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import strategies as st\nfrom hypothesis.errors import InvalidArgument\n\n\ndef test_no_args():\n    assert st.text() is st.text()\n\n\ndef test_tuple_lengths():\n    assert st.tuples(st.integers()) is st.tuples(st.integers())\n    assert st.tuples(st.integers()) is not st.tuples(st.integers(), st.integers())\n\n\ndef test_values():\n    assert st.integers() is not st.integers(min_value=1)\n\n\ndef test_alphabet_key():\n    assert st.text(alphabet=\"abcs\") is st.text(alphabet=\"abcs\")\n\n\ndef test_does_not_error_on_unhashable_posarg():\n    st.text([\"a\", \"b\", \"c\"])\n\n\ndef test_does_not_error_on_unhashable_kwarg():\n    with pytest.raises(InvalidArgument):\n        st.builds(lambda alphabet: 1, alphabet=[\"a\", \"b\", \"c\"]).validate()\n\n\ndef test_caches_floats_sensitively():\n    assert st.floats(min_value=0.0) is st.floats(min_value=0.0)\n    assert st.floats(min_value=0.0) is not st.floats(min_value=0)\n    assert st.floats(min_value=0.0) is not st.floats(min_value=-0.0)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_cathetus.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nimport sys\nfrom sys import float_info\n\nimport pytest\n\nfrom hypothesis import assume, given\nfrom hypothesis.internal.cathetus import cathetus\nfrom hypothesis.strategies import floats\n\n\ndef test_cathetus_subnormal_underflow():\n    u = sys.float_info.min * sys.float_info.epsilon\n    h = 5 * u\n    a = 4 * u\n    assert cathetus(h, a) == 3 * u\n\n\ndef test_cathetus_simple_underflow():\n    a = sys.float_info.min\n    h = a * math.sqrt(2)\n    b = cathetus(h, a)\n    assert b > 0, f\"expecting positive cathetus({h:g}, {a:g}), got {b:g}\"\n\n\ndef test_cathetus_huge_no_overflow():\n    h = sys.float_info.max\n    a = h / math.sqrt(2)\n    b = cathetus(h, a)\n    assert math.isfinite(b), f\"expecting finite cathetus({h:g}, {a:g}), got {b:g}\"\n\n\ndef test_cathetus_large_no_overflow():\n    h = sys.float_info.max / 3\n    a = h / math.sqrt(2)\n    b = cathetus(h, a)\n    assert math.isfinite(b), f\"expecting finite cathetus({h:g}, {a:g}), got {b:g}\"\n\n\n@pytest.mark.parametrize(\n    \"h,a\",\n    [\n        # NaN hypot\n        (math.nan, 3),\n        (math.nan, 0),\n        (math.nan, math.inf),\n        (math.nan, math.nan),\n        # Infeasible\n        (2, 3),\n        (2, -3),\n        (2, math.inf),\n        (2, math.nan),\n        # Surprisingly consistent with c99 hypot()\n        (math.inf, math.inf),\n    ],\n)\ndef test_cathetus_nan(h, a):\n    assert math.isnan(cathetus(h, a))\n\n\n@pytest.mark.parametrize(\n    \"h,a\", [(math.inf, 3), (math.inf, -3), (math.inf, 0), (math.inf, math.nan)]\n)\ndef test_cathetus_infinite(h, a):\n    assert math.isinf(cathetus(h, a))\n\n\n@pytest.mark.parametrize(\n    \"h,a,b\", [(-5, 4, 3), (5, -4, 3), (-5, -4, 3), (0, 0, 0), (1, 0, 1)]\n)\ndef test_cathetus_signs(h, a, b):\n    assert abs(cathetus(h, a) - b) <= abs(b) * float_info.epsilon\n\n\n@given(\n    h=floats(0) | floats(min_value=1e308, allow_infinity=False),\n    a=floats(0, allow_infinity=False)\n    | floats(min_value=0, max_value=1e250, allow_infinity=False),\n)\ndef test_cathetus_always_leq_hypot(h, a):\n    assume(h >= a)\n    b = cathetus(h, a)\n    assert 0 <= b <= h\n\n\n@pytest.mark.parametrize(\n    \"a,b,h\",\n    [\n        (3, 4, 5),\n        (5, 12, 13),\n        (8, 15, 17),\n        (7, 24, 25),\n        (20, 21, 29),\n        (12, 35, 37),\n        (9, 40, 41),\n        (28, 45, 53),\n        (11, 60, 61),\n        (16, 63, 65),\n        (33, 56, 65),\n        (48, 55, 73),\n        (13, 84, 85),\n        (36, 77, 85),\n        (39, 80, 89),\n        (65, 72, 97),\n        (20, 99, 101),\n        (60, 91, 109),\n        (15, 112, 113),\n        (44, 117, 125),\n        (88, 105, 137),\n        (17, 144, 145),\n        (24, 143, 145),\n        (51, 140, 149),\n        (85, 132, 157),\n        (119, 120, 169),\n        (52, 165, 173),\n        (19, 180, 181),\n        (57, 176, 185),\n        (104, 153, 185),\n        (95, 168, 193),\n        (28, 195, 197),\n        (84, 187, 205),\n        (133, 156, 205),\n        (21, 220, 221),\n        (140, 171, 221),\n        (60, 221, 229),\n        (105, 208, 233),\n        (120, 209, 241),\n        (32, 255, 257),\n        (23, 264, 265),\n        (96, 247, 265),\n        (69, 260, 269),\n        (115, 252, 277),\n        (160, 231, 281),\n        (161, 240, 289),\n        (68, 285, 293),\n    ],\n)\ndef test_pythagorean_triples(a, b, h):\n    assert abs(math.hypot(a, b) - h) <= abs(h) * float_info.epsilon\n    assert abs(cathetus(h, a) - b) <= abs(b) * float_info.epsilon\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_charmap.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport sys\nimport tempfile\nimport time\nimport unicodedata\nfrom typing import get_args\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.internal import charmap as cm\nfrom hypothesis.internal.intervalsets import IntervalSet\n\nfrom tests.common.utils import skipif_threading\n\n\ndef test_charmap_contains_all_unicode():\n    n = 0\n    for vs in cm.charmap().values():\n        for u, v in vs:\n            n += v - u + 1\n    assert n == sys.maxunicode + 1\n\n\ndef test_charmap_has_right_categories():\n    for cat, intervals in cm.charmap().items():\n        for u, v in intervals:\n            for i in range(u, v + 1):\n                real = unicodedata.category(chr(i))\n                assert real == cat, f\"{i} is {real} but reported in {cat}\"\n\n\ndef assert_valid_range_list(ls):\n    for u, v in ls:\n        assert u <= v\n    for i in range(len(ls) - 1):\n        assert ls[i] <= ls[i + 1]\n        assert ls[i][-1] < ls[i + 1][0]\n\n\n@given(st.sets(st.sampled_from(cm.categories())))\ndef test_query_matches_categories(cats):\n    values = cm.query(categories=cats).intervals\n    assert_valid_range_list(values)\n    for u, v in values:\n        for i in (u, v, (u + v) // 2):\n            assert unicodedata.category(chr(i)) in cats\n\n\n@given(\n    st.sets(st.sampled_from(cm.categories())) | st.none(),\n    st.integers(0, sys.maxunicode),\n    st.integers(0, sys.maxunicode),\n)\ndef test_query_matches_categories_codepoints(cats, m1, m2):\n    m1, m2 = sorted((m1, m2))\n    values = cm.query(categories=cats, min_codepoint=m1, max_codepoint=m2).intervals\n    assert_valid_range_list(values)\n    for u, v in values:\n        assert m1 <= u\n        assert v <= m2\n\n\n# any test which sets `_charmap = None` is thread-unsafe.\n@skipif_threading\ndef test_reload_charmap():\n    x = cm.charmap()\n    assert x is cm.charmap()\n    cm._charmap = None\n    y = cm.charmap()\n    assert x is not y\n    assert x == y\n\n\n@skipif_threading\ndef test_recreate_charmap():\n    x = cm.charmap()\n    assert x is cm.charmap()\n    cm._charmap = None\n    cm.charmap_file().unlink()\n    y = cm.charmap()\n    assert x is not y\n    assert x == y\n\n\n# This test fails flakily (every 1 in ~10 full CI runs), but only on the test-pyodide\n# ci job:\n#\n#      os.utime(cm.charmap_file(), (mtime, mtime))\n#      ~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n#   FileNotFoundError: [Errno 44] No such file or directory:\n#   '/home/runner/work/hypothesis/hypothesis/.hypothesis/unicode_data/15.1.0/charmap.json.gz'\n#\n# I suspect this is from a race condition due to how we parallelize the pyodide\n# tests in CI, (splitting test files across 20 processes). It's also possible\n# it's from some pyodide-specific weirdness, but since the test only fails sometimes,\n# I find this less likely.\n#\n# I'm xfailing this on emscripten for now, to get a consistent green CI.\n@pytest.mark.xfail(\n    condition=sys.platform == \"emscripten\", strict=False, reason=\"see comment\"\n)\n@skipif_threading\ndef test_uses_cached_charmap():\n    cm.charmap()\n\n    # Reset the last-modified time of the cache file to a point in the past.\n    mtime = int(time.time() - 1000)\n    os.utime(cm.charmap_file(), (mtime, mtime))\n    statinfo = cm.charmap_file().stat()\n    assert statinfo.st_mtime == mtime\n\n    # Force reload of charmap from cache file and check that mtime is unchanged.\n    cm._charmap = None\n    cm.charmap()\n    statinfo = cm.charmap_file().stat()\n    assert statinfo.st_mtime == mtime\n\n\ndef _union_intervals(x, y):\n    return IntervalSet(x).union(IntervalSet(y)).intervals\n\n\ndef test_union_empty():\n    assert _union_intervals([], []) == ()\n    assert _union_intervals([], [[1, 2]]) == ((1, 2),)\n    assert _union_intervals([[1, 2]], []) == ((1, 2),)\n\n\ndef test_union_handles_totally_overlapped_gap():\n    #   < xx  >  Imagine the intervals x and y as bit strings.\n    # | <yy yy>  The bit at position n is set if n falls inside that interval.\n    # = <zzzzz>  In this model _union_intervals() performs bit-wise or.\n    assert _union_intervals([[2, 3]], [[1, 2], [4, 5]]) == ((1, 5),)\n\n\ndef test_union_handles_partially_overlapped_gap():\n    #   <  x  >  Imagine the intervals x and y as bit strings.\n    # | <yy  y>  The bit at position n is set if n falls inside that interval.\n    # = <zzz z>  In this model _union_intervals() performs bit-wise or.\n    assert _union_intervals([[3, 3]], [[1, 2], [5, 5]]) == ((1, 3), (5, 5))\n\n\ndef test_successive_union():\n    x = []\n    for v in cm.charmap().values():\n        x = _union_intervals(x, v)\n    assert x == ((0, sys.maxunicode),)\n\n\n@skipif_threading\ndef test_can_handle_race_between_exist_and_create(monkeypatch):\n    x = cm.charmap()\n    cm._charmap = None\n    monkeypatch.setattr(os.path, \"exists\", lambda p: False)\n    y = cm.charmap()\n    assert x is not y\n    assert x == y\n\n\n@skipif_threading\ndef test_exception_in_write_does_not_lead_to_broken_charmap(monkeypatch):\n    def broken(*args, **kwargs):\n        raise ValueError\n\n    cm._charmap = None\n    monkeypatch.setattr(os.path, \"exists\", lambda p: False)\n    monkeypatch.setattr(os, \"rename\", broken)\n\n    cm.charmap()\n    cm.charmap()\n\n\n@skipif_threading\ndef test_regenerate_broken_charmap_file():\n    cm.charmap()\n\n    cm.charmap_file().write_bytes(b\"\")  # overwrite with empty file\n\n    cm._charmap = None\n    cm.charmap()\n\n\ndef test_exclude_characters_are_included_in_key():\n    assert cm.query().intervals != cm.query(exclude_characters=\"0\").intervals\n\n\n@skipif_threading\ndef test_error_writing_charmap_file_is_suppressed(monkeypatch):\n    def broken_mkstemp(dir):\n        raise RuntimeError\n\n    monkeypatch.setattr(tempfile, \"mkstemp\", broken_mkstemp)\n\n    try:\n        # Cache the charmap to avoid a performance hit the next time\n        # somebody tries to use it.\n        saved = cm._charmap\n        cm._charmap = None\n        cm.charmap_file().unlink()\n\n        cm.charmap()\n    finally:\n        cm._charmap = saved\n\n\ndef test_categoryname_literal_is_correct():\n    minor_categories = set(cm.categories())\n    major_categories = {c[0] for c in minor_categories}\n    assert set(get_args(cm.CategoryName)) == minor_categories | major_categories\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_compat.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nfrom collections import defaultdict, namedtuple\nfrom dataclasses import dataclass\nfrom functools import partial\nfrom inspect import Parameter, Signature, signature\nfrom typing import ForwardRef, Union\n\nimport pytest\n\nfrom hypothesis.internal.compat import (\n    add_note,\n    ceil,\n    dataclass_asdict,\n    extract_bits,\n    floor,\n    get_type_hints,\n)\n\nfloor_ceil_values = [\n    -10.7,\n    -10.3,\n    -0.5,\n    -0.0,\n    0,\n    0.5,\n    10.3,\n    10.7,\n]\n\n\n@pytest.mark.parametrize(\"value\", floor_ceil_values)\ndef test_our_floor_agrees_with_math_floor(value):\n    assert floor(value) == math.floor(value)\n\n\n@pytest.mark.parametrize(\"value\", floor_ceil_values)\ndef test_our_ceil_agrees_with_math_ceil(value):\n    assert ceil(value) == math.ceil(value)\n\n\nclass WeirdSig:\n    __signature__ = Signature(\n        parameters=[Parameter(name=\"args\", kind=Parameter.VAR_POSITIONAL)]\n    )\n\n\ndef test_no_type_hints():\n    assert get_type_hints(WeirdSig) == {}\n\n\n@dataclass\nclass Foo:\n    x: \"Foo\" = None  # type: ignore\n\n\nFoo.__signature__ = signature(Foo).replace(  # type: ignore\n    parameters=[\n        Parameter(\n            \"x\",\n            Parameter.POSITIONAL_OR_KEYWORD,\n            annotation=ForwardRef(\"Foo\"),\n            default=None,\n        )\n    ]\n)\n\n\n@dataclass\nclass Bar:\n    x: Union[int, \"Bar\"] | None\n\n\nBar.__signature__ = signature(Bar).replace(  # type: ignore\n    parameters=[\n        Parameter(\n            \"x\",\n            Parameter.POSITIONAL_OR_KEYWORD,\n            # ruff reports a false-positive UP007 here, since int | ForwardRef(\"Bar\")\n            # errors on 3.10. We can change this once we drop 3.10.\n            #\n            # see also https://github.com/astral-sh/ruff/issues/20883\n            annotation=Union[int, ForwardRef(\"Bar\"), None],  # type: ignore  # noqa: UP007\n        )\n    ]\n)\n\n\n@pytest.mark.parametrize(\"obj,expected\", [(Foo, Foo | None), (Bar, int | Bar | None)])\ndef test_resolve_fwd_refs(obj, expected):\n    # See: https://github.com/HypothesisWorks/hypothesis/issues/3519\n    assert get_type_hints(obj)[\"x\"] == expected\n\n\ndef func(a, b: int, *c: str, d: int | None = None):\n    pass\n\n\n@pytest.mark.parametrize(\n    \"pf, names\",\n    [\n        (partial(func, 1), \"b c d\"),\n        (partial(func, 1, 2), \"c d\"),\n        (partial(func, 1, 2, 3, 4, 5), \"c d\"),  # varargs don't fill\n        (partial(func, 1, 2, 3, d=4), \"c d\"),  # kwonly args just get new defaults\n    ],\n)\ndef test_get_hints_through_partial(pf, names):\n    assert set(get_type_hints(pf)) == set(names.split())\n\n\n@dataclass\nclass FilledWithStuff:\n    a: list\n    b: tuple\n    c: namedtuple\n    d: dict\n    e: defaultdict\n\n\ndef test_dataclass_asdict():\n    ANamedTuple = namedtuple(\"ANamedTuple\", (\"with_some_field\"))\n    e = defaultdict(list)\n    e[\"a\"].append(1)\n    obj = FilledWithStuff(a=[1], b=(2), c=ANamedTuple(3), d={4: 5}, e=e)\n    assert dataclass_asdict(obj) == {\n        \"a\": [1],\n        \"b\": (2),\n        \"c\": ANamedTuple(3),\n        \"d\": {4: 5},\n        \"e\": {\"a\": [1]},\n    }\n\n\n@pytest.mark.parametrize(\"width\", [None, 8])\n@pytest.mark.parametrize(\"x\", [0, 2, 123])\ndef test_extract_bits_roundtrip(width, x):\n    bits = extract_bits(x, width=width)\n    if width is not None:\n        assert len(bits) == width\n    assert x == sum(v << p for p, v in enumerate(reversed(bits)))\n\n\n@dataclass(frozen=True, slots=False)\nclass ImmutableError:\n    msg: str\n\n\ndef test_add_note_fails_gracefully_on_frozen_instance():\n    add_note(ImmutableError(\"msg\"), \"some note\")\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_complex_numbers.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nimport sys\n\nimport pytest\n\nfrom hypothesis import HealthCheck, given, reject, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.strategies import complex_numbers\n\nfrom tests.common.debug import (\n    assert_no_examples,\n    check_can_generate_examples,\n    find_any,\n    minimal,\n)\n\n\ndef test_minimal():\n    assert minimal(complex_numbers()) == 0\n\n\ndef test_minimal_nonzero_real():\n    assert minimal(complex_numbers(), lambda x: x.real != 0) == 1\n\n\ndef test_minimal_nonzero_imaginary():\n    assert minimal(complex_numbers(), lambda x: x.imag != 0) == 1j\n\n\ndef test_minimal_quadrant1():\n    assert minimal(complex_numbers(), lambda x: x.imag > 0 and x.real > 0) == 1 + 1j\n\n\ndef test_minimal_quadrant2():\n    assert minimal(complex_numbers(), lambda x: x.imag > 0 and x.real < 0) == -1 + 1j\n\n\ndef test_minimal_quadrant3():\n    assert minimal(complex_numbers(), lambda x: x.imag < 0 and x.real < 0) == -1 - 1j\n\n\ndef test_minimal_quadrant4():\n    assert minimal(complex_numbers(), lambda x: x.imag < 0 and x.real > 0) == 1 - 1j\n\n\n@given(st.data(), st.integers(-5, 5).map(lambda x: 10**x))\ndef test_max_magnitude_respected(data, mag):\n    c = data.draw(complex_numbers(max_magnitude=mag))\n    # Note we accept epsilon errors here as internally sqrt is used to draw\n    # complex numbers. sqrt on some platforms gets epsilon errors, which is\n    # too tricky to filter out and so - for now - we just accept them.\n    assert abs(c) <= mag * (1 + sys.float_info.epsilon)\n\n\n@given(complex_numbers(max_magnitude=0))\ndef test_max_magnitude_zero(val):\n    assert val == 0\n\n\n@settings(suppress_health_check=[HealthCheck.too_slow])\n@given(st.data(), st.integers(-5, 5).map(lambda x: 10**x))\ndef test_min_magnitude_respected(data, mag):\n    c = data.draw(complex_numbers(min_magnitude=mag))\n    # See test_max_magnitude_respected comment\n    assert (\n        abs(c.real) >= mag\n        or abs(c.imag) >= mag\n        or abs(c) >= mag * (1 - sys.float_info.epsilon)\n    )\n\n\ndef test_minimal_min_magnitude_zero():\n    assert minimal(complex_numbers(min_magnitude=0)) == 0\n\n\ndef test_minimal_min_magnitude_positive():\n    assert minimal(complex_numbers(min_magnitude=0.5)) in (0.5, 1)\n\n\ndef test_minimal_minmax_magnitude():\n    assert minimal(complex_numbers(min_magnitude=0.5, max_magnitude=1.5)) in (0.5, 1)\n\n\n@given(st.data(), st.floats(0, 10e300, allow_infinity=False, allow_nan=False))\ndef test_minmax_magnitude_equal(data, mag):\n    val = data.draw(st.complex_numbers(min_magnitude=mag, max_magnitude=mag))\n    try:\n        # Cap magnitude at 10e300 to avoid float overflow, and imprecision\n        # at very large exponents (which makes math.isclose fail)\n        assert math.isclose(abs(val), mag)\n    except OverflowError:\n        reject()\n\n\ndef _is_subnormal(x):\n    return 0 < abs(x) < sys.float_info.min\n\n\n@pytest.mark.parametrize(\n    \"allow_subnormal, min_magnitude, max_magnitude\",\n    [\n        (True, 0, None),\n        (True, 1, None),\n        (False, 0, None),\n    ],\n)\ndef test_allow_subnormal(allow_subnormal, min_magnitude, max_magnitude):\n    strat = complex_numbers(\n        min_magnitude=min_magnitude,\n        max_magnitude=max_magnitude,\n        allow_subnormal=allow_subnormal,\n    ).filter(lambda x: x.real != 0 and x.imag != 0)\n\n    if allow_subnormal:\n        find_any(strat, lambda x: _is_subnormal(x.real) or _is_subnormal(x.imag))\n    else:\n        assert_no_examples(\n            strat, lambda x: _is_subnormal(x.real) or _is_subnormal(x.imag)\n        )\n\n\n@pytest.mark.parametrize(\"allow_subnormal\", [1, 0.0, \"False\"])\ndef test_allow_subnormal_validation(allow_subnormal):\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(complex_numbers(allow_subnormal=allow_subnormal))\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_composite.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport typing\n\nimport pytest\n\nfrom hypothesis import HealthCheck, assume, given, settings, strategies as st\nfrom hypothesis.errors import (\n    HypothesisDeprecationWarning,\n    HypothesisWarning,\n    InvalidArgument,\n)\n\nfrom tests.common.debug import minimal\nfrom tests.common.utils import flaky\n\n\n@st.composite\ndef badly_draw_lists(draw, m=0):\n    length = draw(st.integers(m, m + 10))\n    return [draw(st.integers()) for _ in range(length)]\n\n\ndef test_simplify_draws():\n    assert minimal(badly_draw_lists(), lambda x: len(x) >= 3) == [0] * 3\n\n\ndef test_can_pass_through_arguments():\n    assert minimal(badly_draw_lists(5)) == [0] * 5\n    assert minimal(badly_draw_lists(m=6)) == [0] * 6\n\n\n@st.composite\ndef draw_ordered_with_assume(draw):\n    x = draw(st.floats())\n    y = draw(st.floats())\n    assume(x < y)\n    return (x, y)\n\n\n@given(draw_ordered_with_assume())\n@settings(suppress_health_check=[HealthCheck.filter_too_much])\ndef test_can_assume_in_draw(xy):\n    assert xy[0] < xy[1]\n\n\ndef test_uses_definitions_for_reprs():\n    assert repr(badly_draw_lists()) == \"badly_draw_lists()\"\n    assert repr(badly_draw_lists(1)) == \"badly_draw_lists(m=1)\"\n    assert repr(badly_draw_lists(m=1)) == \"badly_draw_lists(m=1)\"\n\n\ndef test_errors_given_default_for_draw():\n    with pytest.raises(InvalidArgument):\n\n        @st.composite\n        def foo(x=None):\n            pass\n\n\ndef test_errors_given_function_of_no_arguments():\n    with pytest.raises(InvalidArgument):\n\n        @st.composite\n        def foo():\n            pass\n\n\ndef test_errors_given_kwargs_only():\n    with pytest.raises(InvalidArgument):\n\n        @st.composite\n        def foo(**kwargs):\n            pass\n\n\ndef test_warning_given_no_drawfn_call():\n    with pytest.warns(HypothesisDeprecationWarning):\n\n        @st.composite\n        def foo(_):\n            return \"bar\"\n\n\ndef test_can_use_pure_args():\n    @st.composite\n    def stuff(*args):\n        return args[0](st.sampled_from(args[1:]))\n\n    assert minimal(stuff(1, 2, 3, 4, 5)) == 1\n\n\ndef test_composite_of_lists():\n    @st.composite\n    def f(draw):\n        return draw(st.integers()) + draw(st.integers())\n\n    assert minimal(st.lists(f()), lambda x: len(x) >= 10) == [0] * 10\n\n\n@flaky(min_passes=2, max_runs=5)\ndef test_can_shrink_matrices_with_length_param():\n    @st.composite\n    def matrix(draw):\n        rows = draw(st.integers(1, 10))\n        columns = draw(st.integers(1, 10))\n        return [\n            [draw(st.integers(0, 10000)) for _ in range(columns)] for _ in range(rows)\n        ]\n\n    def transpose(m):\n        return [[row[i] for row in m] for i in range(len(m[0]))]\n\n    def is_square(m):\n        return len(m) == len(m[0])\n\n    value = minimal(matrix(), lambda m: is_square(m) and transpose(m) != m)\n    assert len(value) == 2\n    assert len(value[0]) == 2\n    assert sorted(value[0] + value[1]) == [0, 0, 0, 1]\n\n\nclass MyList(list):\n    pass\n\n\n@given(st.data(), st.lists(st.integers()).map(MyList))\ndef test_does_not_change_arguments(data, ls):\n    # regression test for issue #1017 or other argument mutation\n    @st.composite\n    def strat(draw, arg):\n        draw(st.none())\n        return arg\n\n    ex = data.draw(strat(ls))\n    assert ex is ls\n\n\nclass ClsWithStrategyMethods:\n    @classmethod\n    @st.composite\n    def st_classmethod_then_composite(draw, cls):\n        return draw(st.integers(0, 10))\n\n    @st.composite\n    @classmethod\n    def st_composite_then_classmethod(draw, cls):\n        return draw(st.integers(0, 10))\n\n    @staticmethod\n    @st.composite\n    def st_staticmethod_then_composite(draw):\n        return draw(st.integers(0, 10))\n\n    @st.composite\n    @staticmethod\n    def st_composite_then_staticmethod(draw):\n        return draw(st.integers(0, 10))\n\n    @st.composite\n    def st_composite_method(draw, self):\n        return draw(st.integers(0, 10))\n\n\n@given(st.data())\ndef test_applying_composite_decorator_to_methods(data):\n    instance = ClsWithStrategyMethods()\n    for strategy in [\n        ClsWithStrategyMethods.st_classmethod_then_composite(),\n        ClsWithStrategyMethods.st_composite_then_classmethod(),\n        ClsWithStrategyMethods.st_staticmethod_then_composite(),\n        ClsWithStrategyMethods.st_composite_then_staticmethod(),\n        instance.st_classmethod_then_composite(),\n        instance.st_composite_then_classmethod(),\n        instance.st_staticmethod_then_composite(),\n        instance.st_composite_then_staticmethod(),\n        instance.st_composite_method(),\n    ]:\n        x = data.draw(strategy)\n        assert isinstance(x, int)\n        assert 0 <= x <= 10\n\n\ndef test_drawfn_cannot_be_instantiated():\n    with pytest.raises(TypeError):\n        st.DrawFn()\n\n\ndef test_warns_on_strategy_annotation():\n    with pytest.warns(HypothesisWarning, match=\"Return-type annotation\") as w:\n\n        @st.composite\n        def my_integers(draw: st.DrawFn) -> st.SearchStrategy[int]:\n            return draw(st.integers())\n\n    assert len(w.list) == 1\n    assert w.list[0].filename == __file__  # check stacklevel points to user code\n\n\ndef test_composite_allows_overload_without_draw():\n    # See https://github.com/HypothesisWorks/hypothesis/issues/3970\n    @st.composite\n    @typing.overload\n    def overloaded(draw: st.DrawFn, *, x: int) -> typing.Literal[True]: ...\n\n    @st.composite\n    @typing.overload\n    def overloaded(draw: st.DrawFn, *, x: str) -> typing.Literal[False]: ...\n\n    @st.composite\n    def overloaded(draw: st.DrawFn, *, x: int | str) -> bool:\n        return draw(st.just(isinstance(x, int)))\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_composite_kwonlyargs.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, strategies as st\n\n# Tests that convert_keyword_arguments in reflection.py can handle\n# composites that only have keyword-only arguments.\n# See https://github.com/HypothesisWorks/hypothesis/issues/1999\n\n\n@st.composite\ndef kwonlyargs_composites(draw, *, kwarg1=None):\n    return draw(st.fixed_dictionaries({\"kwarg1\": st.just(kwarg1), \"i\": st.integers()}))\n\n\n@given(\n    st.lists(\n        st.one_of(kwonlyargs_composites(kwarg1=\"test\")), unique_by=lambda x: x[\"i\"]\n    )\n)\ndef test_composite_with_keyword_only_args(a):\n    pass\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_constants_ast.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport ast\nimport inspect\nimport subprocess\nimport sys\nimport textwrap\nfrom types import ModuleType\n\nimport pytest\n\nfrom hypothesis import example, given, note, settings, strategies as st\nfrom hypothesis.internal.compat import PYPY\nfrom hypothesis.internal.constants_ast import (\n    Constants,\n    ConstantVisitor,\n    TooManyConstants,\n    _constants_file_str,\n    _constants_from_source,\n    constants_from_module,\n    is_local_module_file,\n)\n\nfrom tests.common.utils import skipif_emscripten, skipif_threading\n\nconstant_ints = st.integers(max_value=-101) | st.integers(min_value=101)\nconstant_floats = st.floats(allow_nan=False, allow_infinity=False)\nconstant_bytes = st.binary(min_size=1, max_size=50)\nconstant_strings = st.text(min_size=1, max_size=10).filter(lambda s: not s.isspace())\nconstants = constant_ints | constant_floats | constant_bytes | constant_strings\n\nconstants_classes = st.builds(\n    Constants,\n    integers=st.sets(constant_ints),\n    floats=st.sets(constant_floats),\n    bytes=st.sets(constant_bytes),\n    strings=st.sets(constant_strings),\n)\n\n\ndef constants_from_ast(tree):\n    visitor = ConstantVisitor(limit=True)\n    visitor.visit(tree)\n    return visitor.constants\n\n\ndef test_constants_set_from_type_invalid():\n    with pytest.raises(ValueError):\n        Constants().set_for_type(\"not_a_type\")\n\n\n@given(st.integers())\ndef test_constants_contains(n):\n    assert n in Constants(integers={n})\n\n\n@given(constants_classes)\ndef test_constants_not_equal_to_set(constants):\n    assert constants != set()\n    assert constants != set(constants)\n\n\n@pytest.mark.parametrize(\n    \"source, expected\",\n    [\n        (\n            \"\"\"\n            a1 = 142\n            a2 = 3.14\n            a3 = 'test1'\n            a4 = b'test2'\n            a5 = (101, 102)\n            a6 = frozenset([103])\n            \"\"\",\n            {142, 3.14, 101, 102, 103, \"test1\", b\"test2\"},\n        ),\n        (\n            \"a = (101, (102, 103), frozenset([104, 105]))\",\n            {101, 102, 103, 104, 105},\n        ),\n        (\"a = {'b': 101}\", {\"b\", 101}),\n        (\"a = [101]\", {101}),\n        (\"a = +142\", {142}),\n        (\"a = 101 + 102\", {101, 102}),\n        (\"a = ~ 142\", {142}),\n        # the following cases are ignored:\n        # * booleans\n        # * math.inf and math.nan (not constants, but we don't want to collect them\n        #   even if they were)\n        # * f-strings\n        # * long strings\n        # * pure-whitespace strings\n        # * standalone string expressions (strings not assigned to a variable).\n        #   This covers docstrings of all kinds.\n        # * small integers\n        # * the empty bytestring b\"\"\n        (\"a = True\", set()),\n        (\"a = False\", set()),\n        (\"a = not False\", set()),\n        (\"a = 1e999\", set()),\n        (\"a = math.inf\", set()),\n        (\"a = math.nan\", set()),\n        ('a = f\"test {x}\"', set()),\n        (f'a = \"{\"b\" * 100}\"', set()),\n        ('a = \"\"', set()),\n        ('a = \" \"', set()),\n        ('a = \"\\\\n    \\\\n  \\\\n\"', set()),\n        (\"'test'\", set()),\n        (\"'test with \\\\n newlines'\", set()),\n        (\"a = 10\", set()),\n        (\"a = -1\", set()),\n        (\"a = b''\", set()),\n    ],\n)\ndef test_constants_from_ast(source, expected):\n    source = textwrap.dedent(source)\n    tree = ast.parse(source)\n    assert set(constants_from_ast(tree)) == expected\n\n\n@given(st.integers(max_value=-101))\ndef test_parses_negatives(n):\n    assert constants_from_ast(ast.parse(f\"a = {n}\")) == Constants(integers={n})\n\n\n@given(st.tuples(constants))\ndef test_tuple_constants(value):\n    tree = ast.parse(str(value))\n    assert set(constants_from_ast(tree)) == set(value)\n\n\n@given(st.frozensets(constants))\ndef test_frozenset_constants(value):\n    tree = ast.parse(str(value))\n    assert set(constants_from_ast(tree)) == set(value)\n\n\n@skipif_threading\n@skipif_emscripten\n@pytest.mark.xfail(\n    condition=settings.get_current_profile_name() != \"ci\",\n    strict=False,\n    reason=\"Requires clean environment\",\n)\ndef test_constants_from_running_file(tmp_path):\n    p = tmp_path / \"my_constants.py\"\n    p.write_text(\n        textwrap.dedent(\n            \"\"\"\n        import sys\n        # stdlib\n        import json\n        # third-party\n        import pytest\n        import hypothesis\n        from hypothesis.internal.constants_ast import (\n            is_local_module_file,\n            constants_from_module,\n            Constants\n        )\n\n        # these modules are in fact detected as local if they are installed\n        # as editable (as is common for contributors). Prevent the ast constant\n        # logic from picking up on them\n        for module in sys.modules.copy():\n            if module.startswith(\"hypofuzz\"):\n                del sys.modules[module]\n\n        constants = Constants()\n        for module in sys.modules.values():\n            if getattr(module, \"__file__\", None) is not None and is_local_module_file(\n                module.__file__\n            ):\n                constants |= constants_from_module(module)\n\n        expected = Constants(\n            strings={'float', 'string', 'bytes', 'integer', 'test', 'hypofuzz', '__file__'},\n            floats={3.14},\n            bytes={b'test'},\n            integers={142, 101, 102, 103, 104},\n        )\n        assert constants == expected, set(constants).symmetric_difference(set(expected))\n\n        # local\n        a = 142\n        b = \"test\"\n        c = True\n        d = 3.14\n        e = b\"test\"\n        f = (101, 102)\n        g = frozenset([103, 104])\n        \"\"\",\n        ),\n        encoding=\"utf-8\",\n    )\n    # this test doubles as a regression test for\n    # https://github.com/HypothesisWorks/hypothesis/issues/4375. Fail on comparisons\n    # between bytes and str.\n    subprocess.check_call([sys.executable, \"-bb\", str(p)])\n\n\ndef test_constants_from_bad_module():\n    # covering test for the except branch\n    module = ModuleType(\"nonexistent\")\n    assert constants_from_module(module) == Constants()\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/path/to/tests/module\",\n        \"/path/to/test/module\",\n        \"/a/test_file.py\",\n        \"/a/file_test.py\",\n    ],\n)\ndef test_local_modules_ignores_test_modules(path):\n    assert not is_local_module_file(path)\n\n\n@skipif_threading\n@pytest.mark.skipif(PYPY, reason=\"no memory error on pypy\")\ndef test_ignores_ast_parse_error(tmp_path):\n    p = tmp_path / \"errors_on_parse.py\"\n    p.write_text(\"[1, \" * 200 + \"]\" * 200, encoding=\"utf-8\")\n    module = ModuleType(\"<test_ignores_ast_parse_error>\")\n    module.__file__ = str(p)\n\n    source = inspect.getsource(module)\n    with pytest.raises(MemoryError):\n        ast.parse(source)\n\n    assert constants_from_module(module) == Constants()\n\n\n@example(\n    constants=Constants(\n        integers={-101, 101},\n        floats={101.0},\n        bytes=set(),\n        strings=set(),\n    ),\n)\n@example(\n    constants=Constants(\n        integers={-101, 100},\n        floats={-101.0, 101.0},\n        bytes={b\"-101.0\", b\"101.0\"},\n        strings={\"-101.0\", \"101.0\"},\n    ),\n)\n@given(constants_classes)\ndef test_constant_visitor_roundtrips_string(constants):\n    # our files in storage_directory(\"constants\") rely on this roundtrip\n    visitor = ConstantVisitor(limit=True)\n\n    s = _constants_file_str(constants)\n    visitor.visit(ast.parse(s))\n\n    note(f\"{constants=}\")\n    note(f\"{visitor.constants=}\")\n    assert visitor.constants == constants\n\n\ndef test_too_many_constants():\n    visitor = ConstantVisitor(limit=True)\n    # start at n=1000 to avoid ConstantVisitor ignoring small integers\n    s = \"; \".join(\n        f\"n = {i}\" for i in range(1000, 1000 + ConstantVisitor.CONSTANTS_LIMIT + 1)\n    )\n    # visitor should raise on too many constants\n    with pytest.raises(TooManyConstants):\n        visitor.visit(ast.parse(s))\n\n    # and also _constants_from_source should return empty on too many constants\n    assert _constants_from_source(s, limit=True) == Constants()\n\n    # but it parses fine with limit=False\n    visitor = ConstantVisitor(limit=False)\n    visitor.visit(ast.parse(s))\n    assert _constants_from_source(s, limit=False) == Constants(\n        integers=set(range(1000, 1000 + ConstantVisitor.CONSTANTS_LIMIT + 1))\n    )\n\n\n@skipif_threading  # concurrent writes to the same file\ndef test_module_too_large(tmp_path):\n    constant = 11231783\n\n    p = tmp_path / \"large_file.py\"\n    content = f\"a = {constant}\\n\\n\" + \"#\" * (512 * 1024 + 1)\n    p.write_text(content, encoding=\"utf-8\")\n\n    module = ModuleType(\"large_module\")\n    module.__file__ = str(p)\n    assert constants_from_module(module) == Constants()\n    assert constants_from_module(module, limit=False) == Constants(integers={constant})\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_control.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom dataclasses import dataclass\n\nimport pytest\n\nfrom hypothesis import Verbosity, assume, given, reject, reporting, settings\nfrom hypothesis.control import (\n    BuildContext,\n    _current_build_context,\n    _event_to_string,\n    cleanup,\n    current_build_context,\n    currently_in_test_context,\n    event,\n    note,\n)\nfrom hypothesis.errors import (\n    HypothesisDeprecationWarning,\n    InvalidArgument,\n    UnsatisfiedAssumption,\n)\nfrom hypothesis.internal.compat import ExceptionGroup\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.stateful import RuleBasedStateMachine, rule\nfrom hypothesis.strategies import integers\n\nfrom tests.common.utils import capture_out\n\n\ndef bc():\n    return BuildContext(ConjectureData.for_choices([]), wrapped_test=None)\n\n\ndef test_cannot_cleanup_with_no_context():\n    with pytest.raises(InvalidArgument):\n        cleanup(lambda: None)\n    assert _current_build_context.value is None\n\n\ndef test_cannot_event_with_no_context():\n    with pytest.raises(InvalidArgument):\n        event(\"hi\")\n    assert _current_build_context.value is None\n\n\ndef test_cleanup_executes_on_leaving_build_context():\n    data = []\n    with bc():\n        cleanup(lambda: data.append(1))\n        assert not data\n    assert data == [1]\n    assert _current_build_context.value is None\n\n\ndef test_can_nest_build_context():\n    data = []\n    with bc():\n        cleanup(lambda: data.append(1))\n        with bc():\n            cleanup(lambda: data.append(2))\n            assert not data\n        assert data == [2]\n    assert data == [2, 1]\n    assert _current_build_context.value is None\n\n\ndef test_does_not_suppress_exceptions():\n    with pytest.raises(AssertionError), bc():\n        raise AssertionError\n    assert _current_build_context.value is None\n\n\ndef test_suppresses_exceptions_in_teardown():\n    with pytest.raises(ValueError) as exc_info, bc():\n\n        def foo():\n            raise ValueError\n\n        cleanup(foo)\n        raise AssertionError\n\n    assert isinstance(exc_info.value, ValueError)\n    assert isinstance(exc_info.value.__cause__, AssertionError)\n\n\ndef test_runs_multiple_cleanup_with_teardown():\n    with pytest.raises(ExceptionGroup) as exc_info, bc():\n\n        def foo():\n            raise ValueError\n\n        def bar():\n            raise TypeError\n\n        cleanup(foo)\n        cleanup(bar)\n        raise AssertionError\n\n    assert isinstance(exc_info.value, ExceptionGroup)\n    assert isinstance(exc_info.value.__cause__, AssertionError)\n    assert {type(e) for e in exc_info.value.exceptions} == {ValueError, TypeError}\n    assert _current_build_context.value is None\n\n\ndef test_raises_error_if_cleanup_fails_but_block_does_not():\n    with pytest.raises(ValueError), bc():\n\n        def foo():\n            raise ValueError\n\n        cleanup(foo)\n    assert _current_build_context.value is None\n\n\ndef test_raises_if_note_out_of_context():\n    with pytest.raises(InvalidArgument):\n        note(\"Hi\")\n\n\ndef test_deprecation_warning_if_assume_out_of_context():\n    with pytest.warns(\n        HypothesisDeprecationWarning,\n        match=\"Using `assume` outside a property-based test is deprecated\",\n    ):\n        assume(True)\n\n\ndef test_deprecation_warning_if_reject_out_of_context():\n    with (\n        pytest.warns(\n            HypothesisDeprecationWarning,\n            match=\"Using `reject` outside a property-based test is deprecated\",\n        ),\n        pytest.raises(UnsatisfiedAssumption),\n    ):\n        reject()\n\n\ndef test_raises_if_current_build_context_out_of_context():\n    with pytest.raises(InvalidArgument):\n        current_build_context()\n\n\ndef test_current_build_context_is_current():\n    with bc() as a:\n        assert current_build_context() is a\n\n\ndef test_prints_all_notes_in_verbose_mode():\n    # slightly roundabout because @example messes with verbosity - see #1521\n    messages = set()\n\n    @settings(verbosity=Verbosity.debug, database=None)\n    @given(integers(1, 10))\n    def test(x):\n        msg = f\"x -> {x}\"\n        note(msg)\n        messages.add(msg)\n        assert x < 5\n\n    with (\n        capture_out() as out,\n        reporting.with_reporter(reporting.default),\n        pytest.raises(AssertionError),\n    ):\n        test()\n    v = out.getvalue()\n    for x in sorted(messages):\n        assert x in v\n\n\n@dataclass\nclass CanBePrettyPrinted:\n    n: int\n\n\ndef test_note_pretty_prints():\n    reports = []\n\n    @given(integers(1, 10))\n    def test(n):\n        with reporting.with_reporter(reports.append):\n            note(CanBePrettyPrinted(n))\n        assert n != 5\n\n    with pytest.raises(AssertionError):\n        test()\n\n    assert reports == [\"CanBePrettyPrinted(n=5)\"]\n\n\ndef test_not_currently_in_hypothesis():\n    assert currently_in_test_context() is False\n\n\n@given(integers())\ndef test_currently_in_hypothesis(_):\n    assert currently_in_test_context() is True\n\n\nclass ContextMachine(RuleBasedStateMachine):\n    @rule()\n    def step(self):\n        assert currently_in_test_context() is True\n\n\ntest_currently_in_stateful_test = ContextMachine.TestCase\n\n\ndef test_can_convert_non_weakref_types_to_event_strings():\n    _event_to_string((), avoid_realization=True)\n    _event_to_string((), avoid_realization=False)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_core.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport unittest\n\nimport pytest\nfrom _pytest.outcomes import Failed, Skipped\n\nfrom hypothesis import Phase, example, find, given, reject, settings, strategies as st\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.errors import InvalidArgument, NoSuchExample, Unsatisfiable\n\n\ndef test_stops_after_max_examples_if_satisfying():\n    count = 0\n\n    def track(x):\n        nonlocal count\n        count += 1\n        return False\n\n    max_examples = 100\n\n    with pytest.raises(NoSuchExample):\n        find(st.integers(0, 10000), track, settings=settings(max_examples=max_examples))\n\n    assert count == max_examples\n\n\ndef test_stops_after_ten_times_max_examples_if_not_satisfying():\n    count = 0\n\n    def track(x):\n        nonlocal count\n        count += 1\n        reject()\n\n    max_examples = 100\n    with pytest.raises(Unsatisfiable):\n        find(st.integers(0, 10000), track, settings=settings(max_examples=max_examples))\n\n    # Very occasionally we can generate overflows in generation, which also\n    # count towards our example budget, which means that we don't hit the\n    # maximum.\n    assert count <= 10 * max_examples\n\n\nsome_normal_settings = settings()\n\n\ndef test_is_not_normally_default():\n    assert settings.default is not some_normal_settings\n\n\n@given(st.booleans())\n@some_normal_settings\ndef test_settings_are_default_in_given(x):\n    assert settings.default is some_normal_settings\n\n\ndef test_given_shrinks_pytest_helper_errors():\n    final_value = None\n\n    @settings(derandomize=True, max_examples=100)\n    @given(st.integers())\n    def inner(x):\n        nonlocal final_value\n        final_value = x\n        if x > 100:\n            pytest.fail(f\"{x=} is too big!\")\n\n    with pytest.raises(Failed):\n        inner()\n    assert final_value == 101\n\n\ndef test_pytest_skip_skips_shrinking():\n    seen_large = False\n\n    @settings(derandomize=True, max_examples=100)\n    @given(st.integers())\n    def inner(x):\n        nonlocal seen_large\n        if x > 100:\n            if seen_large:\n                raise Exception(\"Should never replay a skipped test!\")\n            seen_large = True\n            pytest.skip(f\"{x=} is too big!\")\n\n    with pytest.raises(Skipped):\n        inner()\n\n\ndef test_can_find_with_db_eq_none():\n    find(st.integers(), bool, settings=settings(database=None, max_examples=100))\n\n\ndef test_no_such_example():\n    with pytest.raises(NoSuchExample):\n        find(st.none(), bool, database_key=b\"no such example\")\n\n\ndef test_validates_strategies_for_test_method():\n    invalid_strategy = st.lists(st.nothing(), min_size=1)\n\n    class TestStrategyValidation:\n        @given(invalid_strategy)\n        def test_method_with_bad_strategy(self, x):\n            pass\n\n    instance = TestStrategyValidation()\n    with pytest.raises(InvalidArgument):\n        instance.test_method_with_bad_strategy()\n\n\n@example(1)\n@given(st.integers())\n@settings(phases=[Phase.target, Phase.shrink, Phase.explain])\ndef no_phases(_):\n    raise Exception\n\n\n@given(st.integers())\n@settings(phases=[Phase.explicit])\ndef no_explicit(_):\n    raise Exception\n\n\n@given(st.integers())\n@settings(phases=[Phase.reuse], database=InMemoryExampleDatabase())\ndef empty_db(_):\n    raise Exception\n\n\n@pytest.mark.parametrize(\n    \"test_fn\",\n    [no_phases, no_explicit, empty_db],\n    ids=lambda t: t.__name__,\n)\ndef test_non_executed_tests_raise_skipped(test_fn):\n    with pytest.raises(unittest.SkipTest):\n        test_fn()\n\n\n@pytest.mark.parametrize(\n    \"codec, max_codepoint, exclude_categories, categories\",\n    [\n        (\"ascii\", None, None, None),\n        (\"ascii\", 128, None, None),\n        (\"ascii\", 100, None, None),\n        (\"utf-8\", None, None, None),\n        (\"utf-8\", None, [\"Cs\"], None),\n        (\"utf-8\", None, [\"N\"], None),\n        (\"utf-8\", None, None, [\"N\"]),\n    ],\n)\n@given(st.data())\ndef test_characters_codec(codec, max_codepoint, exclude_categories, categories, data):\n    strategy = st.characters(\n        codec=codec,\n        max_codepoint=max_codepoint,\n        exclude_categories=exclude_categories,\n        categories=categories,\n    )\n    example = data.draw(strategy)\n    assert example.encode(encoding=codec).decode(encoding=codec) == example\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_custom_reprs.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis.strategies._internal.lazy import unwrap_strategies\n\n\ndef test_includes_non_default_args_in_repr():\n    assert repr(st.integers()) == \"integers()\"\n    assert repr(st.integers(min_value=1)) == \"integers(min_value=1)\"\n\n\ndef test_sampled_repr_leaves_range_as_range():\n    huge = 10**100\n    assert repr(st.sampled_from(range(huge))) == f\"sampled_from(range(0, {huge}))\"\n\n\ndef hi(there, stuff):\n    return there\n\n\ndef test_supports_positional_and_keyword_args_in_builds():\n    assert (\n        repr(st.builds(hi, st.integers(), there=st.booleans()))\n        == \"builds(hi, integers(), there=booleans())\"\n    )\n\n\ndef test_preserves_sequence_type_of_argument():\n    assert repr(st.sampled_from([0, 1])) == \"sampled_from([0, 1])\"\n    assert repr(st.sampled_from((0, 1))) == \"sampled_from((0, 1))\"\n\n\nclass IHaveABadRepr:\n    def __repr__(self):\n        raise ValueError(\"Oh no!\")\n\n\ndef test_errors_are_deferred_until_repr_is_calculated():\n    s = (\n        st.builds(\n            lambda x, y: 1,\n            st.just(IHaveABadRepr()),\n            y=st.one_of(st.sampled_from((IHaveABadRepr(),)), st.just(IHaveABadRepr())),\n        )\n        .map(lambda t: t)\n        .filter(lambda t: True)\n        .flatmap(lambda t: st.just(IHaveABadRepr()))\n    )\n\n    with pytest.raises(ValueError):\n        repr(s)\n\n\n@given(st.iterables(st.integers()))\ndef test_iterables_repr_is_useful(it):\n    # fairly hard-coded but useful; also ensures _values are inexhaustible\n    assert repr(it) == f\"iter({it._values!r})\"\n\n\nclass Foo:\n    def __init__(self, x: int) -> None:\n        self.x = x\n\n\nclass Bar(Foo):\n    pass\n\n\ndef test_reprs_as_created():\n    @given(foo=st.builds(Foo), bar=st.from_type(Bar), baz=st.none().map(Foo))\n    @settings(print_blob=False, max_examples=10_000, derandomize=True)\n    def inner(foo, bar, baz):\n        assert baz.x is None\n        assert foo.x <= 0 or bar.x >= 0\n\n    with pytest.raises(AssertionError) as err:\n        inner()\n    expected = \"\"\"\nFalsifying example: inner(\n    foo=Foo(x=1),\n    bar=Bar(x=-1),\n    baz=Foo(None),\n)\n\"\"\"\n    assert \"\\n\".join(err.value.__notes__).strip() == expected.strip()\n\n\ndef test_reprs_as_created_interactive():\n    @given(st.data())\n    @settings(print_blob=False, max_examples=10_000)\n    def inner(data):\n        bar = data.draw(st.builds(Bar, st.just(10)))\n        assert not bar.x\n\n    with pytest.raises(AssertionError) as err:\n        inner()\n    expected = \"\"\"\nFalsifying example: inner(\n    data=data(...),\n)\nDraw 1: Bar(10)\n\"\"\"\n    assert \"\\n\".join(err.value.__notes__).strip() == expected.strip()\n\n\nCONSTANT_FOO = Foo(None)\n\n\ndef some_foo(*_):\n    return CONSTANT_FOO\n\n\ndef test_as_created_reprs_fallback_for_distinct_calls_same_obj():\n    # If we have *different* calls which return the *same* object, we skip our\n    # nice repr because it's unclear which one we should use.\n    @given(st.builds(some_foo), st.builds(some_foo, st.none()))\n    @settings(print_blob=False, max_examples=10_000)\n    def inner(a, b):\n        assert a is not b\n\n    with pytest.raises(AssertionError) as err:\n        inner()\n    expected_re = r\"\"\"\nFalsifying example: inner\\(\n    a=<.*Foo object at 0x[0-9A-Fa-f]+>,\n    b=<.*Foo object at 0x[0-9A-Fa-f]+>,\n\\)\n\"\"\".strip()\n    got = \"\\n\".join(err.value.__notes__).strip()\n    assert re.fullmatch(expected_re, got), got\n\n\ndef test_reprs_as_created_consistent_calls_despite_indentation():\n    aas = \"a\" * 60\n    strat = st.builds(some_foo, st.just(aas))\n\n    # If we have multiple calls which return the same object, we can print their\n    # nice repr even if varying indentation means that they'll come out different!\n    @given(strat, st.builds(Bar, strat))\n    @settings(print_blob=False, max_examples=10_000)\n    def inner(a, b):\n        assert a == b\n\n    with pytest.raises(AssertionError) as err:\n        inner()\n    expected = f\"\"\"\nFalsifying example: inner(\n    a=some_foo({aas!r}),\n    b=Bar(\n        some_foo(\n            {aas!r},\n        ),\n    ),\n)\n\"\"\"\n    assert \"\\n\".join(err.value.__notes__).strip() == expected.strip()\n\n\n@pytest.mark.parametrize(\n    \"strategy, expected_repr\",\n    [\n        (st.characters(), \"characters()\"),\n        (st.characters(codec=\"utf-8\"), \"characters(codec='utf-8')\"),\n        (st.characters(min_codepoint=65), \"characters(min_codepoint=65)\"),\n        (st.characters(max_codepoint=127), \"characters(max_codepoint=127)\"),\n        (st.characters(categories=[\"Lu\", \"Ll\"]), \"characters(categories=('Lu', 'Ll'))\"),\n        (\n            st.characters(exclude_characters=\"abc\"),\n            \"characters(exclude_characters='abc')\",\n        ),\n        (\n            st.characters(min_codepoint=65, max_codepoint=90),\n            \"characters(min_codepoint=65, max_codepoint=90)\",\n        ),\n        (\n            st.characters(codec=\"ascii\", min_codepoint=32, max_codepoint=126),\n            \"characters(min_codepoint=32, max_codepoint=126)\",\n        ),\n        (\n            st.characters(categories=[\"Lu\"], exclude_characters=\"AZ\"),\n            \"characters(categories=('Lu',), exclude_characters='AZ')\",\n        ),\n    ],\n)\ndef test_characters_repr(strategy, expected_repr):\n    assert repr(unwrap_strategies(strategy)) == expected_repr\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_database_backend.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport re\nimport shutil\nimport tempfile\nimport time\nimport zipfile\nfrom collections import Counter\nfrom collections.abc import Iterable, Iterator\nfrom contextlib import contextmanager, nullcontext\nfrom datetime import datetime, timedelta, timezone\nfrom pathlib import Path\nfrom shutil import make_archive, rmtree\n\nimport pytest\n\nfrom hypothesis import (\n    HealthCheck,\n    configuration,\n    example,\n    given,\n    settings,\n    strategies as st,\n)\nfrom hypothesis.database import (\n    BackgroundWriteDatabase,\n    DirectoryBasedExampleDatabase,\n    ExampleDatabase,\n    GitHubArtifactDatabase,\n    InMemoryExampleDatabase,\n    MultiplexedDatabase,\n    ReadOnlyDatabase,\n    _db_for_path,\n    _pack_uleb128,\n    _unpack_uleb128,\n    choices_from_bytes,\n    choices_to_bytes,\n)\nfrom hypothesis.errors import HypothesisDeprecationWarning, HypothesisWarning\nfrom hypothesis.internal.compat import WINDOWS\nfrom hypothesis.internal.conjecture.choice import choice_equal\nfrom hypothesis.stateful import (\n    Bundle,\n    RuleBasedStateMachine,\n    invariant,\n    precondition,\n    rule,\n    run_state_machine_as_test,\n)\nfrom hypothesis.strategies import binary, lists, tuples\nfrom hypothesis.utils.conventions import not_set\n\nfrom tests.common.utils import (\n    checks_deprecated_behaviour,\n    skipif_emscripten,\n    skipif_threading,\n    wait_for,\n)\nfrom tests.conjecture.common import nodes, nodes_inline\n\n# we need real time here, not monkeypatched for CI\ntime_sleep = time.sleep\n\n\n@given(lists(tuples(binary(), binary())))\n@settings(max_examples=50)\ndef test_backend_returns_what_you_put_in(xs):\n    backend = InMemoryExampleDatabase()\n    mapping = {}\n    for key, value in xs:\n        mapping.setdefault(key, set()).add(value)\n        backend.save(key, value)\n    for key, values in mapping.items():\n        backend_contents = list(backend.fetch(key))\n        distinct_backend_contents = set(backend_contents)\n        assert len(backend_contents) == len(distinct_backend_contents)\n        assert distinct_backend_contents == set(values)\n\n\ndef test_can_delete_keys():\n    backend = InMemoryExampleDatabase()\n    backend.save(b\"foo\", b\"bar\")\n    backend.save(b\"foo\", b\"baz\")\n    backend.delete(b\"foo\", b\"bar\")\n    assert list(backend.fetch(b\"foo\")) == [b\"baz\"]\n\n\ndef test_default_database_is_in_memory():\n    with pytest.warns(HypothesisDeprecationWarning):\n        assert isinstance(ExampleDatabase(), InMemoryExampleDatabase)\n\n\ndef test_default_on_disk_database_is_dir(tmp_path):\n    with pytest.warns(HypothesisDeprecationWarning):\n        assert isinstance(\n            ExampleDatabase(tmp_path.joinpath(\"foo\")), DirectoryBasedExampleDatabase\n        )\n\n\ndef test_does_not_error_when_fetching_when_not_exist(tmp_path):\n    db = DirectoryBasedExampleDatabase(tmp_path / \"examples\")\n    db.fetch(b\"foo\")\n\n\n@pytest.fixture(scope=\"function\", params=[\"memory\", \"directory\"])\ndef exampledatabase(request, tmp_path):\n    if request.param == \"memory\":\n        return InMemoryExampleDatabase()\n    assert request.param == \"directory\"\n    return DirectoryBasedExampleDatabase(tmp_path / \"examples\")\n\n\ndef test_can_delete_a_key_that_is_not_present(exampledatabase):\n    exampledatabase.delete(b\"foo\", b\"bar\")\n\n\ndef test_can_fetch_a_key_that_is_not_present(exampledatabase):\n    assert list(exampledatabase.fetch(b\"foo\")) == []\n\n\ndef test_saving_a_key_twice_fetches_it_once(exampledatabase):\n    exampledatabase.save(b\"foo\", b\"bar\")\n    exampledatabase.save(b\"foo\", b\"bar\")\n    assert list(exampledatabase.fetch(b\"foo\")) == [b\"bar\"]\n\n\ndef test_can_close_a_database_after_saving(exampledatabase):\n    exampledatabase.save(b\"foo\", b\"bar\")\n\n\ndef test_class_name_is_in_repr(exampledatabase):\n    assert type(exampledatabase).__name__ in repr(exampledatabase)\n\n\ndef test_an_absent_value_is_present_after_it_moves(exampledatabase):\n    exampledatabase.move(b\"a\", b\"b\", b\"c\")\n    assert next(exampledatabase.fetch(b\"b\")) == b\"c\"\n\n\ndef test_an_absent_value_is_present_after_it_moves_to_self(exampledatabase):\n    exampledatabase.move(b\"a\", b\"a\", b\"b\")\n    assert next(exampledatabase.fetch(b\"a\")) == b\"b\"\n\n\n@skipif_threading\ndef test_two_directory_databases_can_interact(tmp_path):\n    db1 = DirectoryBasedExampleDatabase(tmp_path)\n    db2 = DirectoryBasedExampleDatabase(tmp_path)\n    db1.save(b\"foo\", b\"bar\")\n    assert list(db2.fetch(b\"foo\")) == [b\"bar\"]\n    db2.save(b\"foo\", b\"bar\")\n    db2.save(b\"foo\", b\"baz\")\n    assert sorted(db1.fetch(b\"foo\")) == [b\"bar\", b\"baz\"]\n\n\ndef test_can_handle_disappearing_files(tmp_path, monkeypatch):\n    db = DirectoryBasedExampleDatabase(tmp_path)\n    db.save(b\"foo\", b\"bar\")\n    base_listdir = os.listdir\n    monkeypatch.setattr(\n        os, \"listdir\", lambda d: [*base_listdir(d), \"this-does-not-exist\"]\n    )\n    assert list(db.fetch(b\"foo\")) == [b\"bar\"]\n\n\ndef test_readonly_db_is_not_writable():\n    inner = InMemoryExampleDatabase()\n    wrapped = ReadOnlyDatabase(inner)\n    inner.save(b\"key\", b\"value\")\n    inner.save(b\"key\", b\"value2\")\n    wrapped.delete(b\"key\", b\"value\")\n    wrapped.move(b\"key\", b\"key2\", b\"value2\")\n    wrapped.save(b\"key\", b\"value3\")\n    assert set(wrapped.fetch(b\"key\")) == {b\"value\", b\"value2\"}\n    assert set(wrapped.fetch(b\"key2\")) == set()\n\n\ndef test_multiplexed_dbs_read_and_write_all():\n    a = InMemoryExampleDatabase()\n    b = InMemoryExampleDatabase()\n    multi = MultiplexedDatabase(a, b)\n    a.save(b\"a\", b\"aa\")\n    b.save(b\"b\", b\"bb\")\n    multi.save(b\"c\", b\"cc\")\n    multi.move(b\"a\", b\"b\", b\"aa\")\n    for db in (a, b, multi):\n        assert set(db.fetch(b\"a\")) == set()\n        assert set(db.fetch(b\"c\")) == {b\"cc\"}\n    got = list(multi.fetch(b\"b\"))\n    assert len(got) == 2\n    assert set(got) == {b\"aa\", b\"bb\"}\n    multi.delete(b\"c\", b\"cc\")\n    for db in (a, b, multi):\n        assert set(db.fetch(b\"c\")) == set()\n\n\ndef test_ga_require_readonly_wrapping():\n    \"\"\"Test that GitHubArtifactDatabase requires wrapping around ReadOnlyDatabase\"\"\"\n    database = GitHubArtifactDatabase(\"test\", \"test\")\n    # save, move and delete can only be called when wrapped around ReadonlyDatabase\n    with pytest.raises(RuntimeError, match=re.escape(database._read_only_message)):\n        database.save(b\"foo\", b\"bar\")\n    with pytest.raises(RuntimeError):\n        database.move(b\"foo\", b\"bar\", b\"foobar\")\n    with pytest.raises(RuntimeError):\n        database.delete(b\"foo\", b\"bar\")\n\n    # check that the database silently ignores writes when wrapped around ReadOnlyDatabase\n    database = ReadOnlyDatabase(database)\n    database.save(b\"foo\", b\"bar\")\n    database.move(b\"foo\", b\"bar\", b\"foobar\")\n    database.delete(b\"foo\", b\"bar\")\n\n\n@contextmanager\ndef ga_empty_artifact(\n    date: datetime | None = None, path: Path | None = None\n) -> Iterator[tuple[Path, Path]]:\n    \"\"\"Creates an empty GitHub artifact.\"\"\"\n    if date:\n        timestamp = date.isoformat().replace(\":\", \"_\")\n    else:\n        timestamp = datetime.now(timezone.utc).isoformat().replace(\":\", \"_\")\n\n    temp_dir = None\n    if not path:\n        temp_dir = tempfile.mkdtemp()\n        path = Path(temp_dir) / \"github-artifacts\"\n\n    path.mkdir(parents=True, exist_ok=True)\n    zip_path = path / f\"{timestamp}.zip\"\n\n    with zipfile.ZipFile(zip_path, \"w\"):\n        pass\n\n    try:\n        yield (path, zip_path)\n    finally:\n        if temp_dir:\n            rmtree(temp_dir)\n\n\ndef test_ga_empty_read():\n    \"\"\"Tests that an inexistent key returns nothing.\"\"\"\n    with ga_empty_artifact() as (path, _):\n        database = GitHubArtifactDatabase(\"test\", \"test\", path=path)\n        assert list(database.fetch(b\"foo\")) == []\n\n\ndef test_ga_initialize():\n    \"\"\"\n    Tests that the database is initialized when a new artifact is found.\n    As well that initialization doesn't happen again on the next fetch.\n    \"\"\"\n    now = datetime.now(timezone.utc)\n    with ga_empty_artifact(date=(now - timedelta(hours=2))) as (path, _):\n        database = GitHubArtifactDatabase(\"test\", \"test\", path=path)\n        # Trigger initialization\n        list(database.fetch(b\"\"))\n        initial_artifact = database._artifact\n        assert initial_artifact\n        assert database._artifact\n        assert database._access_cache is not None\n        with ga_empty_artifact(date=now, path=path) as (path, _):\n            # Initialization shouldn't happen again\n            list(database.fetch(b\"\"))\n            assert database._initialized\n            assert database._artifact == initial_artifact\n\n\ndef test_ga_no_artifact(tmp_path):\n    \"\"\"Tests that the database is disabled when no artifact is found.\"\"\"\n    database = GitHubArtifactDatabase(\"test\", \"test\", path=tmp_path)\n    # Check that the database raises a warning\n    with pytest.warns(HypothesisWarning):\n        assert list(database.fetch(b\"\")) == []\n    assert database._disabled is True\n    assert list(database.fetch(b\"\")) == []\n\n\ndef test_ga_corrupted_artifact():\n    \"\"\"Tests that corrupted artifacts are properly detected and warned about.\"\"\"\n    with ga_empty_artifact() as (path, zip_path):\n        # Corrupt the CRC of the zip file\n        with open(zip_path, \"rb+\") as f:\n            f.write(b\"\\x00\\x01\\x00\\x01\")\n\n        database = GitHubArtifactDatabase(\"test\", \"test\", path=path)\n        # Check that the database raises a warning\n        with pytest.warns(HypothesisWarning):\n            assert list(database.fetch(b\"\")) == []\n        assert database._disabled is True\n\n\ndef test_ga_deletes_old_artifacts():\n    \"\"\"Tests that old artifacts are automatically deleted.\"\"\"\n    now = datetime.now(timezone.utc)\n    with (\n        ga_empty_artifact(date=now) as (path, file_now),\n        ga_empty_artifact(date=now - timedelta(hours=2), path=path) as (\n            _,\n            file_old,\n        ),\n    ):\n        database = GitHubArtifactDatabase(\"test\", \"test\", path=path)\n        # Trigger initialization\n        list(database.fetch(b\"\"))\n        assert file_now.exists()\n        assert not file_old.exists()\n\n\n@skipif_threading\ndef test_ga_triggers_fetching(monkeypatch, tmp_path):\n    \"\"\"Tests whether an artifact fetch is triggered, and an expired artifact is deleted.\"\"\"\n    with ga_empty_artifact() as (_, artifact):\n        # We patch the _fetch_artifact method to return our artifact\n        def fake_fetch_artifact(self) -> Path | None:\n            return artifact\n\n        monkeypatch.setattr(\n            GitHubArtifactDatabase, \"_fetch_artifact\", fake_fetch_artifact\n        )\n\n        database = GitHubArtifactDatabase(\n            \"test\", \"test\", path=tmp_path, cache_timeout=timedelta(days=1)\n        )\n\n        # Test without an existing artifact\n        list(database.fetch(b\"\"))\n\n        assert not database._disabled\n        assert database._initialized\n        assert database._artifact == artifact\n\n        # Now we'll see if the DB also fetched correctly with an expired artifact\n        now = datetime.now(timezone.utc)\n        # We create an expired artifact\n        with ga_empty_artifact(date=now - timedelta(days=2)) as (\n            path_with_artifact,\n            old_artifact,\n        ):\n            database = GitHubArtifactDatabase(\n                \"test\", \"test\", path=path_with_artifact, cache_timeout=timedelta(days=1)\n            )\n\n            # Trigger initialization\n            list(database.fetch(b\"\"))\n            assert not database._disabled\n            assert database._initialized\n            assert database._artifact == artifact\n\n            # Check that the artifact was deleted\n            assert not old_artifact.exists()\n\n\ndef test_ga_fallback_expired(monkeypatch):\n    \"\"\"\n    Tests that the fallback to an expired artifact is triggered\n    if fetching a new one fails. This allows for (by example) offline development.\n    \"\"\"\n    now = datetime.now(timezone.utc)\n    with ga_empty_artifact(date=now - timedelta(days=2)) as (path, artifact):\n        database = GitHubArtifactDatabase(\n            \"test\", \"test\", path=path, cache_timeout=timedelta(days=1)\n        )\n\n        # This should trigger the fallback\n        def fake_fetch_artifact(self) -> Path | None:\n            return None\n\n        monkeypatch.setattr(\n            GitHubArtifactDatabase, \"_fetch_artifact\", fake_fetch_artifact\n        )\n\n        # Trigger initialization\n        with pytest.warns(HypothesisWarning):\n            list(database.fetch(b\"\"))\n\n        assert not database._disabled\n        assert database._initialized\n        assert database._artifact == artifact\n\n\nclass GitHubArtifactMocks(RuleBasedStateMachine):\n    \"\"\"\n    This is a state machine that tests agreement of GitHubArtifactDatabase\n    with DirectoryBasedExampleDatabase (as a reference implementation).\n    \"\"\"\n\n    def __init__(self):\n        super().__init__()\n        self.temp_directory = Path(tempfile.mkdtemp())\n        self.path = self.temp_directory / \"github-artifacts\"\n\n        # This is where we will store the contents for the zip file\n        timestamp = datetime.now(timezone.utc).isoformat().replace(\":\", \"_\")\n        self.zip_destination = self.path / f\"{timestamp}.zip\"\n\n        # And this is where we want to create it\n        self.zip_content_path = self.path / timestamp\n        self.zip_content_path.mkdir(parents=True, exist_ok=True)\n\n        # We use a DirectoryBasedExampleDatabase to create the contents\n        self.directory_db = DirectoryBasedExampleDatabase(str(self.zip_content_path))\n        self.zip_db = GitHubArtifactDatabase(\"mock\", \"mock\", path=self.path)\n\n        # Create zip file for the first time\n        self._archive_directory_db()\n        self.zip_db._initialize_db()\n\n    def _make_zip(self, tree_path: Path, zip_path: Path):\n        destination = zip_path.parent.absolute() / zip_path.stem\n        make_archive(\n            str(destination),\n            \"zip\",\n            root_dir=tree_path,\n        )\n\n    def _archive_directory_db(self):\n        # Delete all of the zip files in the directory\n        for file in self.path.glob(\"*.zip\"):\n            file.unlink()\n\n        self._make_zip(self.zip_content_path, self.zip_destination)\n\n    keys = Bundle(\"keys\")\n    values = Bundle(\"values\")\n\n    @rule(target=keys, k=st.binary())\n    def k(self, k):\n        return k\n\n    @rule(target=values, v=st.binary())\n    def v(self, v):\n        return v\n\n    @rule(k=keys, v=values)\n    def save(self, k, v):\n        self.directory_db.save(k, v)\n        self._archive_directory_db()\n        self.zip_db = GitHubArtifactDatabase(\"mock\", \"mock\", path=self.path)\n        self.zip_db._initialize_db()\n\n    @rule(k=keys)\n    def values_agree(self, k):\n        v1 = set(self.directory_db.fetch(k))\n        v2 = set(self.zip_db.fetch(k))\n\n        assert v1 == v2\n\n    def teardown(self):\n        shutil.rmtree(self.temp_directory)\n\n\nTestGADReads = GitHubArtifactMocks.TestCase\n\n\ndef test_gadb_coverage():\n    # Ensure that we always cover the nonempty-archive case, which can otherwise\n    # cause rare incomplete-coverage failures.\n    state = GitHubArtifactMocks()\n    state.save(b\"key\", b\"value\")\n    state.values_agree(b\"key\")\n\n\n@pytest.mark.parametrize(\"dirs\", [[], [\"subdir\"]])\ndef test_database_directory_inaccessible(dirs, tmp_path, monkeypatch):\n    monkeypatch.setattr(\n        configuration, \"__hypothesis_home_directory\", tmp_path.joinpath(*dirs)\n    )\n    try:\n        tmp_path.chmod(0o000)\n        with (\n            nullcontext()\n            if WINDOWS\n            else pytest.warns(\n                HypothesisWarning, match=\".*the default location is unusable\"\n            )\n        ):\n            database = _db_for_path(not_set)\n        database.save(b\"fizz\", b\"buzz\")\n    finally:\n        tmp_path.chmod(0o600)  # So that pytest can clean up tmp_path later\n\n\n@skipif_emscripten\ndef test_background_write_database():\n    db = BackgroundWriteDatabase(InMemoryExampleDatabase())\n    db.save(b\"a\", b\"b\")\n    db.save(b\"a\", b\"c\")\n    db.save(b\"a\", b\"d\")\n    assert set(db.fetch(b\"a\")) == {b\"b\", b\"c\", b\"d\"}\n\n    db.move(b\"a\", b\"a2\", b\"b\")\n    assert set(db.fetch(b\"a\")) == {b\"c\", b\"d\"}\n    assert set(db.fetch(b\"a2\")) == {b\"b\"}\n\n    db.delete(b\"a\", b\"c\")\n    assert set(db.fetch(b\"a\")) == {b\"d\"}\n\n\n@given(lists(nodes()))\n# covering examples\n@example(nodes_inline(True))\n@example(nodes_inline(1))\n@example(nodes_inline(0.0))\n@example(nodes_inline(-0.0))\n@example(nodes_inline(\"a\"))\n@example(nodes_inline(b\"a\"))\n@example(nodes_inline(b\"a\" * 50))\n@example(nodes_inline(b\"1\" * 100_000))  # really long bytes\ndef test_nodes_roundtrips(nodes1):\n    s1 = choices_to_bytes([n.value for n in nodes1])\n    assert isinstance(s1, bytes)\n    ir2 = choices_from_bytes(s1)\n    assert len(nodes1) == len(ir2)\n\n    for n1, v2 in zip(nodes1, ir2, strict=True):\n        assert choice_equal(n1.value, v2)\n\n    s2 = choices_to_bytes(ir2)\n    assert s1 == s2\n\n\n@given(st.integers(min_value=0))\ndef test_uleb_128_roundtrips(n1):\n    buffer1 = _pack_uleb128(n1)\n    idx, n2 = _unpack_uleb128(buffer1)\n    assert idx == len(buffer1)\n    assert n1 == n2\n\n\ndef _database_conforms_to_listener_api(\n    create_db,\n    *,\n    flush=None,\n    supports_value_delete=True,\n    parent_settings=None,\n):\n    # this function is a big mess to support a bunch of different special cases\n    # for different databases, sorry. In return, we get one big stateful test\n    # we can use to test the listener api for all of our databases.\n    #\n    # * create_db is a callable which accepts one argument (a path to a temporary\n    #   directory) and returns a database instance.\n    # * flush is a callable which takes the instantiated db as an argument, and\n    #   is called on every step as an invariant. This lets the database do things\n    #   like, time.sleep to give time for events to fire.\n    # * suports_value_delete is True if the db supports passing\n    #   the exact value of a deleted key in \"delete\" events. The directory database\n    #   notably does not support this, and passes None instead.\n\n    @settings(parent_settings, suppress_health_check=[HealthCheck.too_slow])\n    class TestDatabaseListener(RuleBasedStateMachine):\n        # this tests that if we call .delete, .save, or .move in a database, and\n        # that operation changes the state of the database, any registered listeners\n        # get called a corresponding number of times.\n        keys = Bundle(\"keys\")\n        values = Bundle(\"values\")\n\n        def __init__(self):\n            super().__init__()\n\n            self.temp_dir = Path(tempfile.mkdtemp())\n            self.db = create_db(self.temp_dir)\n            self.expected_events = []\n            self.actual_events = []\n\n            def listener(event):\n                self.actual_events.append(event)\n\n            self.listener = listener\n            self.active_listeners = []\n            self.add_listener()\n\n        def _expect_event(self, event_type, args):\n            for _ in range(len(self.active_listeners)):\n                self.expected_events.append((event_type, args))\n\n        def _expect_delete(self, k, v):\n            if not supports_value_delete:\n                v = None\n            self._expect_event(\"delete\", (k, v))\n\n        def _expect_save(self, k, v):\n            self._expect_event(\"save\", (k, v))\n\n        @rule(target=keys, k=st.binary())\n        def k(self, k):\n            return k\n\n        @rule(target=values, v=st.binary())\n        def v(self, v):\n            return v\n\n        @precondition(lambda self: not self.active_listeners)\n        @rule()\n        def add_listener(self):\n            self.db.add_listener(self.listener)\n            # wait for watchdog to initialize the listener asynchronously\n            time_sleep(0.1)\n            self.active_listeners.append(self.listener)\n\n        @precondition(lambda self: self.listener in self.active_listeners)\n        @rule()\n        def remove_listener(self):\n            self.db.remove_listener(self.listener)\n            self.active_listeners.remove(self.listener)\n\n        @rule()\n        def clear_listeners(self):\n            self.db.clear_listeners()\n            self.active_listeners.clear()\n\n        @rule(k=keys)\n        def fetch(self, k):\n            # we don't expect this to do anything, but that's the point. if this\n            # fires a listener call then that's bad and will fail.\n            self.db.fetch(k)\n\n        @rule(k=keys, v=values)\n        def save(self, k, v):\n            changed = v not in set(self.db.fetch(k))\n            self.db.save(k, v)\n\n            if changed:\n                self._expect_save(k, v)\n\n        @rule(k=keys, v=values)\n        def delete(self, k, v):\n            changed = v in set(self.db.fetch(k))\n            self.db.delete(k, v)\n\n            if changed:\n                self._expect_delete(k, v)\n\n        @rule(k1=keys, k2=keys, v=values)\n        def move(self, k1, k2, v):\n            in_k1 = v in set(self.db.fetch(k1))\n            save_changed = v not in set(self.db.fetch(k2))\n            delete_changed = k1 != k2 and in_k1\n            self.db.move(k1, k2, v)\n\n            # A move gets emitted as a delete followed by a save.  The\n            # delete may be omitted if k1==k2, and the save if v in db.fetch(k2).\n            if delete_changed:\n                self._expect_delete(k1, v)\n            if save_changed:\n                self._expect_save(k2, v)\n\n        # it would be nice if this was an @rule, but that runs into race condition\n        # failures where an event listener is removed immediately after a\n        # save/delete/move operation, before the listener can fire. This is only\n        # relevant for DirectoryBasedExampleDatabase.\n        @invariant()\n        def events_agree(self):\n            if flush is not None:\n                flush(self.db)\n\n            wait_for(\n                lambda: len(self.expected_events) == len(self.actual_events), timeout=60\n            )\n            # events *generally* don't arrive out of order, but we've had\n            # flakes reported here, especially on weirder / older machines.\n            # see https://github.com/HypothesisWorks/hypothesis/issues/4274\n            assert Counter(self.expected_events) == Counter(self.actual_events)\n\n        def teardown(self):\n            shutil.rmtree(self.temp_dir)\n\n    run_state_machine_as_test(TestDatabaseListener)\n\n\ndef test_database_listener_memory():\n    _database_conforms_to_listener_api(\n        lambda path: InMemoryExampleDatabase(),\n        parent_settings=settings(max_examples=5, stateful_step_count=10),\n    )\n\n\n@skipif_emscripten\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\", reason=\"takes ages\"\n)\ndef test_database_listener_background_write():\n    _database_conforms_to_listener_api(\n        lambda path: BackgroundWriteDatabase(InMemoryExampleDatabase()),\n        flush=lambda db: db._join(),\n        parent_settings=settings(max_examples=5, stateful_step_count=10),\n    )\n\n\ndef test_can_remove_nonexistent_listener():\n    db = InMemoryExampleDatabase()\n    db.remove_listener(lambda event: event)\n\n\nclass DoesNotSupportListening(ExampleDatabase):\n    def save(self, key: bytes, value: bytes) -> None: ...\n    def fetch(self, key: bytes) -> Iterable[bytes]: ...\n    def delete(self, key: bytes, value: bytes) -> None: ...\n\n\ndef test_warns_when_listening_not_supported():\n    db = DoesNotSupportListening()\n    listener = lambda event: event\n\n    with pytest.warns(\n        HypothesisWarning, match=\"does not support listening for changes\"\n    ):\n        db.add_listener(listener)\n\n    with pytest.warns(\n        HypothesisWarning, match=\"does not support stopping listening for changes\"\n    ):\n        db.remove_listener(listener)\n\n\ndef test_readonly_listener():\n    db = ReadOnlyDatabase(InMemoryExampleDatabase())\n\n    def listener(event):\n        raise AssertionError(\"ReadOnlyDatabase never fires change events\")\n\n    db.add_listener(listener)\n    db.save(b\"a\", b\"a\")\n\n    db.remove_listener(listener)\n    db.save(b\"b\", b\"b\")\n\n\n@skipif_threading\ndef test_metakeys_move_into_existing_key(tmp_path):\n    db = DirectoryBasedExampleDatabase(tmp_path)\n    db.save(b\"k1\", b\"v1\")\n    db.save(b\"k1\", b\"v2\")\n    db.save(b\"k2\", b\"v3\")\n    assert set(db.fetch(db._metakeys_name)) == {b\"k1\", b\"k2\"}\n\n    db.move(b\"k1\", b\"k2\", b\"v2\")\n    assert set(db.fetch(db._metakeys_name)) == {b\"k1\", b\"k2\"}\n\n\n@skipif_threading\ndef test_metakeys_move_into_nonexistent_key(tmp_path):\n    db = DirectoryBasedExampleDatabase(tmp_path)\n    db.save(b\"k1\", b\"v1\")\n    assert set(db.fetch(db._metakeys_name)) == {b\"k1\"}\n\n    db.move(b\"k1\", b\"k2\", b\"v1\")\n    assert set(db.fetch(db._metakeys_name)) == {b\"k1\", b\"k2\"}\n\n\n@skipif_threading\ndef test_metakeys(tmp_path):\n    db = DirectoryBasedExampleDatabase(tmp_path)\n\n    db.save(b\"k1\", b\"v1\")\n    assert set(db.fetch(db._metakeys_name)) == {b\"k1\"}\n\n    db.save(b\"k1\", b\"v2\")\n    assert set(db.fetch(db._metakeys_name)) == {b\"k1\"}\n\n    # deleting all the values from a key removes that metakey\n    db.delete(b\"k1\", b\"v1\")\n    db.delete(b\"k1\", b\"v2\")\n    assert set(db.fetch(db._metakeys_name)) == set()\n\n    db.save(b\"k2\", b\"v1\")\n    assert set(db.fetch(db._metakeys_name)) == {b\"k2\"}\n\n\nclass TracksListens(ExampleDatabase):\n    def __init__(self):\n        super().__init__()\n        self.starts = 0\n        self.ends = 0\n\n    def save(self, key: bytes, value: bytes) -> None: ...\n    def fetch(self, key: bytes) -> Iterable[bytes]: ...\n    def delete(self, key: bytes, value: bytes) -> None: ...\n\n    def _start_listening(self):\n        self.starts += 1\n\n    def _stop_listening(self):\n        self.ends += 1\n\n\ndef test_start_end_listening():\n    db = TracksListens()\n\n    def listener1(event):\n        pass\n\n    def listener2(event):\n        pass\n\n    assert db.starts == 0\n    db.add_listener(listener1)\n    assert db.starts == 1\n    db.add_listener(listener2)\n    assert db.starts == 1\n\n    assert db.ends == 0\n    db.remove_listener(listener2)\n    assert db.ends == 0\n    db.remove_listener(listener1)\n    assert db.ends == 1\n\n    db.clear_listeners()\n    assert db.ends == 1\n\n\n@checks_deprecated_behaviour\ndef test_deprecated_example_database_path(tmp_path):\n    ExampleDatabase(tmp_path)\n\n\n@checks_deprecated_behaviour\ndef test_deprecated_example_database_memory():\n    ExampleDatabase(\":memory:\")\n\n\n@checks_deprecated_behaviour\ndef test_deprecated_example_database_no_args():\n    ExampleDatabase()\n\n\n@pytest.mark.parametrize(\n    \"db1, db2\",\n    [\n        (DirectoryBasedExampleDatabase(\"a\"), DirectoryBasedExampleDatabase(\"a\")),\n        (\n            MultiplexedDatabase(\n                DirectoryBasedExampleDatabase(\"a\"), DirectoryBasedExampleDatabase(\"b\")\n            ),\n            MultiplexedDatabase(\n                DirectoryBasedExampleDatabase(\"a\"), DirectoryBasedExampleDatabase(\"b\")\n            ),\n        ),\n        (\n            ReadOnlyDatabase(DirectoryBasedExampleDatabase(\"a\")),\n            ReadOnlyDatabase(DirectoryBasedExampleDatabase(\"a\")),\n        ),\n        (\n            GitHubArtifactDatabase(\"owner1\", \"repo1\"),\n            GitHubArtifactDatabase(\"owner1\", \"repo1\"),\n        ),\n    ],\n)\ndef test_database_equal(db1, db2):\n    assert db1 == db2\n\n\n@pytest.mark.parametrize(\n    \"db1, db2\",\n    [\n        (InMemoryExampleDatabase(), InMemoryExampleDatabase()),\n        (InMemoryExampleDatabase(), DirectoryBasedExampleDatabase(\"a\")),\n        (BackgroundWriteDatabase(InMemoryExampleDatabase()), InMemoryExampleDatabase()),\n        (DirectoryBasedExampleDatabase(\"a\"), DirectoryBasedExampleDatabase(\"b\")),\n        (\n            ReadOnlyDatabase(DirectoryBasedExampleDatabase(\"a\")),\n            ReadOnlyDatabase(DirectoryBasedExampleDatabase(\"b\")),\n        ),\n        (\n            GitHubArtifactDatabase(\"owner1\", \"repo1\"),\n            GitHubArtifactDatabase(\"owner2\", \"repo2\"),\n        ),\n    ],\n)\ndef test_database_not_equal(db1, db2):\n    assert db1 != db2\n\n\n@skipif_threading  # race in tmp_path\ndef test_directory_db_removes_empty_dirs(tmp_path):\n    db = DirectoryBasedExampleDatabase(tmp_path)\n    db.save(b\"k1\", b\"v1\")\n    db.save(b\"k1\", b\"v2\")\n    assert db._key_path(b\"k1\").exists()\n    assert set(db.fetch(db._metakeys_name)) == {b\"k1\"}\n\n    db.delete(b\"k1\", b\"v1\")\n    assert db._key_path(b\"k1\").exists()\n    assert set(db.fetch(db._metakeys_name)) == {b\"k1\"}\n\n    db.delete(b\"k1\", b\"v2\")\n    assert not db._key_path(b\"k1\").exists()\n    assert set(db.fetch(db._metakeys_name)) == set()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_datetimes.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport datetime as dt\n\nimport pytest\n\nfrom hypothesis import HealthCheck, given, settings\nfrom hypothesis.strategies import dates, datetimes, timedeltas, times\n\nfrom tests.common.debug import assert_simple_property, find_any, minimal\n\n\ndef test_can_find_positive_delta():\n    assert minimal(timedeltas(), lambda x: x.days > 0) == dt.timedelta(1)\n\n\ndef test_can_find_negative_delta():\n    assert minimal(\n        timedeltas(max_value=dt.timedelta(10**6)), lambda x: x.days < 0\n    ) == dt.timedelta(-1)\n\n\ndef test_can_find_on_the_second():\n    find_any(timedeltas(), lambda x: x.seconds == 0)\n\n\ndef test_can_find_off_the_second():\n    find_any(timedeltas(), lambda x: x.seconds != 0)\n\n\ndef test_simplifies_towards_zero_delta():\n    d = minimal(timedeltas())\n    assert d.days == d.seconds == d.microseconds == 0\n\n\ndef test_min_value_is_respected():\n    assert minimal(timedeltas(min_value=dt.timedelta(days=10))).days == 10\n\n\ndef test_max_value_is_respected():\n    assert minimal(timedeltas(max_value=dt.timedelta(days=-10))).days == -10\n\n\n@settings(suppress_health_check=list(HealthCheck))\n@given(timedeltas())\ndef test_single_timedelta(val):\n    assert_simple_property(timedeltas(val, val), lambda v: v is val)\n\n\ndef test_simplifies_towards_millenium():\n    d = minimal(datetimes())\n    assert d.year == 2000\n    assert d.month == d.day == 1\n    assert d.hour == d.minute == d.second == d.microsecond == 0\n\n\n@given(datetimes())\ndef test_default_datetimes_are_naive(dt):\n    assert dt.tzinfo is None\n\n\ndef test_bordering_on_a_leap_year():\n    x = minimal(\n        datetimes(\n            dt.datetime.min.replace(year=2003), dt.datetime.max.replace(year=2005)\n        ),\n        lambda x: x.month == 2 and x.day == 29,\n        settings=settings(max_examples=2500),\n    )\n    assert x.year == 2004\n\n\ndef test_can_find_after_the_year_2000():\n    assert minimal(dates(), lambda x: x.year > 2000).year == 2001\n\n\ndef test_can_find_before_the_year_2000():\n    assert minimal(dates(), lambda x: x.year < 2000).year == 1999\n\n\n@pytest.mark.parametrize(\"month\", range(1, 13))\ndef test_can_find_each_month(month):\n    find_any(dates(), lambda x: x.month == month, settings(max_examples=10**6))\n\n\ndef test_min_year_is_respected():\n    assert minimal(dates(min_value=dt.date.min.replace(2003))).year == 2003\n\n\ndef test_max_year_is_respected():\n    assert minimal(dates(max_value=dt.date.min.replace(1998))).year == 1998\n\n\n@given(dates())\ndef test_single_date(val):\n    assert find_any(dates(val, val)) is val\n\n\ndef test_can_find_midnight():\n    find_any(times(), lambda x: x.hour == x.minute == x.second == 0)\n\n\ndef test_can_find_non_midnight():\n    assert minimal(times(), lambda x: x.hour != 0).hour == 1\n\n\ndef test_can_find_on_the_minute():\n    find_any(times(), lambda x: x.second == 0)\n\n\ndef test_can_find_off_the_minute():\n    find_any(times(), lambda x: x.second != 0)\n\n\ndef test_simplifies_towards_midnight():\n    d = minimal(times())\n    assert d.hour == d.minute == d.second == d.microsecond == 0\n\n\ndef test_can_generate_naive_time():\n    find_any(times(), lambda d: not d.tzinfo)\n\n\n@given(times())\ndef test_naive_times_are_naive(dt):\n    assert dt.tzinfo is None\n\n\ndef test_can_generate_datetime_with_fold_1():\n    find_any(datetimes(), lambda d: d.fold)\n\n\ndef test_can_generate_time_with_fold_1():\n    find_any(times(), lambda d: d.fold)\n\n\n@given(datetimes(allow_imaginary=False))\ndef test_allow_imaginary_is_not_an_error_for_naive_datetimes(d):\n    pass\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_deadline.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport gc\nimport re\nimport time\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis.errors import DeadlineExceeded, FlakyFailure, InvalidArgument\n\nfrom tests.common.utils import assert_falsifying_output, fails_with\n\npytestmark = pytest.mark.skipif(\n    settings.get_current_profile_name() == \"threading\",\n    reason=\"takes a long time because we don't monkeypatch time\",\n)\n\n\ndef test_raises_deadline_on_slow_test():\n    @settings(deadline=500)\n    @given(st.integers())\n    def slow(i):\n        time.sleep(1)\n\n    with pytest.raises(DeadlineExceeded):\n        slow()\n\n\n@pytest.mark.skipif(\n    settings().deadline is None,\n    reason=\"not expected to fail if deadline is disabled\",\n)\n@fails_with(DeadlineExceeded)\n@given(st.integers())\ndef test_slow_tests_are_errors_by_default(i):\n    time.sleep(1)\n\n\ndef test_non_numeric_deadline_is_an_error():\n    with pytest.raises(InvalidArgument):\n        settings(deadline=\"3 seconds\")\n\n\n@given(st.integers())\n@settings(deadline=None)\ndef test_slow_with_none_deadline(i):\n    time.sleep(1)\n\n\ndef test_raises_flaky_if_a_test_becomes_fast_on_rerun():\n    once = True\n\n    @settings(deadline=500, backend=\"hypothesis\")\n    @given(st.integers())\n    def test_flaky_slow(i):\n        nonlocal once\n        if once:\n            once = False\n            time.sleep(1)\n\n    with pytest.raises(FlakyFailure):\n        test_flaky_slow()\n\n\ndef test_deadlines_participate_in_shrinking():\n    @settings(deadline=500, max_examples=1000, database=None)\n    @given(st.integers(min_value=0))\n    def slow_if_large(i):\n        if i >= 1000:\n            time.sleep(1)\n\n    assert_falsifying_output(\n        slow_if_large,\n        expected_exception=DeadlineExceeded,\n        i=1000,\n    )\n\n\ndef test_keeps_you_well_above_the_deadline():\n    seen = set()\n    failed_once = False\n\n    @settings(deadline=100, backend=\"hypothesis\")\n    @given(st.integers(0, 2000))\n    def slow(i):\n        nonlocal failed_once\n        # Make sure our initial failure isn't something that immediately goes flaky.\n        if not failed_once:\n            if i * 0.9 <= 100:\n                return\n            else:\n                failed_once = True\n\n        t = i / 1000\n        if i in seen:\n            time.sleep(0.9 * t)\n        else:\n            seen.add(i)\n            time.sleep(t)\n\n    with pytest.raises(DeadlineExceeded):\n        slow()\n\n\ndef test_gives_a_deadline_specific_flaky_error_message():\n    once = True\n\n    @settings(deadline=100, backend=\"hypothesis\")\n    @given(st.integers())\n    def slow_once(i):\n        nonlocal once\n        if once:\n            once = False\n            time.sleep(0.2)\n\n    with pytest.raises(FlakyFailure) as err:\n        slow_once()\n    assert \"Unreliable test timing\" in \"\\n\".join(err.value.__notes__)\n    # this used to be \"took 2\", but we saw that flake (on pypy, though unsure if\n    # that means anything) with \"took 199.59ms\". It's possible our gc accounting\n    # is incorrect, or we could just be running into rare non-guarantees of\n    # time.sleep.\n    assert re.search(r\"took \\d\", \"\\n\".join(err.value.__notes__))\n\n\n@pytest.mark.parametrize(\"slow_strategy\", [False, True])\n@pytest.mark.parametrize(\"slow_test\", [False, True])\ndef test_should_only_fail_a_deadline_if_the_test_is_slow(slow_strategy, slow_test):\n    s = st.integers()\n    if slow_strategy:\n        s = s.map(lambda x: time.sleep(0.08))\n\n    @settings(deadline=50)\n    @given(st.data())\n    def test(data):\n        data.draw(s)\n        if slow_test:\n            time.sleep(0.1)\n\n    if slow_test:\n        with pytest.raises(DeadlineExceeded):\n            test()\n    else:\n        test()\n\n\n@pytest.mark.skipif(not hasattr(gc, \"callbacks\"), reason=\"CPython specific gc delay\")\ndef test_should_not_fail_deadline_due_to_gc():\n    @settings(max_examples=1, deadline=50)\n    @given(st.integers())\n    def test(i):\n        before = time.perf_counter()\n        gc.collect()\n        assert time.perf_counter() - before >= 0.1  # verify that we're slow\n\n    def delay(phase, _info):\n        if phase == \"start\":\n            time.sleep(0.1)\n\n    try:\n        gc.callbacks.append(delay)\n        test()\n    finally:\n        gc.callbacks.remove(delay)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_debug_information.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\n\nimport pytest\n\nfrom hypothesis import Verbosity, given, settings, strategies as st\nfrom hypothesis.database import InMemoryExampleDatabase\n\nfrom tests.common.utils import capture_out\n\n\ndef test_reports_passes():\n    @given(st.integers())\n    @settings(\n        verbosity=Verbosity.debug, max_examples=1000, database=InMemoryExampleDatabase()\n    )\n    def test(i):\n        assert i < 10\n\n    with capture_out() as out, pytest.raises(AssertionError):\n        test()\n\n    value = out.getvalue()\n\n    assert \"minimize_individual_choices\" in value\n    assert \"calls\" in value\n    assert \"shrinks\" in value\n\n    shrinks_info = re.compile(r\"call(s?) of which ([0-9]+) shrank\")\n\n    for l in value.splitlines():\n        m = shrinks_info.search(l)\n        if m is not None and int(m.group(2)) != 0:\n            break\n    else:\n        pytest.xfail(reason=\"Sometimes the first failure is 10, and cannot shrink.\")\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_deferred_strategies.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import InvalidArgument\n\nfrom tests.common.debug import assert_no_examples, check_can_generate_examples, minimal\n\n\ndef test_binary_tree():\n    tree = st.deferred(lambda: st.integers() | st.tuples(tree, tree))\n\n    assert minimal(tree) == 0\n    assert minimal(tree, lambda x: isinstance(x, tuple)) == (0, 0)\n\n\ndef test_mutual_recursion():\n    t = st.deferred(lambda: a | b)\n    a = st.deferred(lambda: st.none() | st.tuples(st.just(\"a\"), b))\n    b = st.deferred(lambda: st.none() | st.tuples(st.just(\"b\"), a))\n\n    for c in (\"a\", \"b\"):\n        assert minimal(t, lambda x: x is not None and x[0] == c) == (c, None)  # noqa\n\n\ndef test_errors_on_non_function_define():\n    x = st.deferred(1)\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(x)\n\n\ndef test_errors_if_define_does_not_return_search_strategy():\n    x = st.deferred(lambda: 1)\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(x)\n\n\ndef test_errors_on_definition_as_self():\n    x = st.deferred(lambda: x)\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(x)\n\n\ndef test_branches_pass_through_deferred():\n    x = st.one_of(st.booleans(), st.integers())\n    y = st.deferred(lambda: x)\n    assert x.branches == y.branches\n\n\ndef test_can_draw_one_of_self():\n    x = st.deferred(lambda: st.one_of(st.booleans(), x))\n    assert minimal(x) is False\n    assert len(x.branches) == 1\n\n\ndef test_hidden_self_references_just_result_in_no_example():\n    bad = st.deferred(lambda: st.none().flatmap(lambda _: bad))\n    assert_no_examples(bad)\n\n\ndef test_self_recursive_flatmap():\n    bad = st.deferred(lambda: bad.flatmap(lambda x: st.none()))\n    assert_no_examples(bad)\n\n\ndef test_self_reference_through_one_of_can_detect_emptiness():\n    bad = st.deferred(lambda: st.one_of(bad, bad))\n    assert bad.is_empty\n\n\ndef test_self_tuple_draws_nothing():\n    x = st.deferred(lambda: st.tuples(x))\n    assert_no_examples(x)\n\n\ndef test_mutually_recursive_tuples_draw_nothing():\n    x = st.deferred(lambda: st.tuples(y))\n    y = st.tuples(x)\n\n    assert_no_examples(x)\n    assert_no_examples(y)\n\n\ndef test_literals_strategy_is_valid():\n    literals = st.deferred(\n        lambda: st.one_of(\n            st.booleans(), st.tuples(literals, literals), literals.map(lambda x: [x])\n        )\n    )\n\n    @given(literals)\n    def test(e):\n        pass\n\n    test()\n\n    assert not literals.has_reusable_values\n\n\ndef test_impossible_self_recursion():\n    x = st.deferred(lambda: st.tuples(st.none(), x))\n    assert x.is_empty\n    assert x.has_reusable_values\n\n\ndef test_very_deep_deferral():\n    # This test is designed so that the recursive properties take a very long\n    # time to converge: Although we can rapidly determine them for the original\n    # value, each round in the fixed point calculation only manages to update\n    # a single value in the related strategies, so it takes 100 rounds to\n    # update everything. Most importantly this triggers our infinite loop\n    # detection heuristic and we start tracking duplicates, but we shouldn't\n    # see any because this loop isn't infinite, just long.\n    def strat(i):\n        if i == 0:\n            return st.deferred(lambda: st.one_of([*strategies, st.none()]))\n        else:\n            return st.deferred(lambda: st.tuples(strategies[(i + 1) % len(strategies)]))\n\n    strategies = list(map(strat, range(100)))\n\n    assert strategies[0].has_reusable_values\n    assert not strategies[0].is_empty\n\n\ndef test_recursion_in_middle():\n    # This test is significant because the integers().map(abs) is not checked\n    # in the initial pass - when we recurse into x initially we decide that\n    # x is empty, so the tuple is empty, and don't need to check the third\n    # argument. Then when we do the more refined test we've discovered that x\n    # is non-empty, so we need to check the non-emptiness of the last component\n    # to determine the non-emptiness of the tuples.\n    x = st.deferred(lambda: st.tuples(st.none(), x, st.integers().map(abs)) | st.none())\n    assert not x.is_empty\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_detection.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, is_hypothesis_test\nfrom hypothesis.stateful import RuleBasedStateMachine, rule\nfrom hypothesis.strategies import integers\n\n\ndef test_functions_default_to_not_tests():\n    def foo():\n        pass\n\n    assert not is_hypothesis_test(foo)\n\n\ndef test_methods_default_to_not_tests():\n    class Foo:\n        def foo(self):\n            pass\n\n    assert not is_hypothesis_test(Foo().foo)\n\n\ndef test_detection_of_functions():\n    @given(integers())\n    def test(i):\n        pass\n\n    assert is_hypothesis_test(test)\n\n\ndef test_detection_of_methods():\n    class Foo:\n        @given(integers())\n        def test(self, i):\n            pass\n\n    assert is_hypothesis_test(Foo().test)\n\n\ndef test_detection_of_stateful_tests():\n    class Stuff(RuleBasedStateMachine):\n        @rule(x=integers())\n        def a_rule(self, x):\n            pass\n\n    assert is_hypothesis_test(Stuff.TestCase().runTest)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_direct_strategies.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport collections\nimport decimal\nimport enum\nimport fractions\nimport math\nimport warnings\nfrom datetime import date, datetime, time, timedelta\nfrom ipaddress import IPv4Network, IPv6Network\n\nimport pytest\n\nfrom hypothesis import Phase, given, settings, strategies as st\nfrom hypothesis.errors import HypothesisWarning, InvalidArgument\nfrom hypothesis.vendor.pretty import pretty\n\nfrom tests.common.debug import check_can_generate_examples, minimal\nfrom tests.common.utils import Why, xfail_on_crosshair\n\n# Use `pretty` instead of `repr` for building test names, so that set and dict\n# parameters print consistently across multiple worker processes with different\n# PYTHONHASHSEED values.\n\n\ndef fn_test(*fnkwargs):\n    fnkwargs = list(fnkwargs)\n    return pytest.mark.parametrize(\n        (\"fn\", \"args\"),\n        fnkwargs,\n        ids=[\n            \"{}({})\".format(fn.__name__, \", \".join(map(pretty, args)))\n            for fn, args in fnkwargs\n        ],\n    )\n\n\ndef fn_ktest(*fnkwargs):\n    fnkwargs = list(fnkwargs)\n    return pytest.mark.parametrize(\n        (\"fn\", \"kwargs\"),\n        fnkwargs,\n        ids=[f\"{fn.__name__}(**{pretty(kwargs)})\" for fn, kwargs in fnkwargs],\n    )\n\n\n@fn_ktest(\n    (st.integers, {\"min_value\": math.nan}),\n    (st.integers, {\"min_value\": 2, \"max_value\": 1}),\n    (st.integers, {\"min_value\": math.nan}),\n    (st.integers, {\"max_value\": math.nan}),\n    (st.integers, {\"min_value\": decimal.Decimal(\"1.5\")}),\n    (st.integers, {\"max_value\": decimal.Decimal(\"1.5\")}),\n    (st.integers, {\"min_value\": -1.5, \"max_value\": -0.5}),\n    (st.integers, {\"min_value\": 0.1, \"max_value\": 0.2}),\n    (st.dates, {\"min_value\": \"fish\"}),\n    (st.dates, {\"max_value\": \"fish\"}),\n    (st.dates, {\"min_value\": date(2017, 8, 22), \"max_value\": date(2017, 8, 21)}),\n    (st.datetimes, {\"min_value\": \"fish\"}),\n    (st.datetimes, {\"max_value\": \"fish\"}),\n    (st.datetimes, {\"allow_imaginary\": 0}),\n    (\n        st.datetimes,\n        {\"min_value\": datetime(2017, 8, 22), \"max_value\": datetime(2017, 8, 21)},\n    ),\n    (st.decimals, {\"min_value\": math.nan}),\n    (st.decimals, {\"max_value\": math.nan}),\n    (st.decimals, {\"min_value\": 2, \"max_value\": 1}),\n    (st.decimals, {\"max_value\": \"-snan\"}),\n    (st.decimals, {\"max_value\": complex(1, 2)}),\n    (st.decimals, {\"places\": -1}),\n    (st.decimals, {\"places\": 0.5}),\n    (st.decimals, {\"max_value\": 0.0, \"min_value\": 1.0}),\n    (st.decimals, {\"min_value\": 1.0, \"max_value\": 0.0}),\n    (st.decimals, {\"min_value\": 0.0, \"max_value\": 1.0, \"allow_infinity\": True}),\n    (st.decimals, {\"min_value\": \"inf\"}),\n    (st.decimals, {\"max_value\": \"-inf\"}),\n    (st.decimals, {\"min_value\": \"-inf\", \"allow_infinity\": False}),\n    (st.decimals, {\"max_value\": \"inf\", \"allow_infinity\": False}),\n    (st.decimals, {\"min_value\": complex(1, 2)}),\n    (st.decimals, {\"min_value\": \"0.1\", \"max_value\": \"0.9\", \"places\": 0}),\n    (st.decimals, {\"min_value\": fractions.Fraction(1, 3)}),\n    (st.decimals, {\"max_value\": fractions.Fraction(2, 3), \"places\": 1}),\n    (\n        st.dictionaries,\n        {\"keys\": st.booleans(), \"values\": st.booleans(), \"min_size\": 10, \"max_size\": 1},\n    ),\n    (st.floats, {\"min_value\": math.nan}),\n    (st.floats, {\"max_value\": math.nan}),\n    (st.floats, {\"min_value\": complex(1, 2)}),\n    (st.floats, {\"max_value\": complex(1, 2)}),\n    (st.floats, {\"exclude_min\": None}),\n    (st.floats, {\"exclude_max\": None}),\n    (st.floats, {\"exclude_min\": True}),  # because min_value=None\n    (st.floats, {\"exclude_max\": True}),  # because max_value=None\n    (st.floats, {\"min_value\": 1.8, \"width\": 32}),\n    (st.floats, {\"max_value\": 1.8, \"width\": 32}),\n    (st.fractions, {\"min_value\": 2, \"max_value\": 1}),\n    (st.fractions, {\"min_value\": math.nan}),\n    (st.fractions, {\"max_value\": math.nan}),\n    (st.fractions, {\"max_denominator\": 0}),\n    (st.fractions, {\"max_denominator\": 1.5}),\n    (st.fractions, {\"min_value\": complex(1, 2)}),\n    (st.fractions, {\"min_value\": \"1/3\", \"max_value\": \"1/2\", \"max_denominator\": 2}),\n    (st.fractions, {\"min_value\": \"0\", \"max_value\": \"1/3\", \"max_denominator\": 2}),\n    (st.fractions, {\"min_value\": \"1/3\", \"max_value\": \"1/3\", \"max_denominator\": 2}),\n    (st.lists, {\"elements\": st.integers(), \"min_size\": 10, \"max_size\": 9}),\n    (st.lists, {\"elements\": st.integers(), \"min_size\": -10, \"max_size\": -9}),\n    (st.lists, {\"elements\": st.integers(), \"max_size\": -9}),\n    (st.lists, {\"elements\": st.integers(), \"min_size\": -10}),\n    (st.lists, {\"elements\": st.integers(), \"min_size\": math.nan}),\n    (st.lists, {\"elements\": st.nothing(), \"max_size\": 1}),\n    (st.lists, {\"elements\": \"hi\"}),\n    (st.lists, {\"elements\": st.integers(), \"unique_by\": 1}),\n    (st.lists, {\"elements\": st.integers(), \"unique_by\": ()}),\n    (st.lists, {\"elements\": st.integers(), \"unique_by\": (1,)}),\n    (st.lists, {\"elements\": st.sampled_from([0, 1]), \"min_size\": 3, \"unique\": True}),\n    (st.lists, {\"elements\": st.none(), \"min_size\": 100_000}),\n    (st.lists, {\"elements\": st.none(), \"min_size\": 100_000, \"unique\": True}),\n    (\n        st.lists,\n        {\"elements\": st.sampled_from([1, 2]), \"min_size\": 100_000, \"unique\": True},\n    ),\n    (st.text, {\"min_size\": 10, \"max_size\": 9}),\n    (st.text, {\"alphabet\": [1]}),\n    (st.text, {\"alphabet\": [\"abc\"]}),\n    (st.text, {\"alphabet\": st.just(\"abc\")}),\n    (st.text, {\"alphabet\": st.sampled_from([\"abc\", \"def\"])}),\n    (st.text, {\"alphabet\": st.just(123)}),\n    (st.text, {\"alphabet\": st.sampled_from([123, 456])}),\n    (st.text, {\"alphabet\": st.builds(lambda: \"abc\")}),\n    (st.text, {\"alphabet\": st.builds(lambda: 123)}),\n    (st.text, {\"alphabet\": \"abc\", \"min_size\": 100_000}),\n    (st.from_regex, {\"regex\": 123}),\n    (st.from_regex, {\"regex\": b\"abc\", \"alphabet\": \"abc\"}),\n    (st.from_regex, {\"regex\": b\"abc\", \"alphabet\": b\"def\"}),\n    (st.from_regex, {\"regex\": \"abc\", \"alphabet\": \"def\"}),\n    (st.from_regex, {\"regex\": \"aa|bb\", \"alphabet\": \"c\"}),\n    (st.from_regex, {\"regex\": \"[abc]\", \"alphabet\": \"def\"}),\n    (st.from_regex, {\"regex\": \"[ab]x[de]\", \"alphabet\": \"abcdef\"}),\n    (st.from_regex, {\"regex\": \"...\", \"alphabet\": st.builds(lambda: \"a\")}),\n    (st.from_regex, {\"regex\": \"abc\", \"alphabet\": st.sampled_from(\"def\")}),\n    (st.from_regex, {\"regex\": \"abc\", \"alphabet\": st.characters(min_codepoint=128)}),\n    (st.from_regex, {\"regex\": \"abc\", \"alphabet\": 123}),\n    (st.binary, {\"min_size\": 10, \"max_size\": 9}),\n    (st.floats, {\"min_value\": math.nan}),\n    (st.floats, {\"min_value\": \"0\"}),\n    (st.floats, {\"max_value\": \"0\"}),\n    (st.floats, {\"min_value\": 0.0, \"max_value\": -0.0}),\n    (st.floats, {\"min_value\": 0.0, \"max_value\": 1.0, \"allow_infinity\": True}),\n    (st.floats, {\"max_value\": 0.0, \"min_value\": 1.0}),\n    (st.floats, {\"min_value\": 0.0, \"allow_nan\": True}),\n    (st.floats, {\"max_value\": 0.0, \"allow_nan\": True}),\n    (st.floats, {\"min_value\": 0.0, \"max_value\": 1.0, \"allow_infinity\": True}),\n    (st.floats, {\"min_value\": math.inf, \"allow_infinity\": False}),\n    (st.floats, {\"max_value\": -math.inf, \"allow_infinity\": False}),\n    (st.complex_numbers, {\"min_magnitude\": None}),\n    (st.complex_numbers, {\"min_magnitude\": math.nan}),\n    (st.complex_numbers, {\"max_magnitude\": math.nan}),\n    (st.complex_numbers, {\"max_magnitude\": complex(1, 2)}),\n    (st.complex_numbers, {\"min_magnitude\": -1}),\n    (st.complex_numbers, {\"max_magnitude\": -1}),\n    (st.complex_numbers, {\"min_magnitude\": 3, \"max_magnitude\": 2}),\n    (st.complex_numbers, {\"max_magnitude\": 2, \"allow_infinity\": True}),\n    (st.complex_numbers, {\"max_magnitude\": 2, \"allow_nan\": True}),\n    (st.complex_numbers, {\"width\": None}),\n    # Conceivable mistake when misunderstanding width for individual component widths:\n    (st.complex_numbers, {\"width\": 16}),\n    # Unsupported as of now:\n    (st.complex_numbers, {\"width\": 196}),\n    (st.complex_numbers, {\"width\": 256}),\n    (st.fixed_dictionaries, {\"mapping\": \"fish\"}),\n    (st.fixed_dictionaries, {\"mapping\": {1: \"fish\"}}),\n    (st.fixed_dictionaries, {\"mapping\": {}, \"optional\": \"fish\"}),\n    (st.fixed_dictionaries, {\"mapping\": {}, \"optional\": {1: \"fish\"}}),\n    (st.fixed_dictionaries, {\"mapping\": {}, \"optional\": collections.OrderedDict()}),\n    (st.fixed_dictionaries, {\"mapping\": {1: st.none()}, \"optional\": {1: st.none()}}),\n    (st.dictionaries, {\"keys\": st.integers(), \"values\": 1}),\n    (st.dictionaries, {\"keys\": 1, \"values\": st.integers()}),\n    (st.text, {\"alphabet\": \"\", \"min_size\": 1}),\n    (st.timedeltas, {\"min_value\": \"fish\"}),\n    (st.timedeltas, {\"max_value\": \"fish\"}),\n    (\n        st.timedeltas,\n        {\"min_value\": timedelta(hours=1), \"max_value\": timedelta(minutes=1)},\n    ),\n    (st.times, {\"min_value\": \"fish\"}),\n    (st.times, {\"max_value\": \"fish\"}),\n    (st.times, {\"min_value\": time(2, 0), \"max_value\": time(1, 0)}),\n    (st.uuids, {\"version\": 6}),\n    (st.characters, {\"min_codepoint\": -1}),\n    (st.characters, {\"min_codepoint\": \"1\"}),\n    (st.characters, {\"max_codepoint\": -1}),\n    (st.characters, {\"max_codepoint\": \"1\"}),\n    (st.characters, {\"categories\": []}),\n    (st.characters, {\"categories\": [\"Nd\"], \"exclude_categories\": [\"Nd\"]}),\n    (st.characters, {\"whitelist_categories\": [\"Nd\"], \"blacklist_categories\": [\"Nd\"]}),\n    (st.characters, {\"include_characters\": \"a\", \"blacklist_characters\": \"b\"}),\n    (st.characters, {\"codec\": 100}),\n    (st.characters, {\"codec\": \"this is not a valid codec name\"}),\n    (st.characters, {\"codec\": \"ascii\", \"include_characters\": \"é\"}),\n    (st.characters, {\"codec\": \"utf-8\", \"categories\": \"Cs\"}),\n    (st.slices, {\"size\": None}),\n    (st.slices, {\"size\": \"chips\"}),\n    (st.slices, {\"size\": -1}),\n    (st.slices, {\"size\": 2.3}),\n    (st.sampled_from, {\"elements\": ()}),\n    (st.ip_addresses, {\"v\": \"4\"}),\n    (st.ip_addresses, {\"v\": 4.0}),\n    (st.ip_addresses, {\"v\": 5}),\n    (st.ip_addresses, {\"v\": 4, \"network\": \"::/64\"}),\n    (st.ip_addresses, {\"v\": 6, \"network\": \"127.0.0.0/8\"}),\n    (st.ip_addresses, {\"network\": b\"127.0.0.0/8\"}),  # only unicode strings are valid\n    (st.ip_addresses, {\"network\": b\"::/64\"}),\n    (st.randoms, {\"use_true_random\": \"False\"}),\n    (st.randoms, {\"note_method_calls\": \"True\"}),\n)\ndef test_validates_keyword_arguments(fn, kwargs):\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(fn(**kwargs))\n\n\n@fn_ktest(\n    (st.integers, {\"min_value\": 0}),\n    (st.integers, {\"min_value\": 11}),\n    (st.integers, {\"min_value\": 11, \"max_value\": 100}),\n    (st.integers, {\"max_value\": 0}),\n    (st.integers, {\"min_value\": -2, \"max_value\": -1}),\n    (st.decimals, {\"min_value\": 1.0, \"max_value\": 1.5}),\n    (st.decimals, {\"min_value\": \"1.0\", \"max_value\": \"1.5\"}),\n    (st.decimals, {\"min_value\": decimal.Decimal(\"1.5\")}),\n    (st.decimals, {\"max_value\": 1.0, \"min_value\": -1.0, \"allow_infinity\": False}),\n    (st.decimals, {\"min_value\": 1.0, \"allow_nan\": False}),\n    (st.decimals, {\"max_value\": 1.0, \"allow_nan\": False}),\n    (st.decimals, {\"max_value\": 1.0, \"min_value\": -1.0, \"allow_nan\": False}),\n    (st.decimals, {\"min_value\": \"-inf\"}),\n    (st.decimals, {\"max_value\": \"inf\"}),\n    (st.decimals, {\"min_value\": fractions.Fraction(3, 20)}),\n    (st.decimals, {\"max_value\": fractions.Fraction(1, 8), \"places\": 10}),\n    (st.fractions, {\"min_value\": -1, \"max_value\": 1, \"max_denominator\": 1000}),\n    (st.fractions, {\"min_value\": 1, \"max_value\": 1}),\n    (st.fractions, {\"min_value\": 1, \"max_value\": 1, \"max_denominator\": 2}),\n    (st.fractions, {\"min_value\": 1.0}),\n    (st.fractions, {\"min_value\": decimal.Decimal(\"1.0\")}),\n    (st.fractions, {\"min_value\": fractions.Fraction(1, 2)}),\n    (st.fractions, {\"min_value\": \"1/2\", \"max_denominator\": 2}),\n    (st.fractions, {\"max_value\": \"1/2\", \"max_denominator\": 3}),\n    (st.lists, {\"elements\": st.nothing(), \"max_size\": 0}),\n    (st.lists, {\"elements\": st.integers()}),\n    (st.lists, {\"elements\": st.integers(), \"max_size\": 5}),\n    (st.lists, {\"elements\": st.booleans(), \"min_size\": 5}),\n    (st.lists, {\"elements\": st.booleans(), \"min_size\": 5, \"max_size\": 10}),\n    (st.sets, {\"min_size\": 10, \"max_size\": 10, \"elements\": st.integers()}),\n    (st.booleans, {}),\n    (st.just, {\"value\": \"hi\"}),\n    (st.integers, {\"min_value\": 12, \"max_value\": 12}),\n    (st.floats, {}),\n    (st.floats, {\"min_value\": 1.0}),\n    (st.floats, {\"max_value\": 1.0}),\n    (st.floats, {\"min_value\": math.inf}),\n    (st.floats, {\"max_value\": -math.inf}),\n    (st.floats, {\"max_value\": 1.0, \"min_value\": -1.0}),\n    (st.floats, {\"max_value\": 1.0, \"min_value\": -1.0, \"allow_infinity\": False}),\n    (st.floats, {\"min_value\": 1.0, \"allow_nan\": False}),\n    (st.floats, {\"max_value\": 1.0, \"allow_nan\": False}),\n    (st.floats, {\"max_value\": 1.0, \"min_value\": -1.0, \"allow_nan\": False}),\n    (st.complex_numbers, {}),\n    (st.complex_numbers, {\"min_magnitude\": 3, \"max_magnitude\": 3}),\n    (st.complex_numbers, {\"max_magnitude\": 0}),\n    (st.complex_numbers, {\"allow_nan\": True}),\n    (st.complex_numbers, {\"allow_nan\": True, \"allow_infinity\": True}),\n    (st.complex_numbers, {\"allow_nan\": True, \"allow_infinity\": False}),\n    (st.complex_numbers, {\"allow_nan\": False}),\n    (st.complex_numbers, {\"allow_nan\": False, \"allow_infinity\": True}),\n    (st.complex_numbers, {\"allow_nan\": False, \"allow_infinity\": False}),\n    (st.complex_numbers, {\"max_magnitude\": math.inf, \"allow_infinity\": True}),\n    (st.complex_numbers, {\"width\": 32}),\n    (st.complex_numbers, {\"width\": 64}),\n    (st.complex_numbers, {\"width\": 128}),\n    (st.sampled_from, {\"elements\": [1]}),\n    (st.sampled_from, {\"elements\": [1, 2, 3]}),\n    (st.fixed_dictionaries, {\"mapping\": {1: st.integers()}}),\n    (st.dictionaries, {\"keys\": st.booleans(), \"values\": st.integers()}),\n    (st.text, {\"alphabet\": \"abc\"}),\n    (st.text, {\"alphabet\": set(\"abc\")}),\n    (st.text, {\"alphabet\": \"\"}),\n    (st.text, {\"alphabet\": st.just(\"a\")}),\n    (st.text, {\"alphabet\": st.sampled_from(\"abc\")}),\n    (st.text, {\"alphabet\": st.builds(lambda: \"a\")}),\n    (st.characters, {\"codec\": \"ascii\"}),\n    (st.characters, {\"codec\": \"latin1\"}),\n    (st.characters, {\"categories\": [\"N\"]}),\n    (st.characters, {\"exclude_categories\": []}),\n    (st.characters, {\"whitelist_characters\": \"a\", \"codec\": \"ascii\"}),\n    (st.characters, {\"blacklist_characters\": \"a\"}),\n    (st.characters, {\"whitelist_categories\": [\"Nd\"]}),\n    (st.characters, {\"blacklist_categories\": [\"Nd\"]}),\n    (st.from_regex, {\"regex\": \"abc\", \"alphabet\": \"abc\"}),\n    (st.from_regex, {\"regex\": \"abc\", \"alphabet\": \"abcdef\"}),\n    (st.from_regex, {\"regex\": \"[abc]\", \"alphabet\": \"abcdef\"}),\n    (st.from_regex, {\"regex\": \"[a-f]\", \"alphabet\": \"abef\"}),\n    (st.from_regex, {\"regex\": \"[a-d]\", \"alphabet\": \"def\"}),\n    (st.from_regex, {\"regex\": \"[f-z]\", \"alphabet\": \"def\"}),\n    (st.from_regex, {\"regex\": \"abc\", \"alphabet\": st.sampled_from(\"abc\")}),\n    (st.from_regex, {\"regex\": \"abc\", \"alphabet\": st.characters(codec=\"ascii\")}),\n    (st.ip_addresses, {}),\n    (st.ip_addresses, {\"v\": 4}),\n    (st.ip_addresses, {\"v\": 6}),\n    (st.ip_addresses, {\"network\": \"127.0.0.0/8\"}),\n    (st.ip_addresses, {\"network\": \"::/64\"}),\n    (st.ip_addresses, {\"v\": 4, \"network\": \"127.0.0.0/8\"}),\n    (st.ip_addresses, {\"v\": 6, \"network\": \"::/64\"}),\n    (st.ip_addresses, {\"network\": IPv4Network(\"127.0.0.0/8\")}),\n    (st.ip_addresses, {\"network\": IPv6Network(\"::/64\")}),\n    (st.ip_addresses, {\"v\": 4, \"network\": IPv4Network(\"127.0.0.0/8\")}),\n    (st.ip_addresses, {\"v\": 6, \"network\": IPv6Network(\"::/64\")}),\n)\ndef test_produces_valid_examples_from_keyword(fn, kwargs):\n    check_can_generate_examples(fn(**kwargs))\n\n\n@fn_test(\n    (st.one_of, (1,)),\n    (st.one_of, (1, st.integers())),\n    (st.tuples, (1,)),\n)\ndef test_validates_args(fn, args):\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(fn(*args))\n\n\n@fn_test(\n    (st.one_of, (st.booleans(), st.tuples(st.booleans()))),\n    (st.one_of, (st.booleans(),)),\n    (st.text, ()),\n    (st.binary, ()),\n    (st.builds, (lambda x, y: x + y, st.integers(), st.integers())),\n)\ndef test_produces_valid_examples_from_args(fn, args):\n    check_can_generate_examples(fn(*args))\n\n\ndef test_build_class_with_target_kwarg():\n    NamedTupleWithTargetField = collections.namedtuple(\"Something\", [\"target\"])\n    check_can_generate_examples(\n        st.builds(NamedTupleWithTargetField, target=st.integers())\n    )\n\n\ndef test_builds_raises_with_no_target():\n    with pytest.raises(TypeError):\n        check_can_generate_examples(st.builds())\n\n\n@pytest.mark.parametrize(\"non_callable\", [1, \"abc\", st.integers()])\ndef test_builds_raises_if_non_callable_as_target_kwarg(non_callable):\n    with pytest.raises(TypeError):\n        check_can_generate_examples(st.builds(target=non_callable))\n\n\n@pytest.mark.parametrize(\"non_callable\", [1, \"abc\", st.integers()])\ndef test_builds_raises_if_non_callable_as_first_arg(non_callable):\n    # If there are any positional arguments, then the target (which must be\n    # callable) must be specified as the first one.\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(st.builds(non_callable, target=lambda x: x))\n\n\ndef test_tuples_raise_error_on_bad_kwargs():\n    with pytest.raises(TypeError):\n        st.tuples(stuff=\"things\")\n\n\n@given(st.lists(st.booleans(), min_size=10, max_size=10))\ndef test_has_specified_length(xs):\n    assert len(xs) == 10\n\n\n@given(st.integers(max_value=100))\n@settings(max_examples=100)\ndef test_has_upper_bound(x):\n    assert x <= 100\n\n\n@given(st.integers(min_value=100))\ndef test_has_lower_bound(x):\n    assert x >= 100\n\n\n@given(st.integers(min_value=1, max_value=2))\ndef test_is_in_bounds(x):\n    assert 1 <= x <= 2\n\n\n@given(st.fractions(min_value=-1, max_value=1, max_denominator=1000))\ndef test_fraction_is_in_bounds(x):\n    assert -1 <= x <= 1\n    assert abs(x.denominator) <= 1000\n\n\n@given(st.fractions(min_value=fractions.Fraction(1, 2)))\ndef test_fraction_gt_positive(x):\n    assert fractions.Fraction(1, 2) <= x\n\n\n@given(st.fractions(max_value=fractions.Fraction(-1, 2)))\ndef test_fraction_lt_negative(x):\n    assert x <= fractions.Fraction(-1, 2)\n\n\n@given(st.decimals(min_value=-1.5, max_value=1.5))\ndef test_decimal_is_in_bounds(x):\n    assert decimal.Decimal(\"-1.5\") <= x <= decimal.Decimal(\"1.5\")\n\n\ndef test_float_can_find_max_value_inf():\n    assert minimal(st.floats(max_value=math.inf), math.isinf) == float(\"inf\")\n    assert minimal(st.floats(min_value=0.0), math.isinf) == math.inf\n\n\ndef test_float_can_find_min_value_inf():\n    minimal(st.floats(), lambda x: x < 0 and math.isinf(x))\n    minimal(st.floats(min_value=-math.inf, max_value=0.0), math.isinf)\n\n\ndef test_can_find_none_list():\n    assert minimal(st.lists(st.none()), lambda x: len(x) >= 3) == [None] * 3\n\n\ndef test_fractions():\n    assert minimal(st.fractions(), lambda f: f >= 1) == 1\n\n\ndef test_decimals():\n    assert minimal(st.decimals(), lambda f: f.is_finite() and f >= 1) == 1\n\n\n@xfail_on_crosshair(\n    Why.undiscovered\n)  # (SampledFromStrategy.calc_label() hashes a symbolic int)\ndef test_non_float_decimal():\n    minimal(st.decimals(), lambda d: d.is_finite() and decimal.Decimal(float(d)) != d)\n\n\ndef test_produces_dictionaries_of_at_least_minimum_size():\n    t = minimal(\n        st.dictionaries(st.booleans(), st.integers(), min_size=2),\n    )\n    assert t == {False: 0, True: 0}\n\n\n@given(st.dictionaries(st.integers(), st.integers(), max_size=5))\n@settings(max_examples=50)\ndef test_dictionaries_respect_size(d):\n    assert len(d) <= 5\n\n\n@given(st.dictionaries(st.integers(), st.integers(), max_size=0))\n@settings(max_examples=50)\ndef test_dictionaries_respect_zero_size(d):\n    assert len(d) <= 5\n\n\n@given(st.lists(st.none(), max_size=5))\ndef test_none_lists_respect_max_size(ls):\n    assert len(ls) <= 5\n\n\n@given(st.lists(st.none(), max_size=5, min_size=1))\ndef test_none_lists_respect_max_and_min_size(ls):\n    assert 1 <= len(ls) <= 5\n\n\n@given(st.iterables(st.integers(), max_size=5, min_size=1))\ndef test_iterables_are_exhaustible(it):\n    for _ in it:\n        pass\n    with pytest.raises(StopIteration):\n        next(it)\n\n\ndef test_minimal_iterable():\n    assert list(minimal(st.iterables(st.integers()))) == []\n\n\n@pytest.mark.parametrize(\"parameter_name\", [\"min_value\", \"max_value\"])\n@pytest.mark.parametrize(\"value\", [-1, 0, 1])\ndef test_no_infinity_for_min_max_values(value, parameter_name):\n    kwargs = {\"allow_infinity\": False, parameter_name: value}\n\n    @given(st.floats(**kwargs))\n    def test_not_infinite(xs):\n        assert not math.isinf(xs)\n\n    test_not_infinite()\n\n\n@pytest.mark.parametrize(\"parameter_name\", [\"min_value\", \"max_value\"])\n@pytest.mark.parametrize(\"value\", [-1, 0, 1])\ndef test_no_nan_for_min_max_values(value, parameter_name):\n    kwargs = {\"allow_nan\": False, parameter_name: value}\n\n    @given(st.floats(**kwargs))\n    def test_not_nan(xs):\n        assert not math.isnan(xs)\n\n    test_not_nan()\n\n\nclass Sneaky:\n    \"\"\"It's like a strategy, but it's not a strategy.\"\"\"\n\n    is_empty = False\n    depth = 0\n    label = 0\n\n    def do_draw(self, data):\n        pass\n\n    def validate(self):\n        pass\n\n\n@pytest.mark.parametrize(\"value\", [5, Sneaky()])\n@pytest.mark.parametrize(\"label\", [None, \"not a strategy\"])\n@given(data=st.data())\ndef test_data_explicitly_rejects_non_strategies(data, value, label):\n    with pytest.raises(InvalidArgument):\n        data.draw(value, label=label)\n\n\n@given(st.integers().filter(bool).filter(lambda x: x % 3))\ndef test_chained_filter(x):\n    assert x\n    assert x % 3\n\n\ndef test_chained_filter_tracks_all_conditions():\n    s = st.integers().filter(bool).filter(lambda x: x % 3)\n    assert len(s.wrapped_strategy.flat_conditions) == 2\n\n\n@pytest.mark.parametrize(\"version\", [4, 6])\n@given(data=st.data())\ndef test_ipaddress_from_network_is_always_correct_version(data, version):\n    ip = data.draw(st.ip_addresses(v=version), label=\"address\")\n    assert ip.version == version\n\n\n@given(data=st.data(), network=st.from_type(IPv4Network) | st.from_type(IPv6Network))\ndef test_ipaddress_from_network_is_always_in_network(data, network):\n    ip = data.draw(st.ip_addresses(network=network), label=\"address\")\n    assert ip in network\n    assert ip.version == network.version\n\n\nclass AnEnum(enum.Enum):\n    a = 1\n\n\ndef requires_arg(value):\n    \"\"\"Similar to the enum.Enum.__call__ method.\"\"\"\n\n\n@given(st.data())\ndef test_builds_error_messages(data):\n    # If we call them directly, we get a simple TypeError in both cases\n    with pytest.raises(TypeError):\n        requires_arg()\n    with pytest.raises(TypeError):\n        AnEnum()\n    # But we have an improved error message if you try to build an Enum\n    assert issubclass(InvalidArgument, TypeError)  # it's a valid substitution\n    with pytest.raises(TypeError):  # which only applies to enums\n        data.draw(st.builds(requires_arg))\n    with pytest.raises(\n        InvalidArgument,\n        match=r\".* try using sampled_from\\(.+\\) instead of builds\\(.+\\)\",\n    ):\n        data.draw(st.builds(AnEnum))\n    # and sampled_from() does in fact work\n    data.draw(st.sampled_from(AnEnum))\n\n\n@pytest.mark.parametrize(\n    \"strat_a,strat_b\",\n    [\n        pytest.param(\n            st.integers(),\n            st.integers(0),\n            marks=pytest.mark.xfail(\n                # this is the exception raised by failed pytest.warns(),\n                # ref https://github.com/pytest-dev/pytest/issues/8928\n                raises=pytest.fail.Exception,\n                strict=True,\n                reason=\"constraints not checked\",\n            ),\n        ),\n        (st.builds(int), st.builds(float)),\n        (st.none(), st.integers()),\n        (\n            st.composite(lambda draw: draw(st.none()))(),\n            st.composite(lambda draw: draw(st.integers()))(),\n        ),\n    ],\n)\ndef test_incompatible_shared_strategies_warns(strat_a, strat_b):\n    shared_a = st.shared(strat_a, key=\"share\")\n    shared_b = st.shared(strat_b, key=\"share\")\n\n    @given(shared_a, shared_b)\n    @settings(max_examples=10, phases=[Phase.generate])\n    def test_it(a, b):\n        assert a == b\n\n    with pytest.warns(HypothesisWarning, match=\"Different strategies\"):\n        test_it()\n\n\n@st.composite\ndef _composite1(draw):\n    return draw(st.integers())\n\n\n@st.composite\ndef _composite2(draw):\n    return draw(st.integers())\n\n\n@pytest.mark.parametrize(\n    \"strat_a,strat_b\",\n    [\n        (st.floats(allow_nan=False), st.floats(allow_nan=False)),\n        (st.builds(float), st.builds(float)),\n        (_composite1(), _composite1()),\n        (\n            st.floats(allow_nan=False, allow_infinity=False),\n            st.floats(allow_nan=False, allow_infinity=0),\n        ),\n        (_composite1(), _composite2()),\n        pytest.param(\n            st.integers().flatmap(st.just),\n            st.integers(),\n            marks=pytest.mark.xfail(\n                raises=HypothesisWarning,\n                strict=True,\n                reason=\"really different (but compatible)\",\n            ),\n        ),\n    ],\n)\ndef test_compatible_shared_strategies_do_not_warn(strat_a, strat_b):\n    shared_a = st.shared(strat_a, key=\"share\")\n    shared_b = st.shared(strat_b, key=\"share\")\n\n    @given(shared_a, shared_b)\n    @settings(max_examples=10, phases=[Phase.generate])\n    def test_it(a, b):\n        assert a == b\n\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"error\", HypothesisWarning)\n        test_it()\n\n\ndef test_compatible_nested_shared_strategies_do_not_warn():\n    shared_a = st.shared(st.integers(), key=\"share\")\n    shared_b = st.shared(st.integers(), key=\"share\")\n    shared_c = st.shared(shared_a, key=\"nested_share\")\n    shared_d = st.shared(shared_b, key=\"nested_share\")\n\n    @given(shared_a, shared_b, shared_c, shared_d)\n    @settings(max_examples=10, phases=[Phase.generate])\n    def test_it(a, b, c, d):\n        assert a == b == c == d\n\n    test_it()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_draw_example.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis.strategies import lists\n\nfrom tests.common import standard_types\nfrom tests.common.debug import check_can_generate_examples\n\n\n@pytest.mark.parametrize(\"spec\", standard_types, ids=repr)\ndef test_single_example(spec):\n    check_can_generate_examples(spec)\n\n\n@pytest.mark.parametrize(\"spec\", standard_types, ids=repr)\ndef test_list_example(spec):\n    check_can_generate_examples(lists(spec))\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_error_in_draw.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import HypothesisWarning\nfrom hypothesis.stateful import RuleBasedStateMachine, rule, run_state_machine_as_test\n\n\ndef test_error_is_in_finally():\n    @given(st.data())\n    def test(d):\n        try:\n            d.draw(st.lists(st.integers(), min_size=3, unique=True))\n        finally:\n            raise ValueError\n\n    with pytest.raises(ValueError) as err:\n        test()\n\n    assert \"[0, 1, -1]\" in \"\\n\".join(err.value.__notes__)\n\n\n@given(st.data())\ndef test_warns_on_bool_strategy(data):\n    with pytest.warns(\n        HypothesisWarning,\n        match=r\"bool\\(.+\\) is always True, did you mean to draw a value\\?\",\n    ):\n        if st.booleans():  # 'forgot' to draw from the strategy\n            pass\n\n\ndef test_adds_note_showing_which_strategy():\n    class X:\n        def __init__(self, y: int) -> None:\n            assert y == 7\n\n    @given(...)\n    def inner(value: X):\n        assert isinstance(value, X)\n\n    rep = re.escape(repr(st.from_type(X)))\n    with pytest.raises(AssertionError, match=f\".*while generating 'value' from {rep}\"):\n        inner()\n\n\ndef test_adds_note_showing_which_strategy_stateful():\n    strategy = st.integers().map(lambda x: x / 0)\n\n    class Machine(RuleBasedStateMachine):\n        @rule(value=strategy)\n        def take_a_step(self, value):\n            assert value\n\n    msg = f\"while generating 'value' from {strategy!r} for rule take_a_step\"\n    print(msg)\n    with pytest.raises(ZeroDivisionError, match=f\".*{re.escape(msg)}\"):\n        run_state_machine_as_test(Machine)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_escalation.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\n\nimport pytest\n\nimport hypothesis\nfrom hypothesis import errors\nfrom hypothesis.internal import escalation as esc\nfrom hypothesis.internal.compat import BaseExceptionGroup\n\n\ndef test_is_hypothesis_file_not_confused_by_prefix(monkeypatch):\n    # Errors in third-party extensions such as `hypothesis-trio` or\n    # `hypothesis-jsonschema` used to be incorrectly considered to be\n    # Hypothesis internal errors, which could result in confusing error\n    # messages. This test makes sure that files like:\n    # `[...]/python3.12/site-packages/hypothesis_something/[...]`\n    # are not considered as hypothesis files.\n    root = os.path.dirname(hypothesis.__file__)\n    assert esc.is_hypothesis_file(hypothesis.__file__)\n    assert esc.is_hypothesis_file(esc.__file__)\n\n    assert not esc.is_hypothesis_file(pytest.__file__)\n    assert not esc.is_hypothesis_file(root + \"-suffix\")\n    assert not esc.is_hypothesis_file(root + \"-suffix/something.py\")\n\n\n@pytest.mark.parametrize(\"fname\", [\"\", \"<ipython-input-18-f7c304bea5eb>\"])\ndef test_is_hypothesis_file_does_not_error_on_invalid_paths_issue_2319(fname):\n    assert not esc.is_hypothesis_file(fname)\n\n\ndef test_multiplefailures_deprecation():\n    with pytest.warns(errors.HypothesisDeprecationWarning):\n        exc = errors.MultipleFailures\n    assert exc is BaseExceptionGroup\n\n\ndef test_errors_attribute_error():\n    with pytest.raises(AttributeError):\n        errors.ThisIsNotARealAttributeDontCreateSomethingWithThisName\n\n\ndef test_handles_null_traceback():\n    esc.InterestingOrigin.from_exception(Exception())\n\n\ndef test_handles_context():\n    e = ValueError()\n    e.__context__ = KeyError()\n    origin = esc.InterestingOrigin.from_exception(e)\n    assert \"ValueError at \" in str(origin)\n    assert \"  context: \" in str(origin)\n    assert \"KeyError at \" in str(origin)\n\n\ndef test_handles_groups():\n    origin = esc.InterestingOrigin.from_exception(\n        BaseExceptionGroup(\"message\", [ValueError(\"msg2\")])\n    )\n    assert \"ExceptionGroup at \" in str(origin)\n    assert \"child exception\" in str(origin)\n    assert \"ValueError at \" in str(origin)\n\n\ndef make_exceptions_with_cycles():\n    err = ValueError()\n    err.__context__ = err\n    yield err\n\n    err = TypeError()\n    err.__context__ = BaseExceptionGroup(\"msg\", [err])\n    yield err\n\n    inner = LookupError()\n    err = BaseExceptionGroup(\"msg\", [inner])\n    inner.__context__ = err\n    yield err\n\n    inner = OSError()\n    yield BaseExceptionGroup(\"msg\", [inner, inner, inner])\n\n\n@pytest.mark.parametrize(\"err\", list(make_exceptions_with_cycles()))\ndef test_handles_cycles(err):\n    esc.InterestingOrigin.from_exception(err)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_example.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import example, given, strategies as st\nfrom hypothesis.errors import InvalidArgument\n\nfrom tests.common.utils import fails_with\n\n\n@example(False).via(\"Manually specified\")\n@given(st.booleans())\ndef test_ok_example_via(x):\n    pass\n\n\ndef test_invalid_example_via():\n    with pytest.raises(InvalidArgument):\n        example(x=False).via(100)  # not a string!\n    with pytest.raises(TypeError):\n        example(x=False).via(\"abc\", \"def\")  # too many args\n\n\n@pytest.mark.parametrize(\n    \"kw\",\n    [\n        {\"condition\": None},  # must be a bool\n        {\"reason\": None},  # must be a string\n        {\"raises\": None},  # not a BaseException (or even a type)\n        {\"raises\": int},  # not a BaseException\n        {\"raises\": [Exception]},  # not a tuple\n        {\"raises\": (None,)},  # tuple containing a non-BaseException\n        {\"raises\": ()},  # empty tuple doesn't make sense here\n        # raising non-failure exceptions, eg KeyboardInterrupt, is tested below\n    ],\n    ids=repr,\n)\ndef test_invalid_example_xfail_arguments(kw):\n    with pytest.raises(InvalidArgument):\n        example(x=False).xfail(**kw)\n\n\n@example(True).xfail()\n@example(True).xfail(reason=\"ignored for passing tests\")\n@example(True).xfail(raises=KeyError)\n@example(True).xfail(raises=(KeyError, ValueError))\n@example(True).xfail(True, reason=\"...\")\n@example(False).xfail(condition=False)\n@given(st.none())\ndef test_many_xfail_example_decorators(fails):\n    if fails:\n        raise KeyError\n\n\n@fails_with(AssertionError)\n@example(x=True).xfail(raises=KeyError)\n@given(st.none())\ndef test_xfail_reraises_non_specified_exception(x):\n    assert not x\n\n\n@fails_with(\n    InvalidArgument,\n    match=r\"@example\\(x=True\\) raised an expected BaseException\\('msg'\\), \"\n    r\"but Hypothesis does not treat this as a test failure\",\n)\n@example(True).xfail()\n@given(st.none())\ndef test_must_raise_a_failure_exception(x):\n    if x:\n        raise BaseException(\"msg\")\n\n\n@fails_with(\n    AssertionError,\n    match=r\"Expected an exception from @example\\(x=None\\), but no exception was raised.\",\n)\n@example(None).xfail()\n@given(st.none())\ndef test_error_on_unexpected_pass_base(x):\n    pass\n\n\n@fails_with(\n    AssertionError,\n    match=r\"Expected an AssertionError from @example\\(x=None\\), but no exception was raised.\",\n)\n@example(None).xfail(raises=AssertionError)\n@given(st.none())\ndef test_error_on_unexpected_pass_single(x):\n    pass\n\n\n@fails_with(\n    AssertionError,\n    match=r\"Expected an AssertionError from @example\\(x=None\\), but no exception was raised.\",\n)\n@example(None).xfail(raises=(AssertionError,))\n@given(st.none())\ndef test_error_on_unexpected_pass_single_elem_tuple(x):\n    pass\n\n\n@fails_with(\n    AssertionError,\n    match=r\"Expected a KeyError, or ValueError from @example\\(x=None\\), but no exception was raised.\",\n)\n@example(None).xfail(raises=(KeyError, ValueError))\n@given(st.none())\ndef test_error_on_unexpected_pass_multi(x):\n    pass\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_exceptiongroup.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom contextlib import suppress\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import Flaky, FlakyBackendFailure, FlakyFailure, Frozen, StopTest\nfrom hypothesis.internal.compat import BaseExceptionGroup, ExceptionGroup\nfrom hypothesis.strategies import DataObject\n\n\ndef test_discard_frozen() -> None:\n    @given(st.data())\n    def discard_frozen(data: DataObject) -> None:\n        # Accessing .conjecture_data is internal API. Other possible ways of freezing\n        # data might go through ConjectureRunner.cached_test_function_ir or\n        # ConjectureRunner.test_function\n        data.conjecture_data.freeze()\n        # Raising Frozen doesn't actually do anything, what matters is\n        # whether the data is frozen.\n        raise ExceptionGroup(\"\", [Frozen()])\n\n    discard_frozen()\n\n\ndef test_discard_multiple_frozen() -> None:\n    @given(st.data())\n    def discard_multiple_frozen(data: DataObject) -> None:\n        data.conjecture_data.freeze()\n        raise ExceptionGroup(\"\", [Frozen(), Frozen()])\n\n    discard_multiple_frozen()\n\n\ndef test_user_error_and_frozen() -> None:\n    @given(st.data())\n    def user_error_and_frozen(data: DataObject) -> None:\n        raise ExceptionGroup(\"\", [Frozen(), TypeError()])\n\n    with pytest.raises(ExceptionGroup) as excinfo:\n        user_error_and_frozen()\n    e = excinfo.value\n    assert isinstance(e, ExceptionGroup)\n    assert len(e.exceptions) == 2\n    assert isinstance(e.exceptions[0], Frozen)\n    assert isinstance(e.exceptions[1], TypeError)\n\n\ndef test_user_error_and_stoptest() -> None:\n    # if the code base had \"proper\" handling of exceptiongroups, the StopTest would\n    # probably be handled by an except*.\n    # TODO: which I suppose is an argument in favor of stripping it??\n    @given(st.data())\n    def user_error_and_stoptest(data: DataObject) -> None:\n        raise BaseExceptionGroup(\n            \"\", [StopTest(data.conjecture_data.testcounter), TypeError()]\n        )\n\n    with pytest.raises(BaseExceptionGroup) as excinfo:\n        user_error_and_stoptest()\n    e = excinfo.value\n    assert isinstance(e, BaseExceptionGroup)\n    assert len(e.exceptions) == 2\n    assert isinstance(e.exceptions[0], StopTest)\n    assert isinstance(e.exceptions[1], TypeError)\n\n\ndef test_lone_user_error() -> None:\n    # we don't want to unwrap exceptiongroups, since they might contain\n    # useful debugging info\n    @given(st.data())\n    def lone_user_error(data: DataObject) -> None:\n        raise ExceptionGroup(\"foo\", [TypeError()])\n\n    with pytest.raises(ExceptionGroup) as excinfo:\n        lone_user_error()\n    e = excinfo.value\n    assert isinstance(e, ExceptionGroup)\n    assert len(e.exceptions) == 1\n    assert isinstance(e.exceptions[0], TypeError)\n\n\ndef test_nested_stoptest() -> None:\n    @given(st.data())\n    def nested_stoptest(data: DataObject) -> None:\n        raise BaseExceptionGroup(\n            \"\",\n            [BaseExceptionGroup(\"\", [StopTest(data.conjecture_data.testcounter)])],\n        )\n\n    nested_stoptest()\n\n\ndef test_frozen_and_stoptest() -> None:\n    # frozen+stoptest => strip frozen and let engine handle StopTest\n    # actually.. I don't think I've got a live repo for this either.\n    @given(st.data())\n    def frozen_and_stoptest(data: DataObject) -> None:\n        raise BaseExceptionGroup(\n            \"\", [StopTest(data.conjecture_data.testcounter), Frozen()]\n        )\n\n    frozen_and_stoptest()\n\n\ndef test_multiple_stoptest_1() -> None:\n    # multiple stoptest, reraise the one with lowest testcounter\n    @given(st.data())\n    def multiple_stoptest(data: DataObject) -> None:\n        c = data.conjecture_data.testcounter\n        raise BaseExceptionGroup(\"\", [StopTest(c), StopTest(c + 1)])\n\n    multiple_stoptest()\n\n\ndef test_multiple_stoptest_2() -> None:\n    # the lower value is raised, which does not match data.conjecture_data.testcounter\n    # so it is not handled by the engine\n    @given(st.data())\n    def multiple_stoptest_2(data: DataObject) -> None:\n        c = data.conjecture_data.testcounter\n        raise BaseExceptionGroup(\"\", [StopTest(c), StopTest(c - 1)])\n\n    with pytest.raises(StopTest):\n        multiple_stoptest_2()\n\n\ndef test_stoptest_and_hypothesisexception() -> None:\n    # current code raises the first hypothesisexception and throws away stoptest\n    @given(st.data())\n    def stoptest_and_hypothesisexception(data: DataObject) -> None:\n        c = data.conjecture_data.testcounter\n        raise BaseExceptionGroup(\"\", [StopTest(c), Flaky()])\n\n    with pytest.raises(Flaky):\n        stoptest_and_hypothesisexception()\n\n\ndef test_multiple_hypothesisexception() -> None:\n    # this can happen in several ways, see nocover/test_exceptiongroup.py\n    @given(st.data())\n    def stoptest_and_hypothesisexception(data: DataObject) -> None:\n        c = data.conjecture_data.testcounter\n        raise BaseExceptionGroup(\"\", [StopTest(c), Flaky()])\n\n    with pytest.raises(Flaky):\n        stoptest_and_hypothesisexception()\n\n\n@pytest.mark.parametrize(\"ExceptionClass\", [FlakyFailure, FlakyBackendFailure])\ndef test_exceptiongroups_reconstruct_original_type(ExceptionClass):\n    # contextlib.suppress uses .split, and if ExceptionClass does not implement\n    # .derive, .split will return a standard ExceptionGroup instead of\n    # ExceptionClass.\n    # see https://github.com/python/cpython/issues/119287\n    class UnrelatedException(Exception):\n        pass\n\n    with pytest.raises(ExceptionClass), suppress(UnrelatedException):\n        raise ExceptionClass(\"exception message\", [Exception()])\n\n\n@pytest.mark.parametrize(\"ExceptionClass\", [FlakyFailure, FlakyBackendFailure])\ndef test_derived_exception_group(ExceptionClass):\n    exception = ExceptionClass(\"exception message\", [Exception()])\n    # we don't expect a match, we just want to test .derive.\n    match, rest = exception.split(())\n    assert match is None\n    assert isinstance(rest, ExceptionClass)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_executors.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport inspect\nfrom unittest import TestCase\n\nimport pytest\n\nfrom hypothesis import example, given\nfrom hypothesis.strategies import booleans, integers\n\n\ndef test_must_use_result_of_test():\n    class DoubleRun:\n        def execute_example(self, function):\n            x = function()\n            if inspect.isfunction(x):\n                return x()\n\n        @given(booleans())\n        def boom(self, b):\n            def f():\n                raise ValueError\n\n            return f\n\n    with pytest.raises(ValueError):\n        DoubleRun().boom()\n\n\nclass TestTryReallyHard(TestCase):\n    @given(integers())\n    def test_something(self, i):\n        pass\n\n    def execute_example(self, f):\n        f()\n        return f()\n\n\nclass Valueless:\n    def execute_example(self, f):\n        try:\n            return f()\n        except ValueError:\n            return None\n\n    @given(integers())\n    @example(1)\n    def test_no_boom_on_example(self, x):\n        raise ValueError\n\n    @given(integers())\n    def test_no_boom(self, x):\n        raise ValueError\n\n    @given(integers())\n    def test_boom(self, x):\n        raise AssertionError\n\n\ndef test_boom():\n    with pytest.raises(AssertionError):\n        Valueless().test_boom()\n\n\ndef test_no_boom():\n    Valueless().test_no_boom()\n\n\ndef test_no_boom_on_example():\n    Valueless().test_no_boom_on_example()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_explicit_examples.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport time\nfrom unittest import TestCase\n\nimport pytest\n\nfrom hypothesis import (\n    Phase,\n    Verbosity,\n    assume,\n    example,\n    given,\n    note,\n    reporting,\n    settings,\n)\nfrom hypothesis.errors import DeadlineExceeded, HypothesisWarning, InvalidArgument\nfrom hypothesis.internal.compat import ExceptionGroup\nfrom hypothesis.strategies import floats, integers, text\n\nfrom tests.common.utils import (\n    assert_falsifying_output,\n    capture_out,\n    fails_with,\n    skipif_threading,\n)\n\n\nclass TestInstanceMethods(TestCase):\n    @given(integers())\n    @example(1)\n    def test_hi_1(self, x):\n        assert isinstance(x, int)\n\n    @given(integers())\n    @example(x=1)\n    def test_hi_2(self, x):\n        assert isinstance(x, int)\n\n    @given(x=integers())\n    @example(x=1)\n    def test_hi_3(self, x):\n        assert isinstance(x, int)\n\n\ndef test_kwarg_example_on_testcase():\n    class Stuff(TestCase):\n        @given(integers())\n        @example(x=1)\n        def test_hi(self, x):\n            assert isinstance(x, int)\n\n    Stuff(\"test_hi\").test_hi()\n\n\ndef test_errors_when_run_with_not_enough_args():\n    @given(integers(), int)\n    @example(1)\n    def foo(x, y):\n        pass\n\n    with pytest.raises(TypeError):\n        foo()\n\n\ndef test_errors_when_run_with_not_enough_kwargs():\n    @given(integers(), int)\n    @example(x=1)\n    def foo(x, y):\n        pass\n\n    with pytest.raises(TypeError):\n        foo()\n\n\ndef test_can_use_examples_after_given():\n    long_str = \"This is a very long string that you've no chance of hitting\"\n\n    @example(long_str)\n    @given(text())\n    def test_not_long_str(x):\n        assert x != long_str\n\n    with pytest.raises(AssertionError):\n        test_not_long_str()\n\n\ndef test_can_use_examples_before_given():\n    long_str = \"This is a very long string that you've no chance of hitting\"\n\n    @given(text())\n    @example(long_str)\n    def test_not_long_str(x):\n        assert x != long_str\n\n    with pytest.raises(AssertionError):\n        test_not_long_str()\n\n\ndef test_can_use_examples_around_given():\n    long_str = \"This is a very long string that you've no chance of hitting\"\n    short_str = \"Still no chance\"\n\n    seen = []\n\n    @example(short_str)\n    @given(text())\n    @example(long_str)\n    def test_not_long_str(x):\n        seen.append(x)\n\n    test_not_long_str()\n    assert set(seen[:2]) == {long_str, short_str}\n\n\n@pytest.mark.parametrize((\"x\", \"y\"), [(1, False), (2, True)])\n@example(z=10)\n@given(z=integers())\ndef test_is_a_thing(x, y, z):\n    pass\n\n\ndef test_no_args_and_kwargs():\n    with pytest.raises(InvalidArgument):\n        example(1, y=2)\n\n\ndef test_no_empty_examples():\n    with pytest.raises(InvalidArgument):\n        example()\n\n\ndef test_does_not_print_on_explicit_examples_if_no_failure():\n    @example(1)\n    @given(integers())\n    def test_positive(x):\n        assert x > 0\n\n    with (\n        reporting.with_reporter(reporting.default),\n        pytest.raises(AssertionError),\n        capture_out() as out,\n    ):\n        test_positive()\n    out = out.getvalue()\n    assert \"Falsifying example: test_positive(1)\" not in out\n\n\ndef test_prints_output_for_explicit_examples():\n    @example(-1)\n    @given(integers())\n    def test_positive(x):\n        assert x > 0\n\n    assert_falsifying_output(test_positive, \"Falsifying explicit\", x=-1)\n\n\ndef test_prints_verbose_output_for_explicit_examples():\n    @settings(verbosity=Verbosity.verbose)\n    @example(\"NOT AN INTEGER\")\n    @given(integers())\n    def test_always_passes(x):\n        pass\n\n    assert_falsifying_output(\n        test_always_passes,\n        expected_exception=None,\n        example_type=\"Trying explicit\",\n        x=\"NOT AN INTEGER\",\n    )\n\n\ndef test_captures_original_repr_of_example():\n    @example(x=[])\n    @given(integers())\n    def test_mutation(x):\n        x.append(1)\n        assert not x\n\n    assert_falsifying_output(test_mutation, \"Falsifying explicit\", x=[])\n\n\ndef test_examples_are_tried_in_order():\n    @example(x=1)\n    @example(x=2)\n    @given(integers())\n    @settings(phases=[Phase.explicit])\n    @example(x=3)\n    def test(x):\n        print(f\"x -> {x}\")\n\n    with capture_out() as out, reporting.with_reporter(reporting.default):\n        test()\n    ls = out.getvalue().splitlines()\n    assert ls == [\"x -> 1\", \"x -> 2\", \"x -> 3\"]\n\n\ndef test_prints_note_in_failing_example():\n    @example(x=42)\n    @example(x=43)\n    @given(integers())\n    def test(x):\n        note(f\"x -> {x}\")\n        assert x == 42\n\n    with pytest.raises(AssertionError) as err:\n        test()\n    assert \"x -> 43\" in err.value.__notes__\n    assert \"x -> 42\" not in err.value.__notes__\n\n\ndef test_must_agree_with_number_of_arguments():\n    @example(1, 2)\n    @given(integers())\n    def test(a):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        test()\n\n\n@skipif_threading  # deadline disabled under threading\n@fails_with(DeadlineExceeded)\n@example(10)\n@settings(phases=[Phase.explicit], deadline=1)\n@given(integers())\ndef test(x):\n    time.sleep(10)\n\n\n@given(value=floats(0, 1))\n@example(value=0.56789)\n@pytest.mark.parametrize(\"threshold\", [0.5, 1])\ndef test_unsatisfied_assumption_during_explicit_example(threshold, value):\n    # Regression test, expected to pass / skip depending on parametrize.\n    # See https://github.com/HypothesisWorks/hypothesis/issues/2125\n    assume(value < threshold)\n\n\n@pytest.mark.parametrize(\"exc\", [ExceptionGroup, AssertionError])\ndef test_multiple_example_reporting(exc):\n    @example(1)\n    @example(2)\n    @settings(report_multiple_bugs=exc is ExceptionGroup, phases=[Phase.explicit])\n    @given(integers())\n    def inner_test_multiple_failing_examples(x):\n        assert x < 2\n        assert x < 1\n\n    with pytest.raises(exc):\n        inner_test_multiple_failing_examples()\n\n\ndef test_simplifies_multiple_examples_with_same_error():\n    # When multiple examples fail with the same error, only the simplest is shown\n    @example(x=1000)\n    @example(x=1)\n    @example(x=100)\n    @settings(report_multiple_bugs=True, phases=[Phase.explicit])\n    @given(x=integers())\n    def test_fn(x):\n        assert x < 0\n\n    with pytest.raises(AssertionError) as exc_info:\n        test_fn()\n\n    err = exc_info.value\n    # Should show note about other examples\n    assert any(\n        \"2 other explicit examples also failed\" in note for note in err.__notes__\n    )\n    # Should show the simplest example (x=1 is shorter than x=100 or x=1000)\n    assert any(\"x=1,\" in note for note in err.__notes__)\n\n\ndef test_shows_all_examples_at_verbose():\n    # At verbose, all examples with same error should be shown\n    @example(x=1000)\n    @example(x=1)\n    @settings(\n        report_multiple_bugs=True, phases=[Phase.explicit], verbosity=Verbosity.verbose\n    )\n    @given(x=integers())\n    def test_fn(x):\n        assert x < 0\n\n    with pytest.raises(ExceptionGroup) as exc_info:\n        test_fn()\n\n    group = exc_info.value\n    # Both examples should be shown\n    assert len(group.exceptions) == 2\n    # No simplification note should be present\n    for exc in group.exceptions:\n        assert not any(\n            \"other explicit example\" in note for note in getattr(exc, \"__notes__\", [])\n        )\n\n\ndef test_different_errors_not_simplified():\n    # Examples with different errors should all be shown\n    @example(x=1)\n    @example(x=2)\n    @settings(report_multiple_bugs=True, phases=[Phase.explicit])\n    @given(x=integers())\n    def test_fn(x):\n        if x == 1:\n            raise ValueError(\"one\")\n        raise TypeError(\"two\")\n\n    with pytest.raises(ExceptionGroup) as exc_info:\n        test_fn()\n\n    assert {type(e) for e in exc_info.value.exceptions} == {ValueError, TypeError}\n\n\n@example(text())\n@given(text())\ndef test_example_decorator_accepts_strategies(s):\n    \"\"\"The custom error message only happens when the test has already failed.\"\"\"\n\n\ndef test_helpful_message_when_example_fails_because_it_was_passed_a_strategy():\n    @example(text())\n    @given(text())\n    def t(s):\n        assert isinstance(s, str)\n\n    try:\n        t()\n    except HypothesisWarning as err:\n        assert isinstance(err.__cause__, AssertionError)\n    else:\n        raise NotImplementedError(\"should be unreachable\")\n\n\ndef test_stop_silently_dropping_examples_when_decorator_is_applied_to_itself():\n    def f():\n        pass\n\n    test = example(\"outer\")(example(\"inner\"))(f)\n    assert len(test.hypothesis_explicit_examples) == 2\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_falsifying_example_output.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import Phase, example, given, settings, strategies as st\n\nOUTPUT_WITH_BREAK = \"\"\"\nFalsifying explicit example: test(\n    x={0!r},\n    y={0!r},\n)\n\"\"\"\n\n\n@pytest.mark.parametrize(\"n\", [10, 100])\ndef test_inserts_line_breaks_only_at_appropriate_lengths(n):\n    @example(\"0\" * n, \"0\" * n)\n    @given(st.text(), st.text())\n    def test(x, y):\n        assert x < y\n\n    with pytest.raises(AssertionError) as err:\n        test()\n\n    assert OUTPUT_WITH_BREAK.format(\"0\" * n).strip() == \"\\n\".join(err.value.__notes__)\n\n\n@given(kw=st.none())\ndef generate_phase(*args, kw):\n    assert args != (1, 2, 3)\n\n\n@given(kw=st.none())\n@example(kw=None)\n@settings(phases=[Phase.explicit])\ndef explicit_phase(*args, kw):\n    assert args != (1, 2, 3)\n\n\n@pytest.mark.parametrize(\n    \"fn\",\n    [generate_phase, explicit_phase],\n    ids=lambda fn: fn.__name__,\n)\ndef test_vararg_output(fn):\n    with pytest.raises(AssertionError) as err:\n        fn(1, 2, 3)\n\n    assert \"1,\\n    2,\\n    3,\\n\" in \"\\n\".join(err.value.__notes__)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_feature_flags.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.strategies._internal.featureflags import FeatureFlags, FeatureStrategy\n\nfrom tests.common.debug import find_any, minimal\n\nSTRAT = FeatureStrategy()\n\n\ndef test_can_all_be_enabled():\n    find_any(STRAT, lambda x: all(x.is_enabled(i) for i in range(100)))\n\n\ndef test_minimizes_open():\n    features = range(10)\n\n    flags = minimal(STRAT, lambda x: [x.is_enabled(i) for i in features])\n\n    assert all(flags.is_enabled(i) for i in features)\n\n\ndef test_minimizes_individual_features_to_open():\n    features = list(range(10))\n\n    flags = minimal(\n        STRAT, lambda x: sum(x.is_enabled(i) for i in features) < len(features)\n    )\n\n    assert all(flags.is_enabled(i) for i in features[:-1])\n    assert not flags.is_enabled(features[-1])\n\n\ndef test_marks_unknown_features_as_enabled():\n    x = find_any(STRAT, lambda v: True)\n\n    assert x.is_enabled(\"fish\")\n\n\ndef test_by_default_all_enabled():\n    f = FeatureFlags()\n\n    assert f.is_enabled(\"foo\")\n\n\ndef test_eval_featureflags_repr():\n    flags = FeatureFlags(enabled=[\"on\"], disabled=[\"off\"])\n    assert flags.is_enabled(\"on\")\n    assert not flags.is_enabled(\"off\")\n    flags2 = eval(repr(flags))\n    assert flags2.is_enabled(\"on\")\n    assert not flags2.is_enabled(\"off\")\n\n\n@given(st.data())\ndef test_repr_can_be_evalled(data):\n    flags = data.draw(STRAT)\n\n    features = data.draw(st.lists(st.text(), unique=True))\n\n    for f in features:\n        flags.is_enabled(f)\n\n    flags2 = eval(repr(flags))\n\n    for f in features:\n        assert flags2.is_enabled(f) == flags.is_enabled(f)\n\n    more_features = data.draw(st.lists(st.text().filter(lambda s: s not in features)))\n\n    for f in more_features:\n        assert flags2.is_enabled(f)\n\n\n@given(FeatureStrategy(at_least_one_of={\"a\", \"b\", \"c\"}))\ndef test_can_avoid_disabling_every_flag(flags):\n    assert any(flags.is_enabled(k) for k in {\"a\", \"b\", \"c\"})\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_filestorage.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\n\nfrom hypothesis import configuration as fs\n\nprevious_home_dir = None\n\n\ndef setup_function(function):\n    global previous_home_dir\n    previous_home_dir = fs.storage_directory()\n    fs.set_hypothesis_home_dir(None)\n\n\ndef teardown_function(function):\n    global previous_home_dir\n    fs.set_hypothesis_home_dir(previous_home_dir)\n    previous_home_dir = None\n\n\ndef test_defaults_to_the_default():\n    assert fs.storage_directory() == fs.__hypothesis_home_directory_default\n\n\ndef test_can_set_homedir(tmp_path):\n    fs.set_hypothesis_home_dir(tmp_path)\n    assert fs.storage_directory(\"kittens\") == tmp_path / \"kittens\"\n\n\ndef test_will_pick_up_location_from_env(monkeypatch, tmp_path):\n    monkeypatch.setattr(os, \"environ\", {\"HYPOTHESIS_STORAGE_DIRECTORY\": str(tmp_path)})\n    assert fs.storage_directory() == tmp_path\n\n\ndef test_storage_directories_are_not_created_automatically(tmp_path):\n    fs.set_hypothesis_home_dir(tmp_path)\n    assert not fs.storage_directory(\"badgers\").exists()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_filter_rewriting.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport datetime as dt\nimport decimal\nimport math\nimport operator\nimport re\nimport sys\nfrom fractions import Fraction\nfrom functools import partial\nfrom sys import float_info\n\nimport pytest\n\nfrom hypothesis import HealthCheck, given, settings, strategies as st\nfrom hypothesis.errors import HypothesisWarning, Unsatisfiable\nfrom hypothesis.internal.conjecture.providers import COLLECTION_DEFAULT_MAX_SIZE\nfrom hypothesis.internal.filtering import max_len, min_len\nfrom hypothesis.internal.floats import next_down, next_up\nfrom hypothesis.internal.reflection import get_pretty_function_description\nfrom hypothesis.strategies._internal.core import data\nfrom hypothesis.strategies._internal.lazy import LazyStrategy, unwrap_strategies\nfrom hypothesis.strategies._internal.numbers import FloatStrategy, IntegersStrategy\nfrom hypothesis.strategies._internal.strategies import FilteredStrategy, MappedStrategy\nfrom hypothesis.strategies._internal.strings import BytesStrategy, TextStrategy\n\nfrom tests.common.debug import check_can_generate_examples\nfrom tests.common.utils import fails_with\n\nA_FEW = 15  # speed up massively-parametrized tests\n\n\n@pytest.mark.parametrize(\n    \"strategy, predicate, start, end\",\n    [\n        # Finitude check\n        (st.integers(1, 5), math.isfinite, 1, 5),\n        # Integers with integer bounds\n        (st.integers(1, 5), partial(operator.lt, 3), 4, 5),  # lambda x: 3 < x\n        (st.integers(1, 5), partial(operator.le, 3), 3, 5),  # lambda x: 3 <= x\n        (st.integers(1, 5), partial(operator.eq, 3), 3, 3),  # lambda x: 3 == x\n        (st.integers(1, 5), partial(operator.ge, 3), 1, 3),  # lambda x: 3 >= x\n        (st.integers(1, 5), partial(operator.gt, 3), 1, 2),  # lambda x: 3 > x\n        # Integers with non-integer bounds\n        (st.integers(1, 5), partial(operator.lt, 3.5), 4, 5),\n        (st.integers(1, 5), partial(operator.le, 3.5), 4, 5),\n        (st.integers(1, 5), partial(operator.ge, 3.5), 1, 3),\n        (st.integers(1, 5), partial(operator.gt, 3.5), 1, 3),\n        (st.integers(1, 5), partial(operator.lt, -math.inf), 1, 5),\n        (st.integers(1, 5), partial(operator.gt, math.inf), 1, 5),\n        # Integers with only one bound\n        (st.integers(min_value=1), partial(operator.lt, 3), 4, None),\n        (st.integers(min_value=1), partial(operator.le, 3), 3, None),\n        (st.integers(max_value=5), partial(operator.ge, 3), None, 3),\n        (st.integers(max_value=5), partial(operator.gt, 3), None, 2),\n        # Unbounded integers\n        (st.integers(), partial(operator.lt, 3), 4, None),\n        (st.integers(), partial(operator.le, 3), 3, None),\n        (st.integers(), partial(operator.eq, 3), 3, 3),\n        (st.integers(), partial(operator.ge, 3), None, 3),\n        (st.integers(), partial(operator.gt, 3), None, 2),\n        # Simple lambdas\n        (st.integers(), lambda x: x < 3, None, 2),\n        (st.integers(), lambda x: x <= 3, None, 3),\n        (st.integers(), lambda x: x == 3, 3, 3),\n        (st.integers(), lambda x: x >= 3, 3, None),\n        (st.integers(), lambda x: x > 3, 4, None),\n        # Simple lambdas, reverse comparison\n        (st.integers(), lambda x: 3 > x, None, 2),\n        (st.integers(), lambda x: 3 >= x, None, 3),\n        (st.integers(), lambda x: 3 == x, 3, 3),\n        (st.integers(), lambda x: 3 <= x, 3, None),\n        (st.integers(), lambda x: 3 < x, 4, None),\n        # More complicated lambdas\n        (st.integers(), lambda x: 0 < x < 5, 1, 4),\n        (st.integers(), lambda x: 0 < x >= 1, 1, None),\n        (st.integers(), lambda x: 1 > x <= 0, None, 0),\n        (st.integers(), lambda x: x > 0 and x > 0, 1, None),\n        (st.integers(), lambda x: x < 1 and x < 1, None, 0),\n        (st.integers(), lambda x: x > 1 and x > 0, 2, None),\n        (st.integers(), lambda x: x < 1 and x < 2, None, 0),\n    ],\n    ids=get_pretty_function_description,\n)\n@settings(max_examples=A_FEW)\n@given(data=st.data())\ndef test_filter_rewriting_ints(data, strategy, predicate, start, end):\n    s = strategy.filter(predicate)\n    assert isinstance(s, LazyStrategy)\n    assert isinstance(s.wrapped_strategy, IntegersStrategy)\n    assert s.wrapped_strategy.start == start\n    assert s.wrapped_strategy.end == end\n    value = data.draw(s)\n    assert predicate(value)\n\n\n@pytest.mark.parametrize(\n    \"strategy, predicate, min_value, max_value\",\n    [\n        # Floats with integer bounds\n        (st.floats(1, 5), partial(operator.lt, 3), next_up(3.0), 5),  # 3 < x\n        (st.floats(1, 5), partial(operator.le, 3), 3, 5),  # lambda x: 3 <= x\n        (st.floats(1, 5), partial(operator.eq, 3), 3, 3),  # lambda x: 3 == x\n        (st.floats(1, 5), partial(operator.ge, 3), 1, 3),  # lambda x: 3 >= x\n        (st.floats(1, 5), partial(operator.gt, 3), 1, next_down(3.0)),  # 3 > x\n        # Floats with non-integer bounds\n        (st.floats(1, 5), partial(operator.lt, 3.5), next_up(3.5), 5),\n        (st.floats(1, 5), partial(operator.le, 3.5), 3.5, 5),\n        (st.floats(1, 5), partial(operator.ge, 3.5), 1, 3.5),\n        (st.floats(1, 5), partial(operator.gt, 3.5), 1, next_down(3.5)),\n        (st.floats(1, 5), partial(operator.lt, -math.inf), 1, 5),\n        (st.floats(1, 5), partial(operator.gt, math.inf), 1, 5),\n        # Floats with only one bound\n        (st.floats(min_value=1), partial(operator.lt, 3), next_up(3.0), math.inf),\n        (st.floats(min_value=1), partial(operator.le, 3), 3, math.inf),\n        (st.floats(max_value=5), partial(operator.ge, 3), -math.inf, 3),\n        (st.floats(max_value=5), partial(operator.gt, 3), -math.inf, next_down(3.0)),\n        # Unbounded floats\n        (st.floats(), partial(operator.lt, 3), next_up(3.0), math.inf),\n        (st.floats(), partial(operator.le, 3), 3, math.inf),\n        (st.floats(), partial(operator.eq, 3), 3, 3),\n        (st.floats(), partial(operator.ge, 3), -math.inf, 3),\n        (st.floats(), partial(operator.gt, 3), -math.inf, next_down(3.0)),\n        # Simple lambdas\n        (st.floats(), lambda x: x < 3, -math.inf, next_down(3.0)),\n        (st.floats(), lambda x: x <= 3, -math.inf, 3),\n        (st.floats(), lambda x: x == 3, 3, 3),\n        (st.floats(), lambda x: x >= 3, 3, math.inf),\n        (st.floats(), lambda x: x > 3, next_up(3.0), math.inf),\n        # Simple lambdas, reverse comparison\n        (st.floats(), lambda x: 3 > x, -math.inf, next_down(3.0)),\n        (st.floats(), lambda x: 3 >= x, -math.inf, 3),\n        (st.floats(), lambda x: 3 == x, 3, 3),\n        (st.floats(), lambda x: 3 <= x, 3, math.inf),\n        (st.floats(), lambda x: 3 < x, next_up(3.0), math.inf),\n        # More complicated lambdas\n        (st.floats(), lambda x: 0 < x < 5, next_up(0.0), next_down(5.0)),\n        (st.floats(), lambda x: 0 < x >= 1, 1, math.inf),\n        (st.floats(), lambda x: 1 > x <= 0, -math.inf, 0),\n        (st.floats(), lambda x: x > 0 and x > 0, next_up(0.0), math.inf),\n        (st.floats(), lambda x: x < 1 and x < 1, -math.inf, next_down(1.0)),\n        (st.floats(), lambda x: x > 1 and x > 0, next_up(1.0), math.inf),\n        (st.floats(), lambda x: x < 1 and x < 2, -math.inf, next_down(1.0)),\n        # Specific named functions\n        (st.floats(), math.isfinite, next_up(-math.inf), next_down(math.inf)),\n    ],\n    ids=get_pretty_function_description,\n)\n@settings(max_examples=A_FEW)\n@given(data=st.data())\ndef test_filter_rewriting_floats(data, strategy, predicate, min_value, max_value):\n    s = strategy.filter(predicate)\n    assert isinstance(s, LazyStrategy)\n    assert isinstance(s.wrapped_strategy, FloatStrategy)\n    assert s.wrapped_strategy.min_value == min_value\n    assert s.wrapped_strategy.max_value == max_value\n    value = data.draw(s)\n    assert predicate(value)\n\n\n@pytest.mark.parametrize(\n    \"pred\",\n    [\n        math.isinf,\n        math.isnan,\n        partial(operator.lt, 6),\n        partial(operator.eq, Fraction(10, 3)),\n        partial(operator.ge, 0),\n        partial(operator.lt, math.inf),\n        partial(operator.gt, -math.inf),\n    ],\n)\n@pytest.mark.parametrize(\"s\", [st.integers(1, 5), st.floats(1, 5)])\ndef test_rewrite_unsatisfiable_filter(s, pred):\n    assert s.filter(pred).is_empty\n\n\n@pytest.mark.parametrize(\n    \"pred\",\n    [\n        partial(operator.eq, \"numbers are never equal to strings\"),\n    ],\n)\n@pytest.mark.parametrize(\"s\", [st.integers(1, 5), st.floats(1, 5)])\n@fails_with(Unsatisfiable)\ndef test_erroring_rewrite_unsatisfiable_filter(s, pred):\n    check_can_generate_examples(s.filter(pred))\n\n\n@pytest.mark.parametrize(\n    \"strategy, predicate\",\n    [\n        (st.floats(), math.isinf),\n        (st.floats(0, math.inf), math.isinf),\n        (st.floats(), math.isnan),\n    ],\n)\n@given(data=st.data())\ndef test_misc_sat_filter_rewrites(data, strategy, predicate):\n    s = strategy.filter(predicate).wrapped_strategy\n    assert not isinstance(s, FloatStrategy)\n    value = data.draw(s)\n    assert predicate(value)\n\n\n@pytest.mark.parametrize(\n    \"strategy, predicate\",\n    [\n        (st.floats(allow_infinity=False), math.isinf),\n        (st.floats(0, math.inf), math.isnan),\n        (st.floats(allow_nan=False), math.isnan),\n    ],\n)\n@given(data=st.data())\ndef test_misc_unsat_filter_rewrites(data, strategy, predicate):\n    assert strategy.filter(predicate).is_empty\n\n\n@given(st.integers(0, 2).filter(partial(operator.ne, 1)))\ndef test_unhandled_operator(x):\n    assert x in (0, 2)\n\n\ndef test_rewriting_does_not_compare_decimal_snan():\n    s = st.integers(1, 5).filter(partial(operator.eq, decimal.Decimal(\"snan\")))\n    s.wrapped_strategy\n    with pytest.raises(decimal.InvalidOperation):\n        check_can_generate_examples(s)\n\n\n@pytest.mark.parametrize(\"strategy\", [st.integers(0, 1), st.floats(0, 1)], ids=repr)\ndef test_applying_noop_filter_returns_self(strategy):\n    s = strategy.wrapped_strategy\n    s2 = s.filter(partial(operator.le, -1)).filter(partial(operator.ge, 2))\n    assert s is s2\n\n\ndef mod2(x):\n    return x % 2\n\n\nY = 2**20\n\n\n@pytest.mark.parametrize(\"s\", [st.integers(1, 5), st.floats(1, 5)])\n@given(\n    data=st.data(),\n    predicates=st.permutations(\n        [\n            partial(operator.lt, 1),\n            partial(operator.le, 2),\n            partial(operator.ge, 4),\n            partial(operator.gt, 5),\n            mod2,\n            lambda x: x > 2 or x % 7,\n            lambda x: 0 < x <= Y,\n        ]\n    ),\n)\n@settings(suppress_health_check=[HealthCheck.too_slow])\ndef test_rewrite_filter_chains_with_some_unhandled(data, predicates, s):\n    # Set up our strategy\n    for p in predicates:\n        s = s.filter(p)\n\n    # Whatever value we draw is in fact valid for these strategies\n    value = data.draw(s)\n    for p in predicates:\n        assert p(value), f\"{p=}, value={value}\"\n\n    # No matter the order of the filters, we get the same resulting structure\n    unwrapped = s.wrapped_strategy\n    assert isinstance(unwrapped, FilteredStrategy)\n    assert isinstance(unwrapped.filtered_strategy, (IntegersStrategy, FloatStrategy))\n    for pred in unwrapped.flat_conditions:\n        assert pred is mod2 or pred.__name__ == \"<lambda>\"\n\n\nclass NotAFunction:\n    def __call__(self, bar):\n        return True\n\n\nlambda_without_source = eval(\"lambda x: x > 2\", {}, {})\nassert get_pretty_function_description(lambda_without_source) == \"lambda x: <unknown>\"\n\n\n@pytest.mark.parametrize(\n    \"start, end, predicate\",\n    [\n        (1, 4, lambda x: 0 < x < 5 and x % 7),\n        (0, 9, lambda x: 0 <= x < 10 and x % 3),\n        (1, None, lambda x: 0 < x <= Y),\n        (None, None, lambda x: x == x),\n        (None, None, lambda x: 1 == 1),\n        (None, None, lambda x: 1 <= 2),\n        (None, None, lambda x: x != 0),\n        (None, None, NotAFunction()),\n        (None, None, lambda_without_source),\n        (None, None, lambda x, y=2: x >= 0),\n    ],\n)\n@given(data=st.data())\ndef test_rewriting_partially_understood_filters(data, start, end, predicate):\n    s = st.integers().filter(predicate).wrapped_strategy\n\n    assert isinstance(s, FilteredStrategy)\n    assert isinstance(s.filtered_strategy, IntegersStrategy)\n    assert s.filtered_strategy.start == start\n    assert s.filtered_strategy.end == end\n    assert s.flat_conditions == (predicate,)\n\n    value = data.draw(s)\n    assert predicate(value)\n\n\n@pytest.mark.parametrize(\n    \"strategy\",\n    [\n        st.text(),\n        st.text(min_size=2),\n        st.lists(st.none()),\n        st.lists(st.none(), min_size=2),\n    ],\n)\n@pytest.mark.parametrize(\n    \"predicate\",\n    [bool, len, tuple, list, lambda x: x],\n    ids=get_pretty_function_description,\n)\ndef test_sequence_filter_rewriting(strategy, predicate):\n    s = unwrap_strategies(strategy)\n    fs = s.filter(predicate)\n    assert not isinstance(fs, FilteredStrategy)\n    if s.min_size > 0:\n        assert fs is s\n    else:\n        assert fs.min_size == 1\n\n\n@pytest.mark.parametrize(\"method\", [str.lower, str.title, str.upper])\ndef test_warns_on_suspicious_string_methods(method):\n    s = unwrap_strategies(st.text())\n    with pytest.warns(\n        HypothesisWarning, match=\"this allows all nonempty strings!  Did you mean\"\n    ):\n        fs = s.filter(method)\n    assert fs.min_size == 1\n\n\n@pytest.mark.parametrize(\"method\", [str.isalnum])\ndef test_bumps_min_size_and_filters_for_content_str_methods(method):\n    s = unwrap_strategies(st.text())\n    fs = s.filter(method)\n    assert fs.filtered_strategy.min_size == 1\n    assert fs.flat_conditions == (method,)\n\n\n# Should we deterministically check whether ascii or not or st.characters fine?\n@pytest.mark.parametrize(\"al\", [None, \"cdef123\", \"cd12¥¦§©\"])\n@given(data())\ndef test_isidentifier_filter_properly_rewritten(al, data):\n    if al is None:\n        example = data.draw(st.text().filter(str.isidentifier))\n    else:\n        example = data.draw(st.text(alphabet=al).filter(str.isidentifier))\n        assert set(example).issubset(al)\n    assert example.isidentifier()\n\n\ndef test_isidentifer_filter_unsatisfiable():\n    alphabet = \"¥¦§©\"\n    assert not any(f\"_{c}\".isidentifier() for c in alphabet)\n    fs = st.text(alphabet=alphabet).filter(str.isidentifier)\n    with pytest.raises(Unsatisfiable):\n        check_can_generate_examples(fs)\n\n\n@pytest.mark.parametrize(\n    \"op, attr, value, expected\",\n    [\n        (operator.lt, \"min_value\", -float_info.min / 2, 0),\n        (operator.lt, \"min_value\", float_info.min / 2, float_info.min),\n        (operator.gt, \"max_value\", float_info.min / 2, 0),\n        (operator.gt, \"max_value\", -float_info.min / 2, -float_info.min),\n    ],\n)\ndef test_filter_floats_can_skip_subnormals(op, attr, value, expected):\n    base = st.floats(allow_subnormal=False).filter(partial(op, value))\n    assert getattr(base.wrapped_strategy, attr) == expected\n\n\n@pytest.mark.parametrize(\n    \"strategy, predicate, start, end\",\n    [\n        # text with integer bounds\n        (st.text(min_size=1, max_size=5), partial(min_len, 3), 3, 5),\n        (st.text(min_size=1, max_size=5), partial(max_len, 3), 1, 3),\n        # text with only one bound\n        (st.text(min_size=1), partial(min_len, 3), 3, math.inf),\n        (st.text(min_size=1), partial(max_len, 3), 1, 3),\n        (st.text(max_size=5), partial(min_len, 3), 3, 5),\n        (st.text(max_size=5), partial(max_len, 3), 0, 3),\n        # Unbounded text\n        (st.text(), partial(min_len, 3), 3, math.inf),\n        (st.text(), partial(max_len, 3), 0, 3),\n    ],\n    ids=get_pretty_function_description,\n)\n@settings(max_examples=A_FEW)\n@given(data=st.data())\ndef test_filter_rewriting_text_partial_len(data, strategy, predicate, start, end):\n    s = strategy.filter(predicate)\n\n    assert isinstance(s, LazyStrategy)\n    inner = unwrap_strategies(s)\n    assert isinstance(inner, TextStrategy)\n    assert inner.min_size == start\n    assert inner.max_size == end\n    value = data.draw(s)\n    assert predicate(value)\n\n\n@given(data=st.data())\ndef test_can_rewrite_multiple_length_filters_if_not_lambdas(data):\n    # This is a key capability for efficient rewriting using the `annotated-types`\n    # package, although unfortunately we can't do it for lambdas.\n    s = (\n        st.text(min_size=1, max_size=5)\n        .filter(partial(min_len, 2))\n        .filter(partial(max_len, 4))\n    )\n    assert isinstance(s, LazyStrategy)\n    inner = unwrap_strategies(s)\n    assert isinstance(inner, TextStrategy)\n    assert inner.min_size == 2\n    assert inner.max_size == 4\n    value = data.draw(s)\n    assert 2 <= len(value) <= 4\n\n\n@pytest.mark.parametrize(\n    \"predicate, start, end\",\n    [\n        # Simple lambdas\n        (lambda x: len(x) < 3, 0, 2),\n        (lambda x: len(x) <= 3, 0, 3),\n        (lambda x: len(x) == 3, 3, 3),\n        (lambda x: len(x) >= 3, 3, math.inf),\n        (lambda x: len(x) > 3, 4, math.inf),\n        # Simple lambdas, reverse comparison\n        (lambda x: 3 > len(x), 0, 2),\n        (lambda x: 3 >= len(x), 0, 3),\n        (lambda x: 3 == len(x), 3, 3),\n        (lambda x: 3 <= len(x), 3, math.inf),\n        (lambda x: 3 < len(x), 4, math.inf),\n        # More complicated lambdas\n        (lambda x: 0 < len(x) < 5, 1, 4),\n        (lambda x: 0 < len(x) >= 1, 1, math.inf),\n        (lambda x: 1 > len(x) <= 0, 0, 0),\n        (lambda x: len(x) > 0 and len(x) > 0, 1, math.inf),\n        (lambda x: len(x) < 1 and len(x) < 1, 0, 0),\n        (lambda x: len(x) > 1 and len(x) > 0, 2, math.inf),\n        (lambda x: len(x) < 1 and len(x) < 2, 0, 0),\n    ],\n    ids=get_pretty_function_description,\n)\n@pytest.mark.parametrize(\n    \"strategy\",\n    [\n        st.text(),\n        st.lists(st.integers()),\n        st.lists(st.integers(), unique=True),\n        st.lists(st.sampled_from([1, 2, 3])),\n        st.binary(),\n        st.sets(st.integers()),\n        st.frozensets(st.integers()),\n        st.dictionaries(st.integers(), st.none()),\n        st.lists(st.integers(), unique_by=lambda x: x % 17).map(tuple),\n    ],\n    ids=get_pretty_function_description,\n)\n@settings(max_examples=A_FEW)\n@given(data=st.data())\ndef test_filter_rewriting_text_lambda_len(data, strategy, predicate, start, end):\n    s = strategy.filter(predicate)\n    unwrapped_nofilter = unwrap_strategies(strategy)\n    unwrapped = unwrap_strategies(s)\n\n    if was_mapped := isinstance(unwrapped, MappedStrategy):\n        unwrapped = unwrapped.mapped_strategy\n\n    assert isinstance(unwrapped, FilteredStrategy), f\"{unwrapped=} {type(unwrapped)=}\"\n    assert isinstance(\n        unwrapped.filtered_strategy,\n        type(unwrapped_nofilter.mapped_strategy if was_mapped else unwrapped_nofilter),\n    )\n    for pred in unwrapped.flat_conditions:\n        assert pred.__name__ == \"<lambda>\"\n\n    if isinstance(unwrapped.filtered_strategy, MappedStrategy):\n        unwrapped = unwrapped.filtered_strategy.mapped_strategy\n\n    # binary() has a finite-but-effectively-infinite cap instead.\n    if isinstance(unwrapped_nofilter, BytesStrategy) and end == math.inf:\n        end = COLLECTION_DEFAULT_MAX_SIZE\n\n    assert unwrapped.filtered_strategy.min_size == start\n    assert unwrapped.filtered_strategy.max_size == end\n    value = data.draw(s)\n    assert predicate(value)\n\n\ntwo = 2\n\n\n@pytest.mark.parametrize(\n    \"predicate, start, end\",\n    [\n        # Simple lambdas\n        (lambda x: len(x) < 3, 0, 2),\n        (lambda x: len(x) <= 3, 0, 3),\n        (lambda x: len(x) == 3, 3, 3),\n        (lambda x: len(x) >= 3, 3, 3),  # input max element_count=3\n        # Simple lambdas, reverse comparison\n        (lambda x: 3 > len(x), 0, 2),\n        (lambda x: 3 >= len(x), 0, 3),\n        (lambda x: 3 == len(x), 3, 3),\n        (lambda x: 3 <= len(x), 3, 3),  # input max element_count=3\n        # More complicated lambdas\n        (lambda x: 0 < len(x) < 5, 1, 3),  # input max element_count=3\n        (lambda x: 0 < len(x) >= 1, 1, 3),  # input max element_count=3\n        (lambda x: 1 > len(x) <= 0, 0, 0),\n        (lambda x: len(x) > 0 and len(x) > 0, 1, 3),  # input max element_count=3\n        (lambda x: len(x) < 1 and len(x) < 1, 0, 0),\n        (lambda x: len(x) > 1 and len(x) > 0, 2, 3),  # input max element_count=3\n        (lambda x: len(x) < 1 and len(x) < 2, 0, 0),\n        # Comparisons involving one literal and one variable\n        (lambda x: 1 <= len(x) <= two, 1, 3),\n        (lambda x: two <= len(x) <= 4, 0, 3),\n    ],\n    ids=get_pretty_function_description,\n)\n@pytest.mark.parametrize(\n    \"strategy\",\n    [\n        st.lists(st.sampled_from([1, 2, 3]), unique=True),\n    ],\n    ids=get_pretty_function_description,\n)\n@settings(max_examples=A_FEW)\n@given(data=st.data())\ndef test_filter_rewriting_lambda_len_unique_elements(\n    data, strategy, predicate, start, end\n):\n    s = strategy.filter(predicate)\n    unwrapped = unwrap_strategies(s)\n    assert isinstance(unwrapped, FilteredStrategy)\n    assert isinstance(unwrapped.filtered_strategy, type(unwrap_strategies(strategy)))\n    for pred in unwrapped.flat_conditions:\n        assert pred.__name__ == \"<lambda>\"\n\n    assert unwrapped.filtered_strategy.min_size == start\n    assert unwrapped.filtered_strategy.max_size == end\n    value = data.draw(s)\n    assert predicate(value)\n\n\n@pytest.mark.parametrize(\n    \"predicate\",\n    [\n        (lambda x: len(x) < 3),\n        (lambda x: len(x) > 5),\n    ],\n    ids=get_pretty_function_description,\n)\ndef test_does_not_rewrite_unsatisfiable_len_filter(predicate):\n    strategy = st.lists(st.none(), min_size=4, max_size=4).filter(predicate)\n    with pytest.raises(Unsatisfiable):\n        check_can_generate_examples(strategy)\n    # Rewriting to nothing() would correctly express the constraint.  However\n    # we don't want _only rewritable strategies_ to work in e.g. one_of, so:\n    assert not strategy.is_empty\n\n\n@pytest.mark.parametrize(\n    \"method\", [\"match\", \"search\", \"findall\", \"fullmatch\", \"finditer\", \"split\"]\n)\n@pytest.mark.parametrize(\n    \"strategy, pattern\",\n    [\n        (st.text(), \"ab+c\"),\n        (st.text(), \"a|b\"),\n        (st.text(alphabet=\"abcdef\"), \"ab+c\"),\n        (st.text(min_size=5, max_size=10), \"ab+c\"),\n        (st.binary(), b\"ab+c\"),\n        (st.binary(), b\"a|b\"),\n        (st.binary(min_size=5, max_size=10), b\"ab+c\"),\n    ],\n    ids=repr,\n)\n@settings(max_examples=A_FEW)\n@given(data=st.data())\ndef test_regex_filter_rewriting(data, strategy, pattern, method):\n    # This would raise a HealthCheck without rewriting, so checking that\n    # we can draw a valid value is sufficient.\n    predicate = getattr(re.compile(pattern), method)\n    s = strategy.filter(predicate)\n    if method in (\"finditer\", \"split\"):\n        msg = r\"You applied re.compile\\(.+?\\).\\w+ as a filter, but this allows\"\n        with pytest.warns(HypothesisWarning, match=msg):\n            value = data.draw(s)\n    else:\n        value = data.draw(s)\n    assert predicate(value)\n\n\n@fails_with(TypeError)\n@given(st.text().filter(re.compile(\"abc\").sub))\ndef test_error_on_method_which_requires_multiple_args(_):\n    pass\n\n\ndef test_dates_filter_rewriting():\n    today = dt.date.today()\n\n    assert st.dates().filter(partial(operator.lt, dt.date.max)).is_empty\n    assert st.dates().filter(partial(operator.gt, dt.date.min)).is_empty\n    assert st.dates(min_value=today).filter(partial(operator.gt, today)).is_empty\n    assert st.dates(max_value=today).filter(partial(operator.lt, today)).is_empty\n\n    bare = unwrap_strategies(st.dates())\n    assert bare.filter(partial(operator.ge, dt.date.max)) is bare\n    assert bare.filter(partial(operator.le, dt.date.min)) is bare\n\n    new = bare.filter(partial(operator.le, today))\n    assert not new.is_empty\n    assert new is not bare\n\n\n@pytest.mark.skipif(\n    sys.version_info[:2] < (3, 14), reason=\"functools.Placeholder is new in 3.14\"\n)\ndef test_partial_placeholder():\n    from functools import Placeholder\n\n    assert st.integers(0, 5).filter(partial(operator.gt, Placeholder, 5)).is_empty\n\n    s = unwrap_strategies(\n        st.integers(-5, 5).filter(partial(operator.lt, Placeholder, 3))\n    )\n    assert (s.start, s.end) == (-5, 2)\n\n    s = unwrap_strategies(\n        st.integers(-5, 5).filter(partial(operator.le, Placeholder, 3))\n    )\n    assert (s.start, s.end) == (-5, 3)\n\n    s = unwrap_strategies(\n        st.integers(-5, 5).filter(partial(operator.gt, Placeholder, 3))\n    )\n    assert (s.start, s.end) == (4, 5)\n\n    s = unwrap_strategies(\n        st.integers(-5, 5).filter(partial(operator.ge, Placeholder, 3))\n    )\n    assert (s.start, s.end) == (3, 5)\n\n    s = unwrap_strategies(\n        st.integers(-5, 5).filter(partial(operator.eq, Placeholder, 3))\n    )\n    assert (s.start, s.end) == (3, 3)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_filtered_strategy.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport hypothesis.strategies as st\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.strategies._internal.strategies import FilteredStrategy\n\n\ndef test_filter_iterations_are_marked_as_discarded():\n    variable_equal_to_zero = 0  # non-local references disables filter-rewriting\n    x = st.integers().filter(lambda x: x == variable_equal_to_zero)\n\n    data = ConjectureData.for_choices([1, 0])\n    assert data.draw(x) == 0\n    assert data.has_discards\n\n\ndef test_filtered_branches_are_all_filtered():\n    s = FilteredStrategy(st.integers() | st.text(), (bool,))\n    assert all(isinstance(x, FilteredStrategy) for x in s.branches)\n\n\ndef test_filter_conditions_may_be_empty():\n    s = FilteredStrategy(st.integers(), conditions=())\n    s.condition(0)\n\n\ndef test_nested_filteredstrategy_flattens_conditions():\n    s = FilteredStrategy(\n        FilteredStrategy(st.text(), conditions=(bool,)),\n        conditions=(len,),\n    )\n    assert s.filtered_strategy is st.text()\n    assert s.flat_conditions == (bool, len)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_find.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom random import Random\n\nfrom hypothesis import Phase, find, settings, strategies as st\n\nfrom tests.common.utils import Why, xfail_on_crosshair\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context)\ndef test_find_uses_provided_random():\n    prev = None\n\n    for _ in range(3):\n        seen = None\n\n        def test(v):\n            if len(v) > 5:\n                nonlocal seen\n                if seen is not None:\n                    return v == seen\n                else:\n                    seen = v\n                    return True\n\n        result = find(\n            st.text(),\n            test,\n            random=Random(13),\n            settings=settings(phases=[Phase.generate], max_examples=1000),\n        )\n        if prev is None:\n            prev = result\n        else:\n            assert prev == result\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_flakiness.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport sys\n\nimport pytest\n\nfrom hypothesis import HealthCheck, Verbosity, assume, example, given, reject, settings\nfrom hypothesis.core import StateForActualGivenExecution\nfrom hypothesis.errors import Flaky, FlakyFailure, Unsatisfiable, UnsatisfiedAssumption\nfrom hypothesis.internal.compat import ExceptionGroup\nfrom hypothesis.internal.conjecture.engine import MIN_TEST_CALLS\nfrom hypothesis.internal.scrutineer import Tracer\nfrom hypothesis.strategies import booleans, composite, integers, lists, random_module\n\nfrom tests.common.utils import Why, no_shrink, skipif_threading, xfail_on_crosshair\n\n\nclass Nope(Exception):\n    pass\n\n\ndef test_fails_only_once_is_flaky():\n    first_call = True\n\n    @given(integers())\n    def rude(x):\n        nonlocal first_call\n        if first_call:\n            first_call = False\n            raise Nope\n\n    with pytest.raises(FlakyFailure, match=\"Falsified on the first call but\") as e:\n        rude()\n    exceptions = e.value.exceptions\n    assert len(exceptions) == 1\n    assert isinstance(exceptions[0], Nope)\n\n\ndef test_fails_differently_is_flaky():\n    call_count = 0\n\n    class DifferentNope(Exception):\n        pass\n\n    @given(integers())\n    @settings(database=None)\n    def rude(x):\n        nonlocal call_count\n        if x == 0:\n            call_count += 1\n            if call_count > 1:\n                raise Nope\n            else:\n                raise DifferentNope\n\n    with pytest.raises(FlakyFailure, match=\"Inconsistent results from replaying\") as e:\n        rude()\n    exceptions = e.value.exceptions\n    assert len(exceptions) == 2\n    assert set(map(type, exceptions)) == {Nope, DifferentNope}\n\n\n@skipif_threading  # executing into global scope\n@pytest.mark.skipif(sys.version_info < (3, 11), reason=\"except* syntax\")\ndef test_exceptiongroup_wrapped_naked_exception_is_flaky():\n\n    # Defer parsing until runtime, as \"except*\" is syntax error pre 3.11\n    rude_def = \"\"\"\nfirst_call = True\ndef rude_fn(x):\n    global first_call\n    if first_call:\n        first_call = False\n        try:\n            raise Nope\n        except* Nope:\n            raise\n    \"\"\"\n    exec(rude_def, globals())\n    rude = given(integers())(rude_fn)  # noqa: F821 # defined by exec()\n\n    with pytest.raises(FlakyFailure, match=\"Falsified on the first call but\") as e:\n        rude()\n    exceptions = e.value.exceptions\n    assert list(map(type, exceptions)) == [ExceptionGroup]\n    assert list(map(type, exceptions[0].exceptions)) == [Nope]\n\n\ndef test_gives_flaky_error_if_assumption_is_flaky():\n    seen = set()\n\n    @given(integers())\n    @settings(verbosity=Verbosity.quiet, database=None)\n    def oops(s):\n        assume(s not in seen)\n        seen.add(s)\n        raise AssertionError\n\n    with pytest.raises(FlakyFailure, match=\"Inconsistent results from replaying\") as e:\n        oops()\n    exceptions = e.value.exceptions\n    assert len(exceptions) == 2\n    assert isinstance(exceptions[0], AssertionError)\n    assert isinstance(exceptions[1], UnsatisfiedAssumption)\n\n\ndef test_flaky_with_context_when_fails_only_under_tracing(monkeypatch):\n    # make anything fail under tracing\n    monkeypatch.setattr(Tracer, \"can_trace\", staticmethod(lambda: True))\n    monkeypatch.setattr(Tracer, \"__enter__\", lambda *_: 1 / 0)\n    # ensure tracing is always entered inside _execute_once_for_engine\n    monkeypatch.setattr(StateForActualGivenExecution, \"_should_trace\", lambda _: True)\n\n    @given(integers())\n    def test(x):\n        pass\n\n    with pytest.raises(\n        FlakyFailure, match=\"failed on the first run but now succeeds\"\n    ) as e:\n        test()\n    exceptions = e.value.exceptions\n    assert len(exceptions) == 1\n    assert isinstance(exceptions[0], ZeroDivisionError)\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context)\ndef test_does_not_attempt_to_shrink_flaky_errors():\n    values = []\n\n    @settings(database=None)\n    @given(integers())\n    def test(x):\n        values.append(x)\n        assert len(values) != 1\n\n    with pytest.raises(FlakyFailure):\n        test()\n    # We try a total of ten calls in the generation phase, each usually a\n    # unique value, looking briefly (and unsuccessfully) for another bug.\n    assert 1 < len(set(values)) <= MIN_TEST_CALLS\n    # We don't try any new values while shrinking, just execute the test\n    # twice more (to check for flakiness and to raise the bug to the user).\n    assert set(values) == set(values[:-2])\n\n\nclass SatisfyMe(Exception):\n    pass\n\n\n@composite\ndef single_bool_lists(draw):\n    n = draw(integers(0, 20))\n    result = [False] * (n + 1)\n    result[n] = True\n    return result\n\n\n@xfail_on_crosshair(Why.nested_given)\n@example([True, False, False, False], [3], None)\n@example([False, True, False, False], [3], None)\n@example([False, False, True, False], [3], None)\n@example([False, False, False, True], [3], None)\n@settings(\n    deadline=None, suppress_health_check=[HealthCheck.nested_given], max_examples=10\n)\n@given(lists(booleans()) | single_bool_lists(), lists(integers(1, 3)), random_module())\ndef test_failure_sequence_inducing(building, testing, rnd):\n    buildit = iter(building)\n    testit = iter(testing)\n\n    def build(x):\n        try:\n            assume(not next(buildit))\n        except StopIteration:\n            pass\n        return x\n\n    @given(integers().map(build))\n    @settings(\n        verbosity=Verbosity.quiet,\n        database=None,\n        suppress_health_check=list(HealthCheck),\n        phases=no_shrink,\n        max_examples=10,\n    )\n    def test(x):\n        try:\n            i = next(testit)\n        except StopIteration:\n            return\n        if i == 1:\n            return\n        elif i == 2:\n            reject()\n        else:\n            raise Nope\n\n    try:\n        test()\n    except (Nope, Flaky, Unsatisfiable):\n        pass\n    except UnsatisfiedAssumption:\n        raise SatisfyMe from None\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_float_nastiness.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nimport sys\nimport warnings\n\nimport pytest\n\nfrom hypothesis import assume, given, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.floats import (\n    float_of,\n    float_to_int,\n    int_to_float,\n    is_negative,\n    next_down,\n    next_up,\n)\n\nfrom tests.common.debug import find_any, minimal\n\ntry:\n    import numpy\nexcept ImportError:\n    numpy = None\n\n\n@pytest.mark.parametrize(\n    (\"lower\", \"upper\"),\n    [\n        # Exact values don't matter, but they're large enough so that x + y = inf.\n        (9.9792015476736e291, 1.7976931348623157e308),\n        (-sys.float_info.max, sys.float_info.max),\n    ],\n)\n@given(data=st.data())\ndef test_floats_are_in_range(data, lower, upper):\n    t = data.draw(st.floats(lower, upper))\n    assert lower <= t <= upper\n\n\n@pytest.mark.parametrize(\"sign\", [-1, 1])\ndef test_can_generate_both_zeros(sign):\n    assert minimal(st.floats(), lambda x: math.copysign(1, x) == sign) == sign * 0.0\n\n\n@pytest.mark.parametrize(\n    (\"l\", \"r\"),\n    [(-1.0, 1.0), (-0.0, 1.0), (-1.0, 0.0), (-sys.float_info.min, sys.float_info.min)],\n)\n@pytest.mark.parametrize(\"sign\", [-1, 1])\ndef test_can_generate_both_zeros_when_in_interval(l, r, sign):\n    assert minimal(st.floats(l, r), lambda x: math.copysign(1, x) == sign) == sign * 0.0\n\n\n@given(st.floats(0.0, 1.0))\ndef test_does_not_generate_negative_if_right_boundary_is_positive(x):\n    assert math.copysign(1, x) == 1\n\n\n@given(st.floats(-1.0, -0.0))\ndef test_does_not_generate_positive_if_right_boundary_is_negative(x):\n    assert math.copysign(1, x) == -1\n\n\ndef test_half_bounded_generates_zero():\n    find_any(st.floats(min_value=-1.0), lambda x: x == 0.0)\n    find_any(st.floats(max_value=1.0), lambda x: x == 0.0)\n\n\n@given(st.floats(max_value=-0.0))\ndef test_half_bounded_respects_sign_of_upper_bound(x):\n    assert math.copysign(1, x) == -1\n\n\n@given(st.floats(min_value=0.0))\ndef test_half_bounded_respects_sign_of_lower_bound(x):\n    assert math.copysign(1, x) == 1\n\n\n@given(st.floats(allow_nan=False))\ndef test_filter_nan(x):\n    assert not math.isnan(x)\n\n\n@given(st.floats(allow_infinity=False))\ndef test_filter_infinity(x):\n    assert not math.isinf(x)\n\n\ndef test_can_guard_against_draws_of_nan():\n    \"\"\"In this test we create a NaN value that naturally \"tries\" to shrink into\n    the first strategy, where it is not permitted. This tests a case that is\n    very unlikely to happen in random generation: When the unconstrained first\n    branch of generating a float just happens to produce a NaN value.\n\n    Here what happens is that we get a NaN from the *second* strategy,\n    but this then shrinks into its unconstrained branch. The natural\n    thing to happen is then to try to zero the branch parameter of the\n    one_of, but that will put an illegal value there, so it's not\n    allowed to happen.\n    \"\"\"\n    tagged_floats = st.one_of(\n        st.tuples(st.just(0), st.floats(allow_nan=False)),\n        st.tuples(st.just(1), st.floats(allow_nan=True)),\n    )\n\n    tag, _f = minimal(tagged_floats, lambda x: math.isnan(x[1]))\n    assert tag == 1\n\n\ndef test_very_narrow_interval():\n    upper_bound = -1.0\n    lower_bound = int_to_float(float_to_int(upper_bound) + 10)\n    assert lower_bound < upper_bound\n\n    @given(st.floats(lower_bound, upper_bound))\n    def test(f):\n        assert lower_bound <= f <= upper_bound\n\n    test()\n\n\n@given(st.floats())\ndef test_up_means_greater(x):\n    hi = next_up(x)\n    if not x < hi:\n        assert (\n            (math.isnan(x) and math.isnan(hi))\n            or (x > 0 and math.isinf(x))\n            or (x == hi == 0 and is_negative(x) and not is_negative(hi))\n        )\n\n\n@given(st.floats())\ndef test_down_means_lesser(x):\n    lo = next_down(x)\n    if not x > lo:\n        assert (\n            (math.isnan(x) and math.isnan(lo))\n            or (x < 0 and math.isinf(x))\n            or (x == lo == 0 and is_negative(lo) and not is_negative(x))\n        )\n\n\n@given(st.floats(allow_nan=False, allow_infinity=False))\ndef test_updown_roundtrip(val):\n    assert val == next_up(next_down(val))\n    assert val == next_down(next_up(val))\n\n\n@given(st.floats(width=32, allow_infinity=False))\ndef test_float32_can_exclude_infinity(x):\n    assert not math.isinf(x)\n\n\n@given(st.floats(width=16, allow_infinity=False))\ndef test_float16_can_exclude_infinity(x):\n    assert not math.isinf(x)\n\n\n@pytest.mark.parametrize(\n    \"kwargs\",\n    [\n        {\"min_value\": 10**5, \"width\": 16},\n        {\"max_value\": 10**5, \"width\": 16},\n        {\"min_value\": 10**40, \"width\": 32},\n        {\"max_value\": 10**40, \"width\": 32},\n        {\"min_value\": 10**400, \"width\": 64},\n        {\"max_value\": 10**400, \"width\": 64},\n        {\"min_value\": 10**400},\n        {\"max_value\": 10**400},\n    ],\n)\ndef test_out_of_range(kwargs):\n    with pytest.raises(OverflowError):\n        st.floats(**kwargs).validate()\n\n\ndef test_disallowed_width():\n    with pytest.raises(InvalidArgument):\n        st.floats(width=128).validate()\n\n\ndef test_no_single_floats_in_range():\n    low = 2.0**25 + 1\n    high = low + 2\n    st.floats(low, high).validate()  # Note: OK for 64bit floats\n    with warnings.catch_warnings():\n        # Unrepresentable bounds are deprecated, but we're not testing that here\n        warnings.simplefilter(\"ignore\")\n        with pytest.raises(InvalidArgument):\n            st.floats(low, high, width=32).validate()\n\n\n# If the floats() strategy adds random floats to a value as large as 10^304\n# without handling overflow, we are very likely to generate infinity.\n@given(st.floats(min_value=1e304, allow_infinity=False))\ndef test_finite_min_bound_does_not_overflow(x):\n    assert not math.isinf(x)\n\n\n@given(st.floats(max_value=-1e304, allow_infinity=False))\ndef test_finite_max_bound_does_not_overflow(x):\n    assert not math.isinf(x)\n\n\n@given(st.floats(0, 1, exclude_min=True, exclude_max=True))\ndef test_can_exclude_endpoints(x):\n    assert 0 < x < 1\n\n\n@given(st.floats(-math.inf, -1e307, exclude_min=True))\ndef test_can_exclude_neg_infinite_endpoint(x):\n    assert not math.isinf(x)\n\n\n@given(st.floats(1e307, math.inf, exclude_max=True))\ndef test_can_exclude_pos_infinite_endpoint(x):\n    assert not math.isinf(x)\n\n\ndef test_exclude_infinite_endpoint_is_invalid():\n    with pytest.raises(InvalidArgument):\n        st.floats(min_value=math.inf, exclude_min=True).validate()\n    with pytest.raises(InvalidArgument):\n        st.floats(max_value=-math.inf, exclude_max=True).validate()\n\n\n@pytest.mark.parametrize(\"lo,hi\", [(True, False), (False, True), (True, True)])\n@given(bound=st.floats(allow_nan=False, allow_infinity=False).filter(bool))\ndef test_exclude_entire_interval(lo, hi, bound):\n    with pytest.raises(InvalidArgument, match=r\"exclude_min=.+ and exclude_max=\"):\n        st.floats(bound, bound, exclude_min=lo, exclude_max=hi).validate()\n\n\ndef test_zero_intervals_are_OK():\n    st.floats(0.0, 0.0).validate()\n    st.floats(-0.0, 0.0).validate()\n    st.floats(-0.0, -0.0).validate()\n\n\n@pytest.mark.parametrize(\"lo\", [0.0, -0.0])\n@pytest.mark.parametrize(\"hi\", [0.0, -0.0])\n@pytest.mark.parametrize(\"exmin,exmax\", [(True, False), (False, True), (True, True)])\ndef test_cannot_exclude_endpoint_with_zero_interval(lo, hi, exmin, exmax):\n    with pytest.raises(InvalidArgument):\n        st.floats(lo, hi, exclude_min=exmin, exclude_max=exmax).validate()\n\n\nWIDTHS = (64, 32, 16)\n\n\n@pytest.mark.parametrize(\"nonfloat\", [st.nothing(), st.none()])\n@given(data=st.data(), width=st.sampled_from(WIDTHS))\ndef test_fuzzing_floats_bounds(data, width, nonfloat):\n    lo = data.draw(nonfloat | st.floats(allow_nan=False, width=width), label=\"lo\")\n    hi = data.draw(nonfloat | st.floats(allow_nan=False, width=width), label=\"hi\")\n    if lo is not None and hi is not None and lo > hi:\n        lo, hi = hi, lo\n    assume(lo != 0 or hi != 0)\n    value = data.draw(\n        st.floats(min_value=lo, max_value=hi, width=width, allow_nan=False),\n        label=\"value\",\n    )\n    assert value == float_of(value, width=width)\n    assert lo is None or lo <= value\n    assert hi is None or value <= hi\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_float_utils.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nfrom sys import float_info\n\nimport pytest\n\nfrom hypothesis import example, given, strategies as st\nfrom hypothesis.internal.conjecture.choice import choice_equal, choice_permitted\nfrom hypothesis.internal.conjecture.provider_conformance import float_constraints\nfrom hypothesis.internal.floats import (\n    count_between_floats,\n    make_float_clamper,\n    next_down,\n    next_up,\n    sign_aware_lte,\n)\n\nfrom tests.conjecture.common import float_constr\n\n\ndef test_can_handle_straddling_zero():\n    assert count_between_floats(-0.0, 0.0) == 2\n\n\n@pytest.mark.parametrize(\n    \"func,val\",\n    [\n        (next_up, math.nan),\n        (next_up, math.inf),\n        (next_up, -0.0),\n        (next_down, math.nan),\n        (next_down, -math.inf),\n        (next_down, 0.0),\n    ],\n)\ndef test_next_float_equal(func, val):\n    if math.isnan(val):\n        assert math.isnan(func(val))\n    else:\n        assert func(val) == val\n\n\n# exponent comparisons:\n@example(float_constr(1, float_info.max), 0.0)\n@example(float_constr(1, float_info.max), 1.0)\n@example(float_constr(1, float_info.max), 10.0)\n@example(float_constr(1, float_info.max), float_info.max)\n@example(float_constr(1, float_info.max), math.inf)\n# mantissa comparisons:\n@example(float_constr(100.0001, 100.0003), 100.0001)\n@example(float_constr(100.0001, 100.0003), 100.0002)\n@example(float_constr(100.0001, 100.0003), 100.0003)\n@example(float_constr(100.0001, 100.0003, allow_nan=False), math.nan)\n@example(float_constr(0, 10, allow_nan=False), math.nan)\n@example(float_constr(0, 10, allow_nan=True), math.nan)\n# the branch coverage of resampling in the \"out of range of smallest magnitude\" case\n# relies on randomness from the mantissa. try a few different values.\n@example(float_constr(-4, -1, smallest_nonzero_magnitude=4), 4.0)\n@example(float_constr(-4, -1, smallest_nonzero_magnitude=4), 5.0)\n@example(float_constr(-4, -1, smallest_nonzero_magnitude=4), 6.0)\n@example(float_constr(1, 4, smallest_nonzero_magnitude=4), -4.0)\n@example(float_constr(1, 4, smallest_nonzero_magnitude=4), -5.0)\n@example(float_constr(1, 4, smallest_nonzero_magnitude=4), -6.0)\n@example(float_constr(-5e-324, -0.0), 3.0)\n@example(float_constr(0.0, 0.0), -0.0)\n@example(float_constr(-0.0, -0.0), 0.0)\n@given(float_constraints(), st.floats())\ndef test_float_clamper(constraints, input_value):\n    min_value = constraints[\"min_value\"]\n    max_value = constraints[\"max_value\"]\n    allow_nan = constraints[\"allow_nan\"]\n    smallest_nonzero_magnitude = constraints[\"smallest_nonzero_magnitude\"]\n    clamper = make_float_clamper(\n        min_value,\n        max_value,\n        smallest_nonzero_magnitude=smallest_nonzero_magnitude,\n        allow_nan=allow_nan,\n    )\n    clamped = clamper(input_value)\n    if math.isnan(clamped):\n        # we should only clamp to nan if nans are allowed.\n        assert allow_nan\n    else:\n        # otherwise, we should have clamped to something in the permitted range.\n        assert sign_aware_lte(min_value, clamped)\n        assert sign_aware_lte(clamped, max_value)\n\n    # if input_value was permitted in the first place, then the clamped value should\n    # be the same as the input value.\n    if choice_permitted(\n        input_value,\n        {\n            \"min_value\": min_value,\n            \"max_value\": max_value,\n            \"allow_nan\": allow_nan,\n            \"smallest_nonzero_magnitude\": smallest_nonzero_magnitude,\n        },\n    ):\n        assert choice_equal(input_value, clamped)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_functions.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom inspect import signature\n\nimport pytest\n\nfrom hypothesis import Verbosity, assume, find, given, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument, InvalidState\nfrom hypothesis.reporting import with_reporter\nfrom hypothesis.strategies import booleans, functions, integers\n\nfrom tests.common.debug import check_can_generate_examples\n\n\ndef func_a():\n    pass\n\n\n@given(functions(like=func_a, returns=booleans()))\ndef test_functions_no_args(f):\n    assert f.__name__ == \"func_a\"\n    assert f is not func_a\n    assert isinstance(f(), bool)\n\n\ndef func_b(a, b, c):\n    pass\n\n\n@given(functions(like=func_b, returns=booleans()))\ndef test_functions_with_args(f):\n    assert f.__name__ == \"func_b\"\n    assert f is not func_b\n    with pytest.raises(TypeError):\n        f()\n    assert isinstance(f(1, 2, 3), bool)\n\n\ndef func_c(**kwargs):\n    pass\n\n\n@given(functions(like=func_c, returns=booleans()))\ndef test_functions_kw_args(f):\n    assert f.__name__ == \"func_c\"\n    assert f is not func_c\n    with pytest.raises(TypeError):\n        f(1, 2, 3)\n    assert isinstance(f(a=1, b=2, c=3), bool)\n\n\n@given(functions(like=lambda: None, returns=booleans()))\ndef test_functions_argless_lambda(f):\n    assert f.__name__ == \"<lambda>\"\n    with pytest.raises(TypeError):\n        f(1)\n    assert isinstance(f(), bool)\n\n\n@given(functions(like=lambda a: None, returns=booleans()))\ndef test_functions_lambda_with_arg(f):\n    assert f.__name__ == \"<lambda>\"\n    with pytest.raises(TypeError):\n        f()\n    assert isinstance(f(1), bool)\n\n\n@pytest.mark.parametrize(\n    \"like,returns,pure\",\n    [\n        (None, booleans(), False),\n        (lambda: None, \"not a strategy\", True),\n        (lambda: None, booleans(), None),\n    ],\n)\ndef test_invalid_arguments(like, returns, pure):\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(functions(like=like, returns=returns, pure=pure))\n\n\ndef func_returns_str() -> str:\n    return \"a string\"\n\n\n@given(functions(like=func_returns_str))\ndef test_functions_strategy_return_type_inference(f):\n    result = f()\n    assume(result != \"a string\")\n    assert isinstance(result, str)\n\n\ndef test_functions_valid_within_given_invalid_outside():\n    cache = None\n\n    @given(functions())\n    def t(f):\n        nonlocal cache\n        cache = f\n        assert f() is None\n\n    t()\n    with pytest.raises(InvalidState):\n        cache()\n\n\ndef test_can_call_default_like_arg():\n    # This test is somewhat silly, but coverage complains about the uncovered\n    # branch for calling it otherwise and alternative workarounds are worse.\n    like, returns, pure = signature(functions).parameters.values()\n    assert like.default() is None\n    assert returns.default is ...\n    assert pure.default is False\n\n\ndef func(arg, *, kwonly_arg):\n    pass\n\n\n@given(functions(like=func))\ndef test_functions_strategy_with_kwonly_args(f):\n    with pytest.raises(TypeError):\n        f(1, 2)\n    f(1, kwonly_arg=2)\n    f(kwonly_arg=2, arg=1)\n\n\ndef pure_func(arg1, arg2):\n    pass\n\n\n@given(\n    f=functions(like=pure_func, returns=integers(), pure=True),\n    arg1=integers(),\n    arg2=integers(),\n)\ndef test_functions_pure_with_same_args(f, arg1, arg2):\n    # Same regardless of calling convention, unlike functools.lru_cache()\n    expected = f(arg1, arg2)\n    assert f(arg1, arg2) == expected\n    assert f(arg1, arg2=arg2) == expected\n    assert f(arg1=arg1, arg2=arg2) == expected\n    assert f(arg2=arg2, arg1=arg1) == expected\n\n\n@given(\n    f=functions(like=pure_func, returns=integers(), pure=True),\n    arg1=integers(),\n    arg2=integers(),\n)\ndef test_functions_pure_with_different_args(f, arg1, arg2):\n    r1 = f(arg1, arg2)\n    r2 = f(arg2, arg1)\n    assume(r1 != r2)\n    # If this is never true, the test will fail with Unsatisfiable\n\n\n@given(\n    f1=functions(like=pure_func, returns=integers(), pure=True),\n    f2=functions(like=pure_func, returns=integers(), pure=True),\n)\ndef test_functions_pure_two_functions_different_args_different_result(f1, f2):\n    r1 = f1(1, 2)\n    r2 = f2(3, 4)\n    assume(r1 != r2)\n    # If this is never true, the test will fail with Unsatisfiable\n\n\n@given(\n    f1=functions(like=pure_func, returns=integers(), pure=True),\n    f2=functions(like=pure_func, returns=integers(), pure=True),\n    arg1=integers(),\n    arg2=integers(),\n)\ndef test_functions_pure_two_functions_same_args_different_result(f1, f2, arg1, arg2):\n    r1 = f1(arg1, arg2)\n    r2 = f2(arg1, arg2)\n    assume(r1 != r2)\n    # If this is never true, the test will fail with Unsatisfiable\n\n\n@settings(verbosity=Verbosity.verbose)\n@given(functions(pure=False))\ndef test_functions_note_all_calls_to_impure_functions(f):\n    ls = []\n    with with_reporter(ls.append):\n        f()\n        f()\n    assert len(ls) == 2\n\n\n@settings(verbosity=Verbosity.verbose)\n@given(functions(pure=True))\ndef test_functions_note_only_first_to_pure_functions(f):\n    ls = []\n    with with_reporter(ls.append):\n        f()\n        f()\n    assert len(ls) == 1\n\n\ndef test_functions_supports_find():\n    f = find(\n        st.functions(like=pure_func, returns=st.integers(), pure=True), lambda x: True\n    )\n    with pytest.raises(InvalidState):\n        f(1, 2)\n    assert f.__name__ == pure_func.__name__\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_fuzz_one_input.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport io\nimport unittest\nfrom operator import attrgetter\nfrom random import randbytes\n\nimport pytest\n\nfrom hypothesis import Phase, given, settings, strategies as st\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.conjecture.engine import shortlex\n\n\n@pytest.mark.parametrize(\n    \"buffer_type\",\n    [bytes, bytearray, memoryview, io.BytesIO],\n    ids=attrgetter(\"__name__\"),\n)\ndef test_fuzz_one_input(buffer_type):\n    db = InMemoryExampleDatabase()\n    seen = []\n    seeds = []\n\n    # This is a standard `@given` test, which we can also use as a fuzz target.\n    # Note that we specify the DB so we can make more precise assertions,\n    # and tighten the phases so we can be sure the failing examples come from fuzzing.\n    @given(st.text())\n    @settings(database=db, phases=[Phase.reuse, Phase.shrink])\n    def test(s):\n        seen.append(s)\n        assert len(s) < 5, repr(s)\n\n    # Before running fuzz_one_input, there's nothing in `db`, and so the test passes\n    # (because example generation is disabled by the custom settings)\n    with pytest.raises(unittest.SkipTest):  # because this generates no examples\n        test()\n    assert len(seen) == 0\n\n    # If we run a lot of random bytestrings through fuzz_one_input, we'll eventually\n    # find a failing example.\n    with pytest.raises(AssertionError):\n        for _ in range(1000):\n            buf = randbytes(1000)\n            seeds.append(buf)\n            test.hypothesis.fuzz_one_input(buffer_type(buf))\n\n    # fuzz_one_input returns False for invalid bytestrings, due to e.g. assume(False)\n    assert len(seen) <= len(seeds)\n\n    # `db` contains exactly one failing example, which is either the most\n    # recent seed that we tried or the pruned-and-canonicalised form of it.\n    (saved_examples,) = db.data.values()\n    assert len(saved_examples) == 1\n    assert shortlex(seeds[-1]) >= shortlex(next(iter(saved_examples)))\n\n    # Now that we have a failure in `db`, re-running our test is sufficient to\n    # reproduce it, *and shrink to a minimal example*.\n    with pytest.raises(AssertionError):\n        test()\n    assert seen[-1] == \"0\" * 5\n\n\ndef test_can_fuzz_with_database_eq_None():\n    # This test exists to cover the can't-record-failure branch.\n\n    @given(st.none())\n    @settings(database=None)\n    def test(s):\n        raise AssertionError\n\n    with pytest.raises(AssertionError):\n        test.hypothesis.fuzz_one_input(b\"\\x00\\x00\")\n\n\ndef test_fuzzing_unsatisfiable_test_always_returns_None():\n    # There are no examples of `st.none().filter(bool)`, but while the Hypothesis\n    # engine would give up, fuzz_one_input will just return None each time.\n\n    @given(st.none().filter(bool))\n    @settings(database=None)\n    def test(s):\n        raise AssertionError(\"Unreachable because there are no valid examples\")\n\n    for _ in range(100):\n        buf = randbytes(3)\n        ret = test.hypothesis.fuzz_one_input(buf)\n        assert ret is None\n\n\ndef test_autopruning_of_returned_buffer():\n    @given(st.binary(min_size=4, max_size=4))\n    @settings(database=None)\n    def test(s):\n        pass\n\n    # Unused portions of the input buffer are discarded from output.\n    # (and canonicalised, but that's a no-op for fixed-length `binary()`)\n    assert test.hypothesis.fuzz_one_input(b\"deadbeef\") == b\"dead\"\n\n\ndef test_can_access_strategy_for_wrapped_test():\n    strategy = st.builds(object)\n\n    @given(x=strategy)\n    def addx(x, y):\n        pass\n\n    @given(strategy)\n    def addy(x, y):\n        pass\n\n    assert addx.hypothesis._given_kwargs == {\"x\": strategy}\n    assert addy.hypothesis._given_kwargs == {\"y\": strategy}\n\n\n@pytest.mark.parametrize(\n    \"buffers,db_size\",\n    [\n        ([b\"aa\", b\"bb\", b\"cc\", b\"dd\"], 1),  # ascending -> only saves first\n        ([b\"dd\", b\"cc\", b\"bb\", b\"aa\"], 4),  # descending -> saves all\n        ([b\"cc\", b\"dd\", b\"aa\", b\"bb\"], 2),  # sawtooth -> saves cc then aa\n        ([b\"aa\", b\"bb\", b\"cc\", b\"XX\"], 2),  # two distinct errors -> saves both\n    ],\n)\ndef test_fuzz_one_input_does_not_add_redundant_entries_to_database(buffers, db_size):\n    db = InMemoryExampleDatabase()\n    seen = []\n\n    @given(st.binary(min_size=2, max_size=2))\n    @settings(database=db)\n    def test(s):\n        seen.append(s)\n        assert s != b\"XX\"\n        raise AssertionError\n\n    for buf in buffers:\n        with pytest.raises(AssertionError):\n            test.hypothesis.fuzz_one_input(buf)\n\n    (saved_examples,) = db.data.values()\n    assert seen == buffers\n    assert len(saved_examples) == db_size\n\n\ndef test_fuzzing_invalid_test_raises_error():\n    # Invalid: @given with too many positional arguments\n    @given(st.integers(), st.integers())\n    def invalid_test(s):\n        pass\n\n    with pytest.raises(InvalidArgument, match=\"Too many positional arguments\"):\n        # access the property to check error happens during setup\n        invalid_test.hypothesis.fuzz_one_input\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_given_error_conditions.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import assume, given, reject, settings\nfrom hypothesis._settings import all_settings\nfrom hypothesis.errors import InvalidArgument, Unsatisfiable\nfrom hypothesis.strategies import booleans, integers, nothing\n\nfrom tests.common.utils import fails_with\n\n\n@fails_with(Unsatisfiable)\n@given(booleans())\ndef test_raises_unsatisfiable_if_all_false_in_finite_set(x):\n    reject()\n\n\ndef test_does_not_raise_unsatisfiable_if_some_false_in_finite_set():\n    @given(booleans())\n    def test_assume_x(x):\n        assume(x)\n\n    test_assume_x()\n\n\ndef test_raises_unsatisfiable_if_passed_explicit_nothing():\n    @given(x=nothing())\n    def test_never_runs(x):\n        raise Exception(\"Can't ever execute this\")\n\n    with pytest.raises(\n        Unsatisfiable,\n        match=r\"Cannot generate examples from empty strategy: x=nothing\\(\\)\",\n    ):\n        test_never_runs()\n\n\ndef test_error_if_has_no_hints():\n    @given(a=...)\n    def inner(a):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        inner()\n\n\ndef test_error_if_infer_all_and_has_no_hints():\n    @given(...)\n    def inner(a):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        inner()\n\n\ndef test_error_if_infer_is_posarg():\n    @given(..., ...)\n    def inner(ex1: int, ex2: int):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        inner()\n\n\ndef test_error_if_infer_is_posarg_mixed_with_kwarg():\n    @given(..., ex2=...)\n    def inner(ex1: int, ex2: int):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        inner()\n\n\ndef test_given_twice_is_an_error():\n    @settings(deadline=None)\n    @given(booleans())\n    @given(integers())\n    def inner(a, b):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        inner()\n\n\n@fails_with(InvalidArgument)\ndef test_given_is_not_a_class_decorator():\n    @given(integers())\n    class test_given_is_not_a_class_decorator:\n        def __init__(self, i):\n            pass\n\n\ndef test_specific_error_for_coroutine_functions():\n    @settings(database=None)\n    @given(booleans())\n    async def foo(x):\n        pass\n\n    with pytest.raises(\n        InvalidArgument,\n        match=\"Hypothesis doesn't know how to run async test functions\",\n    ):\n        foo()\n\n\n@pytest.mark.parametrize(\"setting_name\", all_settings)\ndef test_suggests_at_settings_if_extra_kwarg_matches_setting_name(setting_name):\n    val = 1\n\n    # dynamically create functions with an extra kwarg argument which happens to\n    # match a settings variable. The user probably meant @settings.\n    # exec is pretty cursed here, but it does work.\n    namespace = {}\n    exec(\n        f\"\"\"\n@given(a=1, {setting_name}={val})\ndef foo(a):\n    pass\n    \"\"\",\n        globals(),\n        namespace,\n    )\n\n    with pytest.raises(\n        InvalidArgument,\n        match=rf\"Did you mean @settings\\({setting_name}={val}\\)\\?\",\n    ):\n        namespace[\"foo\"]()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_health_checks.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\nimport time\n\nimport pytest\n\nfrom hypothesis import HealthCheck, given, settings, strategies as st\nfrom hypothesis.control import assume, current_build_context\nfrom hypothesis.errors import FailedHealthCheck, InvalidArgument\nfrom hypothesis.internal.compat import int_from_bytes\nfrom hypothesis.stateful import (\n    RuleBasedStateMachine,\n    initialize,\n    invariant,\n    rule,\n    run_state_machine_as_test,\n)\nfrom hypothesis.strategies import SearchStrategy\n\nfrom tests.common.utils import Why, no_shrink, skipif_time_unpatched, xfail_on_crosshair\n\nHEALTH_CHECK_SETTINGS = settings(\n    max_examples=11, database=None, suppress_health_check=()\n)\n\n\ndef test_slow_generation_fails_a_health_check():\n    @settings(HEALTH_CHECK_SETTINGS, deadline=200)\n    @given(st.integers().map(lambda x: time.sleep(0.2)))\n    def test(x):\n        pass\n\n    with pytest.raises(FailedHealthCheck):\n        test()\n\n\ndef test_slow_generation_inline_fails_a_health_check():\n    @settings(HEALTH_CHECK_SETTINGS, deadline=200)\n    @given(st.data())\n    def test(data):\n        data.draw(st.integers().map(lambda x: time.sleep(0.2)))\n\n    with pytest.raises(FailedHealthCheck):\n        test()\n\n\ndef test_default_health_check_can_weaken_specific():\n    import random\n\n    @settings(HEALTH_CHECK_SETTINGS, suppress_health_check=list(HealthCheck))\n    @given(st.lists(st.integers(), min_size=1))\n    def test(x):\n        random.choice(x)\n\n    test()\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\", reason=\"nondeterministic\"\n)\ndef test_suppressing_filtering_health_check():\n    forbidden = set()\n\n    def unhealthy_filter(x):\n        if len(forbidden) < 200:\n            forbidden.add(x)\n        return x not in forbidden\n\n    @HEALTH_CHECK_SETTINGS\n    @given(st.integers().filter(unhealthy_filter))\n    def test1(x):\n        raise ValueError\n\n    with pytest.raises(FailedHealthCheck):\n        test1()\n\n    forbidden = set()\n\n    @settings(suppress_health_check=[HealthCheck.filter_too_much, HealthCheck.too_slow])\n    @given(st.integers().filter(unhealthy_filter))\n    def test2(x):\n        raise ValueError\n\n    with pytest.raises(ValueError):\n        test2()\n\n\ndef test_filtering_everything_fails_a_health_check():\n    @given(st.integers().filter(lambda x: False))\n    @settings(database=None, suppress_health_check=())\n    def test(x):\n        pass\n\n    with pytest.raises(FailedHealthCheck, match=\"filter\"):\n        test()\n\n\nclass fails_regularly(SearchStrategy):\n    def do_draw(self, data):\n        b = int_from_bytes(data.draw_bytes(2, 2))\n        assume(b == 3)\n\n\ndef test_filtering_most_things_fails_a_health_check():\n    @given(fails_regularly())\n    @settings(database=None, phases=no_shrink, suppress_health_check=())\n    def test(x):\n        if current_build_context().data.provider.avoid_realization:\n            pytest.skip(\"symbolic backends can filter efficiently!\")\n\n    with pytest.raises(FailedHealthCheck, match=\"filter\"):\n        test()\n\n\ndef test_returning_non_none_is_forbidden():\n    @given(st.integers())\n    def a(x):\n        return 1\n\n    with pytest.raises(FailedHealthCheck):\n        a()\n\n\n@skipif_time_unpatched  # takes forever\ndef test_the_slow_test_health_check_can_be_disabled():\n    @given(st.integers())\n    @settings(deadline=None)\n    def a(x):\n        time.sleep(1000)\n\n    a()\n\n\n@skipif_time_unpatched  # takes forever\ndef test_the_slow_test_health_only_runs_if_health_checks_are_on():\n    @given(st.integers())\n    @settings(suppress_health_check=list(HealthCheck), deadline=None)\n    def a(x):\n        time.sleep(1000)\n\n    a()\n\n\nclass sample_test_runner:\n    @given(st.none())\n    def test(self, _):\n        pass\n\n\ndef test_differing_executors_fails_health_check():\n    sample_test_runner().test()\n    msg = re.escape(str(HealthCheck.differing_executors))\n    with pytest.raises(FailedHealthCheck, match=msg):\n        sample_test_runner().test()\n\n\ndef test_it_is_an_error_to_suppress_non_iterables():\n    with pytest.raises(InvalidArgument):\n        settings(suppress_health_check=1)\n\n\ndef test_it_is_an_error_to_suppress_non_healthchecks():\n    with pytest.raises(InvalidArgument):\n        settings(suppress_health_check=[\"notahealthcheck\"])\n\n\nclass ReturningRuleMachine(RuleBasedStateMachine):\n    @rule()\n    def r(self):\n        return \"any non-None value\"\n\n\nclass ReturningInitializeMachine(RuleBasedStateMachine):\n    _ = rule()(lambda self: None)\n\n    @initialize()\n    def r(self):\n        return \"any non-None value\"\n\n\nclass ReturningInvariantMachine(RuleBasedStateMachine):\n    _ = rule()(lambda self: None)\n\n    @invariant(check_during_init=True)\n    def r(self):\n        return \"any non-None value\"\n\n\n@pytest.mark.parametrize(\n    \"cls\", [ReturningRuleMachine, ReturningInitializeMachine, ReturningInvariantMachine]\n)\ndef test_stateful_returnvalue_healthcheck(cls):\n    with pytest.raises(FailedHealthCheck):\n        run_state_machine_as_test(cls, settings=settings())\n\n\ndef test_nested_given_raises_healthcheck():\n    @given(st.integers())\n    def f(n1):\n        @given(st.integers())\n        def g(n2):\n            pass\n\n        g()\n\n    with pytest.raises(FailedHealthCheck):\n        f()\n\n\ndef test_triply_nested_given_raises_healthcheck():\n    @given(st.integers())\n    @settings(max_examples=10)\n    def f(n1):\n\n        @given(st.integers())\n        @settings(max_examples=10)\n        def g(n2):\n\n            @given(st.integers())\n            @settings(max_examples=10)\n            def h(n3):\n                pass\n\n            h()\n\n        g()\n\n    with pytest.raises(FailedHealthCheck):\n        f()\n\n\n@xfail_on_crosshair(Why.nested_given)\ndef test_can_suppress_nested_given():\n    @given(st.integers())\n    @settings(suppress_health_check=[HealthCheck.nested_given], max_examples=5)\n    def f(n1):\n\n        @given(st.integers())\n        @settings(max_examples=5)\n        def g(n2):\n            pass\n\n        g()\n\n    f()\n\n\ndef test_cant_suppress_nested_given_on_inner():\n    # nested_given has to be suppressed at the function right above the nesting.\n    # this isn't a principled design choice, but a limitation of how we access\n    # the current settings.\n    @given(st.integers())\n    @settings(max_examples=5)\n    def f(n1):\n\n        @given(st.integers())\n        @settings(suppress_health_check=[HealthCheck.nested_given], max_examples=5)\n        def g(n2):\n            pass\n\n        g()\n\n    with pytest.raises(FailedHealthCheck):\n        f()\n\n\n@xfail_on_crosshair(Why.nested_given)\ndef test_suppress_triply_nested_given():\n    # both suppressions are necessary here\n    @given(st.integers())\n    @settings(suppress_health_check=[HealthCheck.nested_given], max_examples=5)\n    def f(n1):\n\n        @given(st.integers())\n        @settings(suppress_health_check=[HealthCheck.nested_given], max_examples=5)\n        def g(n2):\n\n            @given(st.integers())\n            @settings(max_examples=5)\n            def h(n3):\n                pass\n\n            h()\n\n        g()\n\n    f()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_interactive_example.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport subprocess\nimport sys\nimport warnings\nfrom decimal import Decimal\n\nimport pytest\n\nfrom hypothesis import example, find, given, settings, strategies as st\nfrom hypothesis.errors import (\n    HypothesisException,\n    InvalidArgument,\n    NonInteractiveExampleWarning,\n    Unsatisfiable,\n)\nfrom hypothesis.internal.compat import WINDOWS\n\nfrom tests.common.debug import find_any\nfrom tests.common.utils import (\n    Why,\n    fails_with,\n    skipif_emscripten,\n    skipif_threading,\n    xfail_on_crosshair,\n)\n\npytest_plugins = \"pytester\"\n# .example() uses random.shuffle, which changes the global random state and\n# produces \"do not use the `random` module inside strategies\" deprecation warnings.\n#\n# Since we recommend against using .example() interactively, fixing this is\n# an enhancement, not a bug.\npytestmark = pytest.mark.skipif(\n    settings.get_current_profile_name() == \"threading\",\n    reason=\".example() is not thread-safe\",\n)\n\n\n# Allow calling .example() without warnings for all tests in this module\n@pytest.fixture(scope=\"function\", autouse=True)\ndef _allow_noninteractive_example():\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", NonInteractiveExampleWarning)\n        yield\n\n\ndef test_example_of_none_is_none():\n    assert st.none().example() is None\n\n\ndef test_exception_in_compare_can_still_have_example():\n    st.one_of(st.none().map(lambda n: Decimal(\"snan\")), st.just(Decimal(0))).example()\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context)\ndef test_does_not_always_give_the_same_example():\n    s = st.integers()\n    assert len({s.example() for _ in range(100)}) >= 10\n\n\ndef test_raises_on_no_examples():\n    with pytest.raises(Unsatisfiable):\n        st.nothing().example()\n\n\n@fails_with(HypothesisException)\n@example(False)\n@given(st.booleans())\ndef test_example_inside_given(b):\n    st.integers().example()\n\n\n@fails_with(HypothesisException)\ndef test_example_inside_find():\n    find(st.integers(0, 100), lambda x: st.integers().example())\n\n\n@fails_with(HypothesisException)\ndef test_example_inside_strategy():\n    find_any(st.booleans().map(lambda x: st.integers().example()))\n\n\ndef test_raises_on_arbitrary_data():\n    with pytest.raises(InvalidArgument):\n        st.data().example()\n\n\ndef test_non_interactive_example_emits_warning():\n    # Revert the effect of the allow_noninteractive_example autouse fixture\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"always\")\n        with pytest.warns(NonInteractiveExampleWarning):\n            st.text().example()\n\n\nEXAMPLE_GENERATING_TEST = \"\"\"\nfrom hypothesis import strategies as st\n\ndef test_interactive_example():\n    st.integers().example()\n\"\"\"\n\n\n@skipif_threading  # pytester not thread safe\ndef test_selftests_exception_contains_note(pytester):\n    # The note is added by a pytest hook, so we need to run it under pytest in a\n    # subenvironment with (effectively) the same toplevel conftest.\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"error\")\n\n        pytester.makeconftest(\"from tests.conftest import *\")\n        result = pytester.runpytest_inprocess(\n            pytester.makepyfile(EXAMPLE_GENERATING_TEST), \"-p\", \"no:cacheprovider\"\n        )\n        assert \"helper methods in tests.common.debug\" in \"\\n\".join(result.outlines)\n\n\n@skipif_emscripten\ndef test_script_example_does_not_emit_warning(tmp_path):\n    script = tmp_path / \"script.py\"\n    script.write_text(\n        \"from hypothesis.strategies import integers\\nintegers().example()\\n\",\n        encoding=\"utf-8\",\n    )\n    # get rid of PYTEST_CURRENT_TEST, which we special-case as forcing this\n    # warning to still appear\n    env = os.environ.copy()\n    env.pop(\"PYTEST_CURRENT_TEST\")\n    subprocess.check_call([sys.executable, \"-Werror\", str(script)], env=env)\n\n\n@skipif_emscripten\n@pytest.mark.skipif(WINDOWS, reason=\"pexpect.spawn not supported on Windows\")\ndef test_interactive_example_does_not_emit_warning():\n    import pexpect\n\n    try:\n        child = pexpect.spawn(f\"{sys.executable} -Werror\")\n        child.expect(\">>> \", timeout=10)\n    except pexpect.exceptions.EOF:\n        pytest.skip(\n            \"Unable to run python with -Werror.  This may be because you are \"\n            \"running from an old virtual environment - update your installed \"\n            \"copy of `virtualenv` and then create a fresh environment.\"\n        )\n    child.sendline(\"from hypothesis.strategies import none\")\n    child.sendline(\"none().example()\")\n    child.sendline(\"quit(code=0)\")\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_internal_helpers.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis.internal.floats import is_negative\n\n\ndef test_is_negative_gives_good_type_error():\n    x = \"foo\"\n    with pytest.raises(TypeError) as e:\n        is_negative(x)\n    assert repr(x) in e.value.args[0]\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_intervalset.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import HealthCheck, assume, example, given, settings, strategies as st\nfrom hypothesis.internal.conjecture.provider_conformance import (\n    interval_lists,\n    intervals,\n)\nfrom hypothesis.internal.intervalsets import IntervalSet\n\n# various tests in this file impose a max_codepoint restriction on intervals,\n# for performance. There may be possibilities for performance improvements in\n# IntervalSet itself as well.\n\n\n@given(intervals(max_codepoint=200))\ndef test_intervals_are_equivalent_to_their_lists(intervals):\n    ls = list(intervals)\n    assert len(ls) == len(intervals)\n    for i in range(len(ls)):\n        assert ls[i] == intervals[i]\n    for i in range(1, len(ls) - 1):\n        assert ls[-i] == intervals[-i]\n\n\n@given(intervals(max_codepoint=200))\ndef test_intervals_match_indexes(intervals):\n    ls = list(intervals)\n    for v in ls:\n        assert ls.index(v) == intervals.index(v)\n\n\n@example(intervals=IntervalSet(((1, 1),)), v=0)\n@example(intervals=IntervalSet(()), v=0)\n@given(intervals(), st.integers(0, 0x10FFFF))\ndef test_error_for_index_of_not_present_value(intervals, v):\n    assume(v not in intervals)\n    with pytest.raises(ValueError):\n        intervals.index(v)\n\n\ndef test_validates_index():\n    with pytest.raises(IndexError):\n        IntervalSet([])[1]\n\n    with pytest.raises(IndexError):\n        IntervalSet([[1, 10]])[11]\n\n    with pytest.raises(IndexError):\n        IntervalSet([[1, 10]])[-11]\n\n\ndef test_index_above_is_index_if_present():\n    assert IntervalSet([[1, 10]]).index_above(1) == 0\n    assert IntervalSet([[1, 10]]).index_above(2) == 1\n\n\ndef test_index_above_is_length_if_higher():\n    assert IntervalSet([[1, 10]]).index_above(100) == 10\n\n\ndef intervals_to_set(ints):\n    return set(IntervalSet(ints))\n\n\n@settings(suppress_health_check=[HealthCheck.filter_too_much, HealthCheck.too_slow])\n@example(x=[(0, 1), (3, 3)], y=[(1, 3)])\n@example(x=[(0, 1)], y=[(0, 0), (1, 1)])\n@example(x=[(0, 1)], y=[(1, 1)])\n@given(interval_lists(max_codepoint=200), interval_lists(max_codepoint=200))\ndef test_subtraction_of_intervals(x, y):\n    xs = intervals_to_set(x)\n    ys = intervals_to_set(y)\n    assume(not xs.isdisjoint(ys))\n    z = IntervalSet(x).difference(IntervalSet(y)).intervals\n    assert z == tuple(sorted(z))\n    for a, b in z:\n        assert a <= b\n    assert intervals_to_set(z) == intervals_to_set(x) - intervals_to_set(y)\n\n\n@given(intervals(max_codepoint=200), intervals(max_codepoint=200))\ndef test_interval_intersection(x, y):\n    assert set(x & y) == set(x) & set(y)\n    assert set(x.intersection(y)) == set(x).intersection(y)\n\n\ndef test_char_in_shrink_order():\n    xs = IntervalSet([(0, 256)])\n    assert xs[xs._idx_of_zero] == ord(\"0\")\n    assert xs[xs._idx_of_Z] == ord(\"Z\")\n    rewritten = [ord(xs.char_in_shrink_order(i)) for i in range(256)]\n    assert rewritten != list(range(256))\n    assert sorted(rewritten) == sorted(range(256))\n\n\ndef test_index_from_char_in_shrink_order():\n    xs = IntervalSet([(0, 256)])\n    for i in xs:\n        assert xs.index_from_char_in_shrink_order(xs.char_in_shrink_order(i)) == i\n\n\ndef test_intervalset_equal():\n    xs1 = IntervalSet([(0, 256)])\n    xs2 = IntervalSet([(0, 256)])\n    assert xs1 == xs2\n\n    xs3 = IntervalSet([(0, 255)])\n    assert xs2 != xs3\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_lambda_formatting.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport runpy\nimport sys\n\nimport pytest\n\nfrom hypothesis.internal import lambda_sources\nfrom hypothesis.internal.conjecture.utils import identity\nfrom hypothesis.internal.reflection import get_pretty_function_description\n\nfrom tests.common.utils import skipif_threading\n\n\n@pytest.fixture(autouse=True, params=[True, False])\ndef clear_lambda_caches(request, monkeypatch):\n    # Run all tests in this file twice, once using cache and once forcing\n    # from-scratch generation\n    if request.param:\n        monkeypatch.setattr(lambda_sources, \"LAMBDA_DESCRIPTION_CACHE\", {})\n        monkeypatch.setattr(lambda_sources, \"LAMBDA_DIGEST_DESCRIPTION_CACHE\", {})\n        monkeypatch.setattr(lambda_sources, \"AST_LAMBDAS_CACHE\", {})\n    return request.param\n\n\ndef test_bracket_whitespace_is_stripped():\n    # fmt: off\n    t = lambda x: (x + 1 )\n    # fmt: on\n    assert get_pretty_function_description(t) == \"lambda x: x + 1\"\n\n\ndef test_can_have_unicode_in_lambda_sources():\n    t = lambda x: \"é\" not in x\n    assert get_pretty_function_description(t) == \"lambda x: 'é' not in x\"\n\n\n@pytest.mark.skipif(\n    sys.version_info < (3, 11), reason=\"nested lambdas fail compile-test\"\n)\ndef test_can_get_descriptions_of_nested_lambdas_with_different_names():\n    # fmt: off\n    ordered_pair = (\n        lambda right: [].map(\n            lambda length: ()))\n    # fmt: on\n    assert (\n        get_pretty_function_description(ordered_pair)\n        == \"lambda right: [].map(lambda length: ())\"\n    )\n\n\ndef test_does_not_error_on_unparsable_source():\n    # fmt: off\n    t = [\n        lambda x: \\\n        # This will break ast.parse, but the brackets are needed for the real\n        # parser to accept this lambda\n        x][0]\n    # fmt: on\n    assert get_pretty_function_description(t) == \"lambda x: x\"\n\n\n@pytest.mark.skipif(\n    sys.version_info < (3, 11), reason=\"nested lambdas fail compile-test\"\n)\ndef test_separate_line_map_filter():\n    # this isn't intentionally testing nested lambdas, but hey, it's a nice bonus.\n    # fmt: off\n    f1 = (\n        lambda x: x\n        .map(lambda y: y)\n    )\n    f2 = (\n        lambda x: x\n        .filter(lambda y: y)\n    )\n    # fmt: on\n\n    assert get_pretty_function_description(f1) == \"lambda x: x.map(lambda y: y)\"\n    assert get_pretty_function_description(f2) == \"lambda x: x.filter(lambda y: y)\"\n\n\ndef test_source_of_lambda_is_pretty():\n    assert get_pretty_function_description(lambda x: True) == \"lambda x: True\"\n\n\ndef test_variable_names_are_not_pretty():\n    t = lambda x: True\n    assert get_pretty_function_description(t) == \"lambda x: True\"\n\n\ndef test_does_not_error_on_dynamically_defined_functions():\n    x = eval(\"lambda t: 1\")\n    assert get_pretty_function_description(x) == \"lambda t: <unknown>\"\n\n\ndef test_collapses_whitespace_nicely():\n    # fmt: off\n    t = (\n        lambda x,       y:           1\n    )\n    # fmt: on\n    assert get_pretty_function_description(t) == \"lambda x, y: 1\"\n\n\ndef test_is_not_confused_by_tuples():\n    p = (lambda x: x > 1, 2)[0]\n\n    assert get_pretty_function_description(p) == \"lambda x: x > 1\"\n\n\ndef test_strips_comments_from_the_end():\n    t = lambda x: 1  # A lambda comment\n    assert get_pretty_function_description(t) == \"lambda x: 1\"\n\n\ndef test_does_not_strip_hashes_within_a_string():\n    t = lambda x: \"#\"\n    assert get_pretty_function_description(t) == \"lambda x: '#'\"\n\n\ndef test_can_distinguish_between_two_lambdas_with_different_args():\n    a, b = (lambda x: 1, lambda y: 2)\n    assert get_pretty_function_description(a) == \"lambda x: 1\"\n    assert get_pretty_function_description(b) == \"lambda y: 2\"\n\n\ndef test_can_distinguish_between_two_lambdas_with_different_constants():\n    a, b = (lambda x: 1, lambda x: 2)\n    assert get_pretty_function_description(a) == \"lambda x: 1\"\n    assert get_pretty_function_description(b) == \"lambda x: 2\"\n\n\ndef test_can_distinguish_between_two_lambdas_with_different_signatures():\n    a, b = (lambda x: x, lambda y: y)\n    assert get_pretty_function_description(a) == \"lambda x: x\"\n    assert get_pretty_function_description(b) == \"lambda y: y\"\n\n\ndef test_can_distinguish_between_two_lambdas_where_one_fails_localparse():\n    # fmt: off\n    a, b = (\n        lambda x: x,\n        lambda x: x\n        or None,\n    )\n    # fmt: on\n    assert get_pretty_function_description(a) == \"lambda x: x\"\n    assert get_pretty_function_description(b) == \"lambda x: x or None\"\n\n\ndef test_does_not_get_confused_by_identical_lambdas():\n    a, b = (lambda x: 1, lambda x: 1)\n    assert get_pretty_function_description(a) == \"lambda x: 1\"\n    assert get_pretty_function_description(b) == \"lambda x: 1\"\n\n\nc = 1\nlambda_capturing_globals = (lambda: c, lambda: 1)\n\n\ndef test_lambda_capturing_globals():\n    assert get_pretty_function_description(lambda_capturing_globals[0]) == \"lambda: c\"\n    assert get_pretty_function_description(lambda_capturing_globals[1]) == \"lambda: 1\"\n\n\ndef test_lambda_capturing_locals():\n    const = 1\n    a, b = (lambda: const, lambda: 1)\n    assert get_pretty_function_description(a) == \"lambda: const\"\n    assert get_pretty_function_description(b) == \"lambda: 1\"\n\n\ndef test_can_distinguish_between_two_lambdas_with_different_captures():\n    # fmt: off\n    a = 1; f1 = lambda x=a: x; a=2; f2=lambda x=a: x  # noqa: E702\n    # fmt: on\n\n    assert get_pretty_function_description(f1) == \"lambda x=1: x\"\n    assert get_pretty_function_description(f2) == \"lambda x=2: x\"\n\n\ndef test_lambda_source_break_after_bracket():\n    # Issue #4498 regression test, inspect.getsource only sees the first line\n    # fmt: off\n    f = (\n        lambda x: x\n        or None\n    )\n    # fmt: on\n\n    source = get_pretty_function_description(f)\n    assert source == \"lambda x: x or None\"\n\n\ndef test_lambda_source_break_after_def_with_brackets():\n    # fmt: off\n    f = (lambda n:\n         'aaa')\n    # fmt: on\n\n    source = get_pretty_function_description(f)\n    assert source == \"lambda n: 'aaa'\"\n\n\ndef test_lambda_source_break_after_def_with_line_continuation():\n    # fmt: off\n    f = lambda n:\\\n        'aaa'\n    # fmt: on\n\n    source = get_pretty_function_description(f)\n    assert source == \"lambda n: 'aaa'\"\n\n\ndef arg_decorator(*s):\n    def accept(f):\n        return s\n\n    return accept\n\n\n@arg_decorator(lambda x: x + 1)\ndef plus_one():\n    pass\n\n\n@arg_decorator(lambda x: x + 1, lambda y: y * 2)\ndef two_decorators():\n    pass\n\n\ndef test_can_extract_lambda_repr_in_a_decorator():\n    assert get_pretty_function_description(plus_one[0]) == \"lambda x: x + 1\"\n\n\ndef test_can_extract_two_lambdas_from_a_decorator_if_args_differ():\n    a, b = two_decorators\n    assert get_pretty_function_description(a) == \"lambda x: x + 1\"\n    assert get_pretty_function_description(b) == \"lambda y: y * 2\"\n\n\n@arg_decorator(lambda: ())\ndef to_brackets():\n    pass\n\n\ndef test_can_handle_brackets_in_decorator_argument():\n    assert get_pretty_function_description(to_brackets[0]) == \"lambda: ()\"\n\n\n@arg_decorator(identity(lambda x: x + 1))\ndef decorator_with_wrapper():\n    pass\n\n\ndef test_can_handle_nested_lambda_in_decorator_argument():\n    assert (\n        get_pretty_function_description(decorator_with_wrapper[0]) == \"lambda x: x + 1\"\n    )\n\n\n@skipif_threading  # concurrent writes to the same file\ndef test_modifying_lambda_source_code_returns_unknown(tmp_path):\n    # see https://github.com/HypothesisWorks/hypothesis/pull/4452\n    test_module = tmp_path / \"test_module.py\"\n    test_module.write_text(\n        \"# line one\\n\\ntest_lambda = lambda x: x * 2\", encoding=\"utf-8\"\n    )\n\n    module_globals = runpy.run_path(str(test_module))\n    test_module.write_text(\"# line one\\n\\n# line two\", encoding=\"utf-8\")\n    assert (\n        get_pretty_function_description(module_globals[\"test_lambda\"])\n        == \"lambda x: <unknown>\"\n    )\n\n\n@skipif_threading  # concurrent writes to the same file\ndef test_adding_other_lambda_does_not_confuse(tmp_path):\n    test_module = tmp_path / \"test_module.py\"\n    test_module.write_text(\n        \"# line one\\ntest_lambda = lambda x: x * 2\", encoding=\"utf-8\"\n    )\n    module_globals = runpy.run_path(str(test_module))\n\n    test_module.write_text(\n        \"# line one\\nlambda x: x\\n\\n\\ntest_lambda = lambda x: x * 2\", encoding=\"utf-8\"\n    )\n    f1 = module_globals[\"test_lambda\"]\n    assert get_pretty_function_description(f1) == \"lambda x: x * 2\"\n\n\n@skipif_threading  # concurrent writes to the same file\ndef test_changing_lambda_confuses(tmp_path, allow_unknown_lambdas, clear_lambda_caches):\n    if not clear_lambda_caches:\n        pytest.skip(\"requires clean cache\")\n    test_module = tmp_path / \"test_module.py\"\n    test_module.write_text(\"test_lambda = lambda x: x * 2\", encoding=\"utf-8\")\n    module_globals = runpy.run_path(str(test_module))\n\n    test_module.write_text(\"lambda x: x\", encoding=\"utf-8\")\n    f1 = module_globals[\"test_lambda\"]\n    assert get_pretty_function_description(f1) == \"lambda x: <unknown>\"\n\n\n@skipif_threading  # concurrent writes to the same file\n@pytest.mark.skipif(sys.version_info[:2] < (3, 11), reason=\"not checked before 3.11\")\ndef test_that_test_harness_raises_on_unknown_lambda(tmp_path):\n    test_module = tmp_path / \"test_module.py\"\n    test_module.write_text(\"test_lambda = lambda x: x * 2\", encoding=\"utf-8\")\n    module_globals = runpy.run_path(str(test_module))\n\n    test_module.write_text(\"lambda x: x\", encoding=\"utf-8\")\n    f1 = module_globals[\"test_lambda\"]\n    with pytest.raises(AssertionError):\n        assert get_pretty_function_description(f1) == \"lambda x: <unknown>\"\n\n\n@skipif_threading  # concurrent writes to the same file\ndef test_source_with_syntax_error(tmp_path, allow_unknown_lambdas, clear_lambda_caches):\n    if not clear_lambda_caches:\n        pytest.skip(\"requires clean cache\")\n    test_module = tmp_path / \"test_module.py\"\n    test_module.write_text(\"test_lambda = lambda x: x * 2\", encoding=\"utf-8\")\n    module_globals = runpy.run_path(str(test_module))\n    f1 = module_globals[\"test_lambda\"]\n\n    test_module.write_text(\"line 1\", encoding=\"utf-8\")\n    assert get_pretty_function_description(f1) == \"lambda x: <unknown>\"\n\n\n@skipif_threading  # concurrent writes to the same file\ndef test_unknown_is_not_stuck(tmp_path, allow_unknown_lambdas, clear_lambda_caches):\n    if not clear_lambda_caches:\n        pytest.skip(\"requires clean cache\")\n    test_module = tmp_path / \"test_module.py\"\n    test_module.write_text(\"test_lambda = lambda x: x * 2\", encoding=\"utf-8\")\n    module_globals = runpy.run_path(str(test_module))\n    f1 = module_globals[\"test_lambda\"]\n\n    test_module.write_text(\"line 1\", encoding=\"utf-8\")\n    assert get_pretty_function_description(f1) == \"lambda x: <unknown>\"\n\n    test_module2 = tmp_path / \"test_module2.py\"\n    test_module2.write_text(\"test_lambda = lambda x: x * 2\", encoding=\"utf-8\")\n    module_globals2 = runpy.run_path(str(test_module2))\n    f2 = module_globals2[\"test_lambda\"]\n\n    # f2 matches f1 in the digest cache, ensure that it gets a proper description\n    assert get_pretty_function_description(f1) == \"lambda x: <unknown>\"\n    assert get_pretty_function_description(f2) == \"lambda x: x * 2\"\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_lazy_import.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport subprocess\nimport sys\n\nfrom tests.common.utils import skipif_emscripten\n\nSHOULD_NOT_IMPORT_TEST_RUNNERS = \"\"\"\nimport sys\nimport unittest\nfrom hypothesis import given, strategies as st\n\nclass TestDoesNotImportRunners(unittest.TestCase):\n    strat = st.integers() | st.floats() | st.sampled_from([\"a\", \"b\"])\n\n    @given(strat)\n    def test_does_not_import_unittest2(self, x):\n        assert \"unittest2\" not in sys.modules\n\n    @given(strat)\n    def test_does_not_import_nose(self, x):\n        assert \"nose\" not in sys.modules\n        assert \"nose2\" not in sys.modules\n\n    @given(strat)\n    def test_does_not_import_pytest(self, x):\n        assert \"pytest\" not in sys.modules\n\nif __name__ == '__main__':\n    unittest.main()\n\"\"\"\n\n\n@skipif_emscripten\ndef test_hypothesis_does_not_import_test_runners(tmp_path):\n    # We obviously can't use pytest to check that pytest is not imported,\n    # so for consistency we use unittest for all three non-stdlib test runners.\n    # It's unclear which of our dependencies is importing unittest, but\n    # since I doubt it's causing any spurious failures I don't really care.\n    # See https://github.com/HypothesisWorks/hypothesis/pull/2204\n    fname = tmp_path / \"test.py\"\n    fname.write_text(SHOULD_NOT_IMPORT_TEST_RUNNERS, encoding=\"utf-8\")\n    subprocess.check_call(\n        [sys.executable, str(fname)],\n        env={**os.environ, \"HYPOTHESIS_NO_PLUGINS\": \"1\"},\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_lookup.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport abc\nimport builtins\nimport collections\nimport contextlib\nimport datetime\nimport enum\nimport inspect\nimport io\nimport random\nimport re\nimport string\nimport sys\nimport typing\nimport warnings\nfrom dataclasses import dataclass\nfrom inspect import signature\nfrom numbers import Real\nfrom typing import (\n    Dict as _Dict,\n    FrozenSet as _FrozenSet,\n    List as _List,\n    Set as _Set,\n    Tuple as _Tuple,\n    Type as _Type,\n)\n\nimport pytest\n\nfrom hypothesis import HealthCheck, assume, given, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument, ResolutionFailed, SmallSearchSpaceWarning\nfrom hypothesis.internal.compat import get_type_hints\nfrom hypothesis.internal.conjecture.junkdrawer import stack_depth_of_caller\nfrom hypothesis.internal.reflection import get_pretty_function_description\nfrom hypothesis.strategies import from_type\nfrom hypothesis.strategies._internal import types\n\nfrom tests.common.debug import (\n    assert_all_examples,\n    assert_no_examples,\n    assert_simple_property,\n    check_can_generate_examples,\n    find_any,\n    minimal,\n)\nfrom tests.common.utils import fails_with, temp_registered\n\n# we'll continue testing the typing variants until their removal from the stdlib\n# ruff: noqa: UP006, UP035, UP045, UP007\n\nsentinel = object()\nBUILTIN_TYPES = tuple(\n    v\n    for v in vars(builtins).values()\n    if isinstance(v, type) and v.__name__ != \"BuiltinImporter\"\n)\ngenerics = sorted(\n    (\n        t\n        for t in types._global_type_lookup\n        # We ignore TypeVar, because it is not a Generic type:\n        if isinstance(t, types.typing_root_type)\n        and t != typing.TypeVar\n        and (\n            sys.version_info[:2] <= (3, 11)\n            or t != getattr(typing, \"ByteString\", object())\n        )\n    ),\n    key=str,\n)\n\n\n@pytest.mark.parametrize(\"typ\", generics, ids=repr)\n@settings(\n    suppress_health_check=[HealthCheck.too_slow, HealthCheck.filter_too_much],\n    database=None,\n)\n@given(data=st.data())\ndef test_resolve_typing_module(data, typ):\n    ex = data.draw(from_type(typ))\n\n    if typ in (typing.BinaryIO, typing.TextIO):\n        assert isinstance(ex, io.IOBase)\n    elif isinstance(typ, typing._ProtocolMeta):\n        pass\n    elif (typing.get_origin(typ) or typ) is type and not isinstance(type, type):\n        assert ex is type or isinstance(ex, typing.TypeVar)\n    else:\n        assert isinstance(ex, typ)\n\n\n@pytest.mark.parametrize(\"typ\", [typing.Any, typing.Union])\ndef test_does_not_resolve_special_cases(typ):\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(from_type(typ))\n\n\n@pytest.mark.parametrize(\n    \"typ,instance_of\",\n    [\n        (typing.Union[int, str], (int, str)),\n        (int | str, (int, str)),\n        (typing.Optional[int], (int, type(None))),\n        (int | None, (int, type(None))),\n    ],\n)\n@given(data=st.data())\ndef test_specialised_scalar_types(data, typ, instance_of):\n    ex = data.draw(from_type(typ))\n    assert isinstance(ex, instance_of)\n\n\ndef test_typing_Type_int():\n    for t in (type[int], type[\"int\"], _Type[int], _Type[\"int\"]):\n        assert_simple_property(from_type(t), lambda x: x is int)\n\n\n@given(from_type(type[str | list]) | from_type(_Type[str | list]))\ndef test_typing_Type_Union(ex):\n    assert ex in (str, list)\n\n\n@pytest.mark.parametrize(\n    \"typ\",\n    [\n        pytest.param(\n            getattr(collections.abc, \"ByteString\", ...),\n            marks=pytest.mark.skipif(sys.version_info[:2] >= (3, 14), reason=\"removed\"),\n        ),\n        typing.Match,\n        typing.Pattern,\n        re.Match,\n        re.Pattern,\n    ],\n    ids=repr,\n)\n@given(data=st.data())\ndef test_rare_types(data, typ):\n    ex = data.draw(from_type(typ))\n    with warnings.catch_warnings():\n        if sys.version_info[:2] >= (3, 12):\n            warnings.simplefilter(\"ignore\", DeprecationWarning)\n        # ByteString is deprecated in Python 3.12\n        assert isinstance(ex, typ)\n\n\nclass Elem:\n    pass\n\n\n@pytest.mark.parametrize(\n    \"typ,coll_type\",\n    [\n        (_Set[Elem], set),\n        (_FrozenSet[Elem], frozenset),\n        (_Dict[Elem, None], dict),\n        (set[Elem], set),\n        (frozenset[Elem], frozenset),\n        # (dict[Elem, None], dict),  # FIXME this should work\n        (typing.DefaultDict[Elem, None], collections.defaultdict),\n        (typing.KeysView[Elem], type({}.keys())),\n        (typing.ValuesView[Elem], type({}.values())),\n        (_List[Elem], list),\n        (_Tuple[Elem], tuple),\n        (_Tuple[Elem, ...], tuple),\n        (list[Elem], list),\n        (tuple[Elem], tuple),\n        (tuple[Elem, ...], tuple),\n        (typing.Iterator[Elem], typing.Iterator),\n        (typing.Sequence[Elem], typing.Sequence),\n        (typing.Iterable[Elem], typing.Iterable),\n        (typing.Mapping[Elem, None], typing.Mapping),\n        (typing.Container[Elem], typing.Container),\n        (typing.NamedTuple(\"A_NamedTuple\", ((\"elem\", Elem),)), tuple),\n        (typing.Counter[Elem], typing.Counter),\n        (typing.Deque[Elem], typing.Deque),\n    ],\n    ids=repr,\n)\n@given(data=st.data())\ndef test_specialised_collection_types(data, typ, coll_type):\n    ex = data.draw(from_type(typ))\n    assert isinstance(ex, coll_type)\n    instances = [isinstance(elem, Elem) for elem in ex]\n    assert all(instances)\n    assume(instances)  # non-empty collections without calling len(iterator)\n\n\nclass ElemValue:\n    pass\n\n\n@pytest.mark.parametrize(\n    \"typ,coll_type\",\n    [\n        (typing.ChainMap[Elem, ElemValue], typing.ChainMap),\n        (typing.DefaultDict[Elem, ElemValue], typing.DefaultDict),\n        (typing.OrderedDict[Elem, ElemValue], typing.OrderedDict),\n    ],\n    ids=repr,\n)\n@given(data=st.data())\ndef test_specialised_mapping_types(data, typ, coll_type):\n    ex = data.draw(from_type(typ).filter(len))\n    assert isinstance(ex, coll_type)\n    instances = [isinstance(elem, Elem) for elem in ex]\n    assert all(instances)\n    assert all(isinstance(elem, ElemValue) for elem in ex.values())\n\n\n@given(from_type(typing.ItemsView[Elem, Elem]).filter(len))\ndef test_ItemsView(ex):\n    # See https://github.com/python/typing/issues/177\n    assert isinstance(ex, type({}.items()))\n    assert all(isinstance(elem, tuple) and len(elem) == 2 for elem in ex)\n    assert all(all(isinstance(e, Elem) for e in elem) for elem in ex)\n\n\n@pytest.mark.parametrize(\"generic\", [typing.Match, typing.Pattern])\n@pytest.mark.parametrize(\"typ\", [bytes, str])\n@given(data=st.data())\ndef test_regex_types(data, generic, typ):\n    x = data.draw(from_type(generic[typ]))\n    assert isinstance(x[0] if generic is typing.Match else x.pattern, typ)\n\n\n@given(x=...)\ndef test_Generator(x: typing.Generator[Elem, None, ElemValue]):\n    assert isinstance(x, typing.Generator)\n    try:\n        while True:\n            e = next(x)\n            assert isinstance(e, Elem)\n            x.send(None)  # The generators we create don't check the send type\n    except StopIteration as stop:\n        assert isinstance(stop.value, ElemValue)\n\n\ndef test_Optional_minimises_to_None():\n    assert minimal(from_type(typing.Optional[int]), lambda ex: True) is None\n\n\n@pytest.mark.parametrize(\"n\", [0, 1, 5])\n@pytest.mark.parametrize(\"t\", [tuple, _Tuple])\ndef test_variable_length_tuples(t, n):\n    type_ = t[int, ...]\n    check_can_generate_examples(from_type(type_).filter(lambda ex: len(ex) == n))\n\n\ndef test_lookup_overrides_defaults():\n    sentinel = object()\n    with temp_registered(int, st.just(sentinel)):\n\n        @given(from_type(list[int]))\n        def inner_1(ex):\n            assert all(elem is sentinel for elem in ex)\n\n        inner_1()\n\n    @given(from_type(list[int]))\n    def inner_2(ex):\n        assert all(isinstance(elem, int) for elem in ex)\n\n    inner_2()\n\n\ndef test_register_generic_typing_strats():\n    # I don't expect anyone to do this, but good to check it works as expected\n    with temp_registered(\n        typing.Sequence,\n        types._global_type_lookup[set],\n    ):\n        # We register sets for the abstract sequence type, which masks subtypes\n        # from supertype resolution but not direct resolution\n        assert_all_examples(\n            from_type(typing.Sequence[int]), lambda ex: isinstance(ex, set)\n        )\n        assert_all_examples(\n            from_type(typing.Container[int]),\n            lambda ex: not isinstance(ex, typing.Sequence),\n        )\n        assert_all_examples(from_type(list[int]), lambda ex: isinstance(ex, list))\n\n\ndef if_available(name):\n    try:\n        return getattr(typing, name)\n    except AttributeError:\n        return pytest.param(name, marks=[pytest.mark.skip])\n\n\n@pytest.mark.parametrize(\n    \"typ\",\n    [\n        typing.Sequence,\n        typing.Container,\n        typing.Mapping,\n        typing.Reversible,\n        typing.SupportsBytes,\n        typing.SupportsAbs,\n        typing.SupportsComplex,\n        typing.SupportsFloat,\n        typing.SupportsInt,\n        typing.SupportsRound,\n        if_available(\"SupportsIndex\"),\n    ],\n    ids=get_pretty_function_description,\n)\ndef test_resolves_weird_types(typ):\n    check_can_generate_examples(from_type(typ))\n\n\nclass Foo:\n    def __init__(self, x):\n        pass\n\n\nclass Bar(Foo):\n    pass\n\n\nclass Baz(Foo):\n    pass\n\n\nst.register_type_strategy(Bar, st.builds(Bar, st.integers()))\nst.register_type_strategy(Baz, st.builds(Baz, st.integers()))\n\n\n@pytest.mark.parametrize(\n    \"var,expected\",\n    [\n        (typing.TypeVar(\"V\"), object),\n        (typing.TypeVar(\"V\", bound=int), int),\n        (typing.TypeVar(\"V\", bound=Foo), (Bar, Baz)),\n        (typing.TypeVar(\"V\", bound=int | str), (int, str)),\n        (typing.TypeVar(\"V\", int, str), (int, str)),\n    ],\n)\n@settings(suppress_health_check=[HealthCheck.too_slow])\n@given(data=st.data())\ndef test_typevar_type_is_consistent(data, var, expected):\n    strat = st.from_type(var)\n    v1 = data.draw(strat)\n    v2 = data.draw(strat)\n    assume(v1 != v2)  # Values may vary, just not types\n    assert type(v1) == type(v2)\n    assert isinstance(v1, expected)\n\n\ndef test_distinct_typevars_same_constraint():\n    A = typing.TypeVar(\"A\", int, str)\n    B = typing.TypeVar(\"B\", int, str)\n    find_any(\n        st.tuples(st.from_type(A), st.from_type(B)),\n        lambda ab: type(ab[0]) != type(ab[1]),\n    )\n\n\ndef test_distinct_typevars_distinct_type():\n    \"\"\"Ensures that two different type vars have at least one different type in their strategies.\"\"\"\n    A = typing.TypeVar(\"A\")\n    B = typing.TypeVar(\"B\")\n    find_any(\n        st.tuples(st.from_type(A), st.from_type(B)),\n        lambda ab: type(ab[0]) != type(ab[1]),\n    )\n\n\nA = typing.TypeVar(\"A\")\n\n\ndef same_type_args(a: A, b: A):\n    assert type(a) == type(b)\n\n\n@given(st.builds(same_type_args))\ndef test_same_typevars_same_type(_):\n    \"\"\"Ensures that single type argument will always have the same type in a single context.\"\"\"\n\n\ndef test_typevars_can_be_redefined():\n    \"\"\"We test that one can register a custom strategy for all type vars.\"\"\"\n    A = typing.TypeVar(\"A\")\n\n    with temp_registered(typing.TypeVar, st.just(1)):\n        assert_all_examples(st.from_type(A), lambda obj: obj == 1)\n\n\ndef test_typevars_can_be_redefine_with_factory():\n    \"\"\"We test that one can register a custom strategy for all type vars.\"\"\"\n    A = typing.TypeVar(\"A\")\n\n    with temp_registered(typing.TypeVar, lambda thing: st.just(thing.__name__)):\n        assert_all_examples(st.from_type(A), lambda obj: obj == \"A\")\n\n\ndef test_typevars_can_be_resolved_conditionally():\n    sentinel = object()\n    A = typing.TypeVar(\"A\")\n    B = typing.TypeVar(\"B\")\n\n    def resolve_type_var(thing):\n        assert thing in (A, B)\n        if thing == A:\n            return st.just(sentinel)\n        return NotImplemented\n\n    with temp_registered(typing.TypeVar, resolve_type_var):\n        assert_simple_property(st.from_type(A), lambda x: x is sentinel)\n        # We've re-defined the default TypeVar resolver, so there is no fallback.\n        # This causes the lookup to fail.\n        with pytest.raises(InvalidArgument):\n            check_can_generate_examples(st.from_type(B))\n\n\ndef annotated_func(a: int, b: int = 2, *, c: int, d: int = 4):\n    return a + b + c + d\n\n\ndef test_issue_946_regression():\n    # Turned type hints into kwargs even if the required posarg was passed\n    check_can_generate_examples(st.builds(annotated_func, st.integers()))\n\n\n@pytest.mark.parametrize(\n    \"thing\",\n    [\n        annotated_func,  # Works via typing.get_type_hints\n        typing.NamedTuple(\"N\", [(\"a\", int)]),  # Falls back to inspection\n        int,  # Fails; returns empty dict\n    ],\n)\ndef test_can_get_type_hints(thing):\n    assert isinstance(get_type_hints(thing), dict)\n\n\ndef test_force_builds_to_infer_strategies_for_default_args():\n    # By default, leaves args with defaults and minimises to 2+4=6\n    assert minimal(st.builds(annotated_func), lambda ex: True) == 6\n    # Inferring integers() for args makes it minimise to zero\n    assert minimal(st.builds(annotated_func, b=..., d=...), lambda ex: True) == 0\n\n\ndef non_annotated_func(a, b=2, *, c, d=4):\n    pass\n\n\ndef test_cannot_pass_infer_as_posarg():\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(st.builds(annotated_func, ...))\n\n\ndef test_cannot_force_inference_for_unannotated_arg():\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(st.builds(non_annotated_func, a=..., c=st.none()))\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(st.builds(non_annotated_func, a=st.none(), c=...))\n\n\nclass UnknownType:\n    def __init__(self, arg):\n        pass\n\n\nclass UnknownAnnotatedType:\n    def __init__(self, arg: int):\n        pass\n\n\n@given(st.from_type(UnknownAnnotatedType))\ndef test_builds_for_unknown_annotated_type(ex):\n    assert isinstance(ex, UnknownAnnotatedType)\n\n\ndef unknown_annotated_func(a: UnknownType, b=2, *, c: UnknownType, d=4):\n    pass\n\n\ndef test_raises_for_arg_with_unresolvable_annotation():\n    with pytest.raises(ResolutionFailed):\n        check_can_generate_examples(st.builds(unknown_annotated_func))\n    with pytest.raises(ResolutionFailed):\n        check_can_generate_examples(\n            st.builds(unknown_annotated_func, a=st.none(), c=...)\n        )\n\n\n@given(a=..., b=...)\ndef test_can_use_type_hints(a: int, b: float):\n    assert isinstance(a, int)\n    assert isinstance(b, float)\n\n\ndef test_error_if_has_unresolvable_hints():\n    @given(a=...)\n    def inner(a: UnknownType):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        inner()\n\n\ndef test_resolves_NewType():\n    typ = typing.NewType(\"T\", int)\n    nested = typing.NewType(\"NestedT\", typ)\n    uni = typing.NewType(\"UnionT\", int | None)\n    assert_simple_property(from_type(typ), lambda x: isinstance(x, int))\n    assert_simple_property(from_type(nested), lambda x: isinstance(x, int))\n    assert_simple_property(from_type(uni), lambda x: isinstance(x, (int, type(None))))\n    find_any(from_type(uni), lambda x: isinstance(x, int))\n    find_any(from_type(uni), lambda x: isinstance(x, type(None)))\n\n\n@pytest.mark.parametrize(\"is_handled\", [True, False])\ndef test_resolves_NewType_conditionally(is_handled):\n    sentinel = object()\n    typ = typing.NewType(\"T\", int)\n\n    def resolve_custom_strategy(thing):\n        assert thing is typ\n        if is_handled:\n            return st.just(sentinel)\n        return NotImplemented\n\n    with temp_registered(typ, resolve_custom_strategy):\n        if is_handled:\n            assert_simple_property(st.from_type(typ), lambda x: x is sentinel)\n        else:\n            assert_simple_property(st.from_type(typ), lambda x: isinstance(x, int))\n\n\nE = enum.Enum(\"E\", \"a b c\")\n\n\n@given(from_type(E))\ndef test_resolves_enum(ex):\n    assert isinstance(ex, E)\n\n\n@pytest.mark.parametrize(\"resolver\", [from_type, st.sampled_from])\ndef test_resolves_flag_enum(resolver):\n    # Storing all combinations takes O(2^n) memory.  Using an enum of 52\n    # members in this test ensures that we won't try!\n    F = enum.Flag(\"F\", \" \".join(string.ascii_letters))\n\n    # Checks for combination coverage are found in nocover/test_sampled_from\n    @given(resolver(F))\n    def inner(ex):\n        assert isinstance(ex, F)\n\n    inner()\n\n\nclass AnnotatedTarget:\n    def __init__(self, a: int, b: int):\n        pass\n\n    def method(self, a: int, b: int):\n        pass\n\n\n@pytest.mark.parametrize(\"target\", [AnnotatedTarget, AnnotatedTarget(1, 2).method])\n@pytest.mark.parametrize(\n    \"args,kwargs\",\n    [\n        ((), {}),\n        ((1,), {}),\n        ((1, 2), {}),\n        ((), {\"a\": 1}),\n        ((), {\"b\": 2}),\n        ((), {\"a\": 1, \"b\": 2}),\n    ],\n)\ndef test_required_args(target, args, kwargs):\n    # Mostly checking that `self` (and only self) is correctly excluded\n    check_can_generate_examples(\n        st.builds(\n            target, *map(st.just, args), **{k: st.just(v) for k, v in kwargs.items()}\n        )\n    )\n\n\nclass AnnotatedNamedTuple(typing.NamedTuple):\n    a: str\n\n\n@given(st.builds(AnnotatedNamedTuple))\ndef test_infers_args_for_namedtuple_builds(thing):\n    assert isinstance(thing.a, str)\n\n\n@given(st.from_type(AnnotatedNamedTuple))\ndef test_infers_args_for_namedtuple_from_type(thing):\n    assert isinstance(thing.a, str)\n\n\n@given(st.builds(AnnotatedNamedTuple, a=st.none()))\ndef test_override_args_for_namedtuple(thing):\n    assert thing.a is None\n\n\n@pytest.mark.parametrize(\"thing\", [typing.Optional, list, type, _List, _Type])\ndef test_cannot_resolve_bare_forward_reference(thing):\n    t = thing[\"ConcreteFoo\"]\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(st.from_type(t))\n\n\nclass Tree:\n    def __init__(self, left: typing.Optional[\"Tree\"], right: typing.Optional[\"Tree\"]):\n        self.left = left\n        self.right = right\n\n    def __repr__(self):\n        return f\"Tree({self.left}, {self.right})\"\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"takes ~19 mins; datastructure explosion https://github.com/pschanely/hypothesis-crosshair/issues/27\",\n)\n@given(tree=st.builds(Tree))\ndef test_resolving_recursive_type(tree):\n    assert isinstance(tree, Tree)\n\n\nclass TypedTree(typing.TypedDict):\n    nxt: typing.Optional[\"TypedTree\"]\n\n\ndef test_resolving_recursive_typeddict():\n    assert_simple_property(\n        st.from_type(TypedTree),\n        lambda tree: isinstance(tree, dict) and len(tree) == 1 and \"nxt\" in tree,\n    )\n\n\nclass MyList:\n    def __init__(self, nxt: typing.Optional[\"MyList\"] = None):\n        self.nxt = nxt\n\n    def __repr__(self):\n        return f\"MyList({self.nxt})\"\n\n    def __eq__(self, other):\n        return type(self) == type(other) and self.nxt == other.nxt\n\n\n@given(lst=st.from_type(MyList))\ndef test_resolving_recursive_type_with_defaults(lst):\n    assert isinstance(lst, MyList)\n\n\ndef test_recursive_type_with_defaults_minimizes_to_defaults():\n    assert minimal(from_type(MyList), lambda ex: True) == MyList()\n\n\nclass MutualA:\n    def __init__(self, nxt: typing.Optional[\"MutualB\"]):\n        self.nxt = nxt\n\n    def __repr__(self):\n        return f\"A({self.nxt})\"\n\n\nclass MutualB:\n    def __init__(self, nxt: typing.Optional[\"MutualA\"]):\n        self.nxt = nxt\n\n    def __repr__(self):\n        return f\"B({self.nxt})\"\n\n\n@given(nxt=st.from_type(MutualA))\ndef test_resolving_mutually_recursive_types(nxt):\n    i = 0\n    while nxt:\n        assert isinstance(nxt, [MutualA, MutualB][i % 2])\n        nxt = nxt.nxt\n        i += 1\n\n\ndef test_resolving_mutually_recursive_types_with_limited_stack():\n    orig_recursionlimit = sys.getrecursionlimit()\n    current_stack_depth = stack_depth_of_caller()\n    sys.setrecursionlimit(current_stack_depth + 100)\n    try:\n\n        @given(nxt=st.from_type(MutualA))\n        def test(nxt):\n            pass\n\n        test()\n    finally:\n        assert sys.getrecursionlimit() == current_stack_depth + 100\n        sys.setrecursionlimit(orig_recursionlimit)\n\n\nclass A_with_default:\n    def __init__(self, nxt: typing.Optional[\"B_with_default\"] = None):\n        self.nxt = nxt\n\n    def __repr__(self):\n        return f\"A_with_default({self.nxt})\"\n\n\nclass B_with_default:\n    def __init__(self, nxt: typing.Optional[\"A_with_default\"] = None):\n        self.nxt = nxt\n\n    def __repr__(self):\n        return f\"B_with_default({self.nxt})\"\n\n\n@given(nxt=st.from_type(A_with_default))\ndef test_resolving_mutually_recursive_types_with_defaults(nxt):\n    # This test is required to cover the raise/except part of the recursion\n    # check in from_type, see\n    # https://github.com/HypothesisWorks/hypothesis/issues/3655. If the\n    # skip-nondefaulted-args check is removed, this test becomes redundant.\n    i = 0\n    while nxt:\n        assert isinstance(nxt, [A_with_default, B_with_default][i % 2])\n        nxt = nxt.nxt\n        i += 1\n\n\nclass SomeClass:\n    def __init__(self, value: int, next_node: typing.Optional[\"SomeClass\"]) -> None:\n        assert value > 0\n        self.value = value\n        self.next_node = next_node\n\n    def __repr__(self) -> str:\n        return f\"SomeClass({self.value}, next_node={self.next_node})\"\n\n\ndef test_resolving_recursive_type_with_registered_constraint():\n    with temp_registered(\n        SomeClass, st.builds(SomeClass, value=st.integers(min_value=1))\n    ):\n\n        @given(s=st.from_type(SomeClass))\n        def test(s):\n            assert isinstance(s, SomeClass)\n\n        test()\n\n\ndef test_resolving_recursive_type_with_registered_constraint_not_none():\n    with temp_registered(\n        SomeClass, st.builds(SomeClass, value=st.integers(min_value=1))\n    ):\n        s = st.from_type(SomeClass)\n        print(s, s.wrapped_strategy)\n        find_any(s, lambda s: s.next_node is not None)\n\n\n@given(from_type(tuple[()]) | from_type(_Tuple[()]))\ndef test_resolves_empty_Tuple_issue_1583_regression(ex):\n    # See e.g. https://github.com/python/mypy/commit/71332d58\n    assert ex == ()\n\n\ndef test_can_register_NewType():\n    Name = typing.NewType(\"Name\", str)\n    st.register_type_strategy(Name, st.just(\"Eric Idle\"))\n    assert_simple_property(st.from_type(Name), lambda x: x == \"Eric Idle\")\n\n\n@given(st.from_type(typing.Callable))\ndef test_resolves_bare_callable_to_function(f):\n    val = f()\n    assert val is None\n    with pytest.raises(TypeError):\n        f(1)\n\n\n@given(st.from_type(typing.Callable[[str], int]))\ndef test_resolves_callable_with_arg_to_function(f):\n    val = f(\"1\")\n    assert isinstance(val, int)\n\n\n@given(st.from_type(typing.Callable[..., int]))\ndef test_resolves_ellipses_callable_to_function(f):\n    val = f()\n    assert isinstance(val, int)\n    f(1)\n    f(1, 2, 3)\n    f(accepts_kwargs_too=1)\n\n\nclass AbstractFoo(abc.ABC):\n    @abc.abstractmethod\n    def foo(self):\n        pass\n\n\nclass ConcreteFoo(AbstractFoo):\n    def foo(self):\n        pass\n\n\n@given(st.from_type(AbstractFoo))\ndef test_can_resolve_abstract_class(instance):\n    assert isinstance(instance, ConcreteFoo)\n    instance.foo()\n\n\nclass AbstractBar(abc.ABC):\n    @abc.abstractmethod\n    def bar(self):\n        pass\n\n\n@fails_with(ResolutionFailed)\n@given(st.from_type(AbstractBar))\ndef test_cannot_resolve_abstract_class_with_no_concrete_subclass(instance):\n    raise AssertionError(\"test body unreachable as strategy cannot resolve\")\n\n\n@fails_with(ResolutionFailed)\n@given(st.from_type(type[\"ConcreteFoo\"]))\ndef test_cannot_resolve_type_with_forwardref(instance):\n    raise AssertionError(\"test body unreachable as strategy cannot resolve\")\n\n\n@fails_with(ResolutionFailed)\n@given(st.from_type(_Type[\"ConcreteFoo\"]))\ndef test_cannot_resolve_type_with_forwardref_old(instance):\n    raise AssertionError(\"test body unreachable as strategy cannot resolve\")\n\n\n@pytest.mark.parametrize(\"typ\", [typing.Hashable, typing.Sized])\n@given(data=st.data())\ndef test_inference_on_generic_collections_abc_aliases(typ, data):\n    # regression test for inference bug on types that are just aliases\n    # types for simple interfaces in collections abc and take no args\n    # the typing module such as Hashable and Sized\n    # see https://github.com/HypothesisWorks/hypothesis/issues/2272\n    value = data.draw(st.from_type(typ))\n    assert isinstance(value, typ)\n\n\n@given(st.from_type(typing.Sequence[set]))\ndef test_bytestring_not_treated_as_generic_sequence(val):\n    # Check that we don't fall into the specific problem from\n    # https://github.com/HypothesisWorks/hypothesis/issues/2257\n    assert not isinstance(val, bytes)\n    # Check it hasn't happened again from some other non-generic sequence type.\n    for x in val:\n        assert isinstance(x, set)\n\n\n@pytest.mark.parametrize(\n    \"type_\", [int, Real, object, typing.Union[int, str], typing.Union[Real, str]]\n)\ndef test_bytestring_is_valid_sequence_of_int_and_parent_classes(type_):\n    find_any(\n        st.from_type(typing.Sequence[type_]),\n        lambda val: isinstance(val, bytes),\n    )\n\n\n@pytest.mark.parametrize(\"protocol\", [typing.SupportsAbs, typing.SupportsRound])\n@given(data=st.data())\ndef test_supportsop_types_support_protocol(protocol, data):\n    # test values drawn from SupportsOp types are indeed considered instances\n    # of that type.\n    value = data.draw(st.from_type(protocol))\n    # check that we aren't somehow generating instances of the protocol itself\n    assert value.__class__ != protocol\n    assert issubclass(type(value), protocol)\n\n\n@pytest.mark.parametrize(\"restrict_custom_strategy\", [True, False])\ndef test_generic_aliases_can_be_conditionally_resolved_by_registered_function(\n    restrict_custom_strategy,\n):\n    # Check that a custom strategy function may provide no strategy for a\n    # generic alias request like Container[T]. We test this under two scenarios:\n    # - where CustomContainer CANNOT be generated from requests for Container[T]\n    #   (only for requests for exactly CustomContainer[T])\n    # - where CustomContainer CAN be generated from requests for Container[T]\n    T = typing.TypeVar(\"T\")\n\n    @dataclass\n    class CustomContainer(typing.Container[T]):\n        content: T\n\n        def __contains__(self, value: object) -> bool:\n            return self.content == value\n\n    def get_custom_container_strategy(thing):\n        if restrict_custom_strategy and typing.get_origin(thing) != CustomContainer:\n            return NotImplemented\n        return st.builds(\n            CustomContainer, content=st.from_type(typing.get_args(thing)[0])\n        )\n\n    with temp_registered(CustomContainer, get_custom_container_strategy):\n\n        def is_custom_container_with_str(example):\n            return isinstance(example, CustomContainer) and isinstance(\n                example.content, str\n            )\n\n        def is_non_custom_container(example):\n            return isinstance(example, typing.Container) and not isinstance(\n                example, CustomContainer\n            )\n\n        assert_all_examples(\n            st.from_type(CustomContainer[str]), is_custom_container_with_str\n        )\n        # If the strategy function is restricting, it doesn't return a strategy\n        # for requests for Container[...], so it's never generated. When not\n        # restricting, it is generated.\n        if restrict_custom_strategy:\n            assert_all_examples(\n                st.from_type(typing.Container[str]), is_non_custom_container\n            )\n        else:\n            find_any(st.from_type(typing.Container[str]), is_custom_container_with_str)\n            find_any(st.from_type(typing.Container[str]), is_non_custom_container)\n\n\n@pytest.mark.parametrize(\n    \"protocol, typ\",\n    [\n        (typing.SupportsFloat, float),\n        (typing.SupportsInt, int),\n        (typing.SupportsBytes, bytes),\n        (typing.SupportsComplex, complex),\n    ],\n)\n@given(data=st.data())\ndef test_supportscast_types_support_protocol_or_are_castable(protocol, typ, data):\n    value = data.draw(st.from_type(protocol))\n    # check that we aren't somehow generating instances of the protocol itself\n    assert value.__class__ != protocol\n    # test values drawn from the protocol types either support the protocol\n    # or can be cast to typ\n    assert issubclass(type(value), protocol) or types.can_cast(typ, value)\n\n\ndef test_can_cast():\n    assert types.can_cast(int, \"0\")\n    assert not types.can_cast(int, \"abc\")\n\n\n@pytest.mark.parametrize(\"type_\", [datetime.timezone, datetime.tzinfo])\ndef test_timezone_lookup(type_):\n    assert issubclass(type_, datetime.tzinfo)\n    assert_all_examples(st.from_type(type_), lambda t: isinstance(t, type_))\n\n\n@pytest.mark.parametrize(\n    \"typ\",\n    [\n        _Set[typing.Hashable],\n        _FrozenSet[typing.Hashable],\n        _Dict[typing.Hashable, int],\n        set[typing.Hashable],\n        frozenset[typing.Hashable],\n        dict[typing.Hashable, int],\n    ],\n)\n@settings(suppress_health_check=[HealthCheck.data_too_large])\n@given(data=st.data())\ndef test_generic_collections_only_use_hashable_elements(typ, data):\n    data.draw(from_type(typ))\n\n\n@given(st.sets(st.integers() | st.binary(), min_size=2))\ndef test_no_byteswarning(_):\n    pass\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"Crosshair is too much slower at hashing values\",\n)\ndef test_hashable_type_unhashable_value():\n    # Decimal(\"snan\") is not hashable; we should be able to generate it.\n    # See https://github.com/HypothesisWorks/hypothesis/issues/2320\n    find_any(\n        from_type(typing.Hashable),\n        lambda x: not types._can_hash(x),\n        settings(max_examples=10**5),\n    )\n\n\ndef test_unhashable_type():\n    class UnhashableMeta(type):\n        __hash__ = None\n\n    class UnhashableType(metaclass=UnhashableMeta):\n        pass\n\n    assert_simple_property(\n        st.from_type(UnhashableType), lambda x: isinstance(x, UnhashableType)\n    )\n\n\nclass _EmptyClass:\n    def __init__(self, value=-1) -> None:\n        pass\n\n\n@pytest.mark.parametrize(\n    \"typ,repr_\",\n    [\n        (int, \"integers()\"),\n        (list[str], \"lists(text())\"),\n        (_List[str], \"lists(text())\"),\n        (\"not a type\", \"from_type('not a type')\"),\n        (random.Random, \"randoms()\"),\n        (_EmptyClass, \"from_type(tests.cover.test_lookup._EmptyClass)\"),\n        (\n            st.SearchStrategy[str],\n            \"from_type(hypothesis.strategies.SearchStrategy[str])\",\n        ),\n    ],\n)\ndef test_repr_passthrough(typ, repr_):\n    assert repr(st.from_type(typ)) == repr_\n\n\nclass TreeForwardRefs(typing.NamedTuple):\n    val: int\n    l: typing.Optional[\"TreeForwardRefs\"]\n    r: typing.Optional[\"TreeForwardRefs\"]\n\n\n@given(st.builds(TreeForwardRefs))\ndef test_resolves_forward_references_outside_annotations(t):\n    assert isinstance(t, TreeForwardRefs)\n\n\ndef constructor(a: str = None):  # noqa  # deprecated implicit optional, for testing\n    pass\n\n\nclass WithOptionalInSignature:\n    __signature__ = inspect.signature(constructor)\n    __annotations__ = typing.get_type_hints(constructor)\n\n    def __init__(self, **kwargs):\n        assert set(kwargs) == {\"a\"}\n        self.a = kwargs[\"a\"]\n\n\ndef test_compat_get_type_hints_aware_of_None_default():\n    # Regression test for https://github.com/HypothesisWorks/hypothesis/issues/2648\n    strategy = st.builds(WithOptionalInSignature, a=...)\n    find_any(strategy, lambda x: x.a is None)\n    find_any(strategy, lambda x: x.a is not None)\n\n    if sys.version_info[:2] >= (3, 11):\n        # https://docs.python.org/3.11/library/typing.html#typing.get_type_hints\n        assert typing.get_type_hints(constructor)[\"a\"] == str\n    else:\n        assert typing.get_type_hints(constructor)[\"a\"] == typing.Optional[str]\n    assert inspect.signature(constructor).parameters[\"a\"].annotation == str\n\n\n_ValueType = typing.TypeVar(\"_ValueType\")\n\n\nclass Wrapper(typing.Generic[_ValueType]):\n    _inner_value: _ValueType\n\n    def __init__(self, inner_value: _ValueType) -> None:\n        self._inner_value = inner_value\n\n\n@given(st.builds(Wrapper))\ndef test_issue_2603_regression(built):\n    \"\"\"It was impossible to build annotated classes with constructors.\"\"\"\n    assert isinstance(built, Wrapper)\n\n\nclass AnnotatedConstructor(typing.Generic[_ValueType]):\n    value: _ValueType  # the same name we have in `__init__`\n\n    def __init__(self, value: int) -> None:\n        \"\"\"By this example we show, that ``int`` is more important than ``_ValueType``.\"\"\"\n        assert isinstance(value, int)\n\n\n@given(st.data())\ndef test_constructor_is_more_important(data):\n    \"\"\"Constructor types should take precedence over all other annotations.\"\"\"\n    data.draw(st.builds(AnnotatedConstructor))\n\n\ndef use_signature(self, value: str) -> None: ...\n\n\nclass AnnotatedConstructorWithSignature(typing.Generic[_ValueType]):\n    value: _ValueType  # the same name we have in `__init__`\n\n    __signature__ = signature(use_signature)\n\n    def __init__(self, value: int) -> None:\n        \"\"\"By this example we show, that ``__signature__`` is the most important source.\"\"\"\n        assert isinstance(value, str)\n\n\ndef selfless_signature(value: str) -> None: ...\n\n\nclass AnnotatedConstructorWithSelflessSignature(AnnotatedConstructorWithSignature):\n    __signature__ = signature(selfless_signature)\n\n\ndef really_takes_str(value: int) -> None:\n    \"\"\"By this example we show, that ``__signature__`` is the most important source.\"\"\"\n    assert isinstance(value, str)\n\n\nreally_takes_str.__signature__ = signature(selfless_signature)\n\n\n@pytest.mark.parametrize(\n    \"thing\",\n    [\n        AnnotatedConstructorWithSignature,\n        AnnotatedConstructorWithSelflessSignature,\n        really_takes_str,\n    ],\n)\ndef test_signature_is_the_most_important_source(thing):\n    \"\"\"Signature types should take precedence over all other annotations.\"\"\"\n    check_can_generate_examples(st.builds(thing))\n\n\nclass AnnotatedAndDefault:\n    def __init__(self, foo: bool | None = None):\n        self.foo = foo\n\n\ndef test_from_type_can_be_default_or_annotation():\n    find_any(st.from_type(AnnotatedAndDefault), lambda x: x.foo is None)\n    find_any(st.from_type(AnnotatedAndDefault), lambda x: isinstance(x.foo, bool))\n\n\n@pytest.mark.parametrize(\"t\", BUILTIN_TYPES, ids=lambda t: t.__name__)\ndef test_resolves_builtin_types(t):\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", SmallSearchSpaceWarning)\n        assert_simple_property(st.from_type(t), lambda v: isinstance(v, t))\n\n\n@pytest.mark.parametrize(\"t\", BUILTIN_TYPES, ids=lambda t: t.__name__)\n@given(data=st.data())\n@settings(max_examples=20)\ndef test_resolves_forwardrefs_to_builtin_types(t, data):\n    if t.__name__ == \"object\" and settings.get_current_profile_name() == \"threading\":\n        # from_type(ForwardRef(\"object\")) pulls from register_type_strategy,\n        # and depending on threading I've seen `st.builds(Bar, st.integers())`\n        # (from this file) be registered in one iteration and not the next,\n        # causing Hypothesis to raise FlakyStrategyDefinition.\n        #\n        # (I would also expect st.from_type(object) to have this problem, but\n        # I haven't seen that error under threading, yet).\n        pytest.skip(\"ForwardRef('object') is inherently flaky under concurrency\")\n    s = st.from_type(typing.ForwardRef(t.__name__))\n    v = data.draw(s)\n    assert isinstance(v, t)\n\n\n@pytest.mark.parametrize(\"t\", BUILTIN_TYPES, ids=lambda t: t.__name__)\ndef test_resolves_type_of_builtin_types(t):\n    assert_simple_property(st.from_type(type[t.__name__]), lambda v: v is t)\n\n\n@given(\n    st.from_type(type[typing.Union[\"str\", \"int\"]])\n    | st.from_type(_Type[typing.Union[\"str\", \"int\"]])\n)\ndef test_resolves_type_of_union_of_forwardrefs_to_builtins(x):\n    assert x in (str, int)\n\n\n@pytest.mark.parametrize(\n    \"type_\",\n    [\n        # Old-style `List` because `list[int]() == list()`, so no need for the hint.\n        getattr(typing, \"List\", None)[int],\n        pytest.param(\n            typing.Optional[int],\n            marks=pytest.mark.skipif(\n                sys.version_info >= (3, 14), reason=\"different error on 3.14+\"\n            ),\n        ),\n    ],\n)\ndef test_builds_suggests_from_type(type_):\n    with pytest.raises(\n        InvalidArgument, match=re.escape(f\"try using from_type({type_!r})\")\n    ):\n        check_can_generate_examples(st.builds(type_))\n\n    try:\n        check_can_generate_examples(st.builds(type_, st.just(\"has an argument\")))\n        raise AssertionError(\"Expected strategy to raise an error\")\n    except TypeError as err:\n        assert not isinstance(err, InvalidArgument)\n\n\n@pytest.mark.skipif(sys.version_info < (3, 14), reason=\"different error on 3.14+\")\n@pytest.mark.parametrize(\"type_\", [typing.Optional[int]])\ndef test_builds_suggests_from_type_on_construction(type_):\n    with pytest.raises(\n        InvalidArgument, match=re.escape(f\"Try using from_type({type_!r})\")\n    ):\n        check_can_generate_examples(st.builds(type_))\n\n    with pytest.raises(\n        InvalidArgument, match=re.escape(f\"Try using from_type({type_!r})\")\n    ):\n        check_can_generate_examples(st.builds(type_, st.just(\"has an argument\")))\n\n\ndef test_builds_mentions_no_type_check():\n    @typing.no_type_check\n    def f(x: int):\n        pass\n\n    msg = \"@no_type_check decorator prevented Hypothesis from inferring a strategy\"\n    with pytest.raises(TypeError, match=msg):\n        check_can_generate_examples(st.builds(f))\n\n\nclass TupleSubtype(tuple):\n    pass\n\n\ndef test_tuple_subclasses_not_generic_sequences():\n    # see https://github.com/HypothesisWorks/hypothesis/issues/3767.\n    with temp_registered(TupleSubtype, st.builds(TupleSubtype)):\n        s = st.from_type(typing.Sequence[int])\n        assert_no_examples(s, lambda x: isinstance(x, tuple))\n\n\ndef test_custom_strategy_function_resolves_types_conditionally():\n    sentinel = object()\n\n    class A:\n        pass\n\n    class B(A):\n        pass\n\n    class C(A):\n        pass\n\n    def resolve_custom_strategy_for_b(thing):\n        if thing == B:\n            return st.just(sentinel)\n        return NotImplemented\n\n    with contextlib.ExitStack() as stack:\n        stack.enter_context(temp_registered(B, resolve_custom_strategy_for_b))\n        stack.enter_context(temp_registered(C, st.builds(C)))\n\n        # C's strategy can be used for A, but B's cannot because its function\n        # only returns a strategy for requests for exactly B.\n        assert_all_examples(st.from_type(A), lambda example: type(example) == C)\n        assert_all_examples(st.from_type(B), lambda example: example is sentinel)\n        assert_all_examples(st.from_type(C), lambda example: type(example) == C)\n\n\nclass CustomInteger(int):\n    def __init__(self, value: int, /) -> None:\n        if not isinstance(value, int):\n            raise TypeError\n\n\n@given(...)\ndef test_from_type_resolves_required_posonly_args(n: CustomInteger):\n    # st.builds() does not infer for positional arguments, but st.from_type()\n    # does.  See e.g. https://stackoverflow.com/q/79199376/ for motivation.\n    assert isinstance(n, CustomInteger)\n\n\nclass MyProtocol(typing.Protocol):\n    pass\n\n\ndef test_issue_4194_regression():\n    # this was an edge case where we were calling issubclass on something\n    # that was not a type, which errored. I don't have a more principled test\n    # case or name for this.\n    inner = typing.Union[typing.Sequence[\"A\"], MyProtocol]\n    A = typing.Union[typing.Sequence[inner], MyProtocol]\n\n    with (\n        temp_registered(MyProtocol, st.just(b\"\")),\n        temp_registered(typing.ForwardRef(\"A\"), st.integers()),\n    ):\n        find_any(st.from_type(A))\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_lookup_py310.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import strategies as st\n\nfrom tests.common.debug import find_any\n\n\ndef test_native_unions():\n    s = st.from_type(int | list[str])\n    find_any(s, lambda x: isinstance(x, int))\n    find_any(s, lambda x: isinstance(x, list))\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_lookup_py314.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections.abc import Buffer\nfrom dataclasses import dataclass\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\n\nfrom tests.common.debug import find_any\n\n\n@dataclass\nclass A:\n    constant = 42\n    x: int\n\n    # see https://docs.python.org/3/reference/datamodel.html#python-buffer-protocol\n    # and https://peps.python.org/pep-0688/\n    def __buffer__(self, flags):\n        return memoryview(\n            self.constant.to_bytes() + self.x.to_bytes(length=32, signed=True)\n        )\n\n\n@given(st.from_type(memoryview[A]))\ndef test_resolve_bufferlike_memoryview(v):\n    assert isinstance(v, memoryview)\n    assert v[0] == A.constant\n    assert len(v) == 1 + 32\n\n\ndef test_errors_when___buffer___not_implemented():\n    class NoBuffer:\n        pass\n\n    @given(st.from_type(memoryview[NoBuffer]))\n    def f(v):\n        pass\n\n    with pytest.raises(\n        TypeError, match=\"a bytes-like object is required, not 'NoBuffer'\"\n    ):\n        f()\n\n\ndef test_resolve_Buffer():\n    s = st.from_type(Buffer)\n    # on 3.12, we can generate neither. On 3.13, we can generate bytearray, because\n    # the removal of ByteString stops blocking bytearray from being the maximal\n    # registered type. On 3.14, we can generate both, because memoryview becomes\n    # generic.\n    find_any(s, lambda v: isinstance(v, memoryview))\n    find_any(s, lambda v: isinstance(v, bytearray))\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_lookup_py37.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport collections\nimport collections.abc\nimport contextlib\nimport re\n\nimport pytest\n\nfrom hypothesis import assume, given\n\n\nclass Elem:\n    pass\n\n\nclass Value:\n    pass\n\n\ndef check(t, ex):\n    assert isinstance(ex, t)\n    assert all(isinstance(e, Elem) for e in ex)\n    assume(ex)\n\n\n@given(...)\ndef test_resolving_standard_tuple1_as_generic(x: tuple[Elem]):\n    check(tuple, x)\n\n\n@given(...)\ndef test_resolving_standard_tuple2_as_generic(x: tuple[Elem, Elem]):\n    check(tuple, x)\n\n\n@given(...)\ndef test_resolving_standard_tuple_variadic_as_generic(x: tuple[Elem, ...]):\n    check(tuple, x)\n\n\n@given(...)\ndef test_resolving_standard_list_as_generic(x: list[Elem]):\n    check(list, x)\n\n\n@given(...)\ndef test_resolving_standard_dict_as_generic(x: dict[Elem, Value]):\n    check(dict, x)\n    assert all(isinstance(e, Value) for e in x.values())\n\n\n@given(...)\ndef test_resolving_standard_set_as_generic(x: set[Elem]):\n    check(set, x)\n\n\n@given(...)\ndef test_resolving_standard_frozenset_as_generic(x: frozenset[Elem]):\n    check(frozenset, x)\n\n\n@given(...)\ndef test_resolving_standard_deque_as_generic(x: collections.deque[Elem]):\n    check(collections.deque, x)\n\n\n@given(...)\ndef test_resolving_standard_defaultdict_as_generic(\n    x: collections.defaultdict[Elem, Value],\n):\n    check(collections.defaultdict, x)\n    assert all(isinstance(e, Value) for e in x.values())\n\n\n@given(...)\ndef test_resolving_standard_ordered_dict_as_generic(\n    x: collections.OrderedDict[Elem, Value],\n):\n    check(collections.OrderedDict, x)\n    assert all(isinstance(e, Value) for e in x.values())\n\n\n@given(...)\ndef test_resolving_standard_counter_as_generic(x: collections.Counter[Elem]):\n    check(collections.Counter, x)\n    assume(any(x.values()))  # Check that we generated at least one nonzero count\n\n\n@given(...)\ndef test_resolving_standard_chainmap_as_generic(x: collections.ChainMap[Elem, Value]):\n    check(collections.ChainMap, x)\n    assert all(isinstance(e, Value) for e in x.values())\n\n\n@given(...)\ndef test_resolving_standard_iterable_as_generic(x: collections.abc.Iterable[Elem]):\n    check(collections.abc.Iterable, x)\n\n\n@given(...)\ndef test_resolving_standard_iterator_as_generic(x: collections.abc.Iterator[Elem]):\n    check(collections.abc.Iterator, x)\n\n\n@given(...)\ndef test_resolving_standard_generator_as_generic(\n    x: collections.abc.Generator[Elem, None, Value],\n):\n    assert isinstance(x, collections.abc.Generator)\n    try:\n        while True:\n            e = next(x)\n            assert isinstance(e, Elem)\n            x.send(None)  # The generators we create don't check the send type\n    except StopIteration as stop:\n        assert isinstance(stop.value, Value)\n\n\n@given(...)\ndef test_resolving_standard_reversible_as_generic(x: collections.abc.Reversible[Elem]):\n    check(collections.abc.Reversible, x)\n\n\n@given(...)\ndef test_resolving_standard_container_as_generic(x: collections.abc.Container[Elem]):\n    check(collections.abc.Container, x)\n\n\n@given(...)\ndef test_resolving_standard_collection_as_generic(x: collections.abc.Collection[Elem]):\n    check(collections.abc.Collection, x)\n\n\n@given(...)\ndef test_resolving_standard_callable_ellipsis(x: collections.abc.Callable[..., Elem]):\n    assert isinstance(x, collections.abc.Callable)\n    assert callable(x)\n    # ... implies *args, **kwargs; as would any argument types\n    assert isinstance(x(), Elem)\n    assert isinstance(x(1, 2, 3, a=4, b=5, c=6), Elem)\n\n\n@given(...)\ndef test_resolving_standard_callable_no_args(x: collections.abc.Callable[[], Elem]):\n    assert isinstance(x, collections.abc.Callable)\n    assert callable(x)\n    # [] implies that no arguments are accepted\n    assert isinstance(x(), Elem)\n    with pytest.raises(TypeError):\n        x(1)\n    with pytest.raises(TypeError):\n        x(a=1)\n\n\n@given(...)\ndef test_resolving_standard_collections_set_as_generic(x: collections.abc.Set[Elem]):\n    check(collections.abc.Set, x)\n\n\n@given(...)\ndef test_resolving_standard_collections_mutableset_as_generic(\n    x: collections.abc.MutableSet[Elem],\n):\n    check(collections.abc.MutableSet, x)\n\n\n@given(...)\ndef test_resolving_standard_mapping_as_generic(x: collections.abc.Mapping[Elem, Value]):\n    check(collections.abc.Mapping, x)\n    assert all(isinstance(e, Value) for e in x.values())\n\n\n@given(...)\ndef test_resolving_standard_mutable_mapping_as_generic(\n    x: collections.abc.MutableMapping[Elem, Value],\n):\n    check(collections.abc.MutableMapping, x)\n    assert all(isinstance(e, Value) for e in x.values())\n\n\n@given(...)\ndef test_resolving_standard_sequence_as_generic(x: collections.abc.Sequence[Elem]):\n    check(collections.abc.Sequence, x)\n\n\n@given(...)\ndef test_resolving_standard_mutable_sequence_as_generic(\n    x: collections.abc.MutableSequence[Elem],\n):\n    check(collections.abc.MutableSequence, x)\n\n\n@given(...)\ndef test_resolving_standard_keysview_as_generic(x: collections.abc.KeysView[Elem]):\n    check(collections.abc.KeysView, x)\n\n\n@given(...)\ndef test_resolving_standard_itemsview_as_generic(\n    x: collections.abc.ItemsView[Elem, Value],\n):\n    assert isinstance(x, collections.abc.ItemsView)\n    assert all(isinstance(e, Elem) and isinstance(v, Value) for e, v in x)\n    assume(x)\n\n\n@given(...)\ndef test_resolving_standard_valuesview_as_generic(x: collections.abc.ValuesView[Elem]):\n    check(collections.abc.ValuesView, x)\n\n\n# Weird interaction with fixes in PR #2952\n#\n# 2025-08-11: this gets even weirder with 3.14, where memoryview is in fact a\n# context manager, and so gets resolved for AbstractContextManager[Elem] here.\n# (But then errors during generation, because Elem does not implement __buffer__).\n@pytest.mark.xfail\n@given(...)\ndef test_resolving_standard_contextmanager_as_generic(\n    x: contextlib.AbstractContextManager[Elem],\n):\n    assert isinstance(x, contextlib.AbstractContextManager)\n\n\n@given(...)\ndef test_resolving_standard_re_match_bytes_as_generic(x: re.Match[bytes]):\n    assert isinstance(x, re.Match)\n    assert isinstance(x[0], bytes)\n\n\n@given(...)\ndef test_resolving_standard_re_match_str_as_generic(x: re.Match[str]):\n    assert isinstance(x, re.Match)\n    assert isinstance(x[0], str)\n\n\n@given(...)\ndef test_resolving_standard_re_pattern_bytes_as_generic(x: re.Pattern[bytes]):\n    assert isinstance(x, re.Pattern)\n    assert isinstance(x.pattern, bytes)\n\n\n@given(...)\ndef test_resolving_standard_re_pattern_str_as_generic(x: re.Pattern[str]):\n    assert isinstance(x, re.Pattern)\n    assert isinstance(x.pattern, str)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_lookup_py38.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport dataclasses\nimport re\nimport typing\nfrom types import SimpleNamespace\n\nimport pytest\n\nfrom hypothesis import example, given, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.reflection import (\n    convert_positional_arguments,\n    get_pretty_function_description,\n)\nfrom hypothesis.strategies import from_type\n\nfrom tests.common.debug import (\n    assert_simple_property,\n    check_can_generate_examples,\n    find_any,\n)\nfrom tests.common.utils import fails_with, temp_registered\n\n\n@given(st.data())\ndef test_typing_Final(data):\n    value = data.draw(from_type(typing.Final[int]))\n    assert isinstance(value, int)\n\n\n@pytest.mark.parametrize(\"value\", [\"dog\", b\"goldfish\", 42, 63.4, -80.5, False])\ndef test_typing_Literal(value):\n    assert_simple_property(from_type(typing.Literal[value]), lambda v: v == value)\n\n\n@given(st.data())\ndef test_typing_Literal_nested(data):\n    lit = typing.Literal\n    values = [\n        (lit[\"hamster\", 0], (\"hamster\", 0)),\n        (lit[26, False, \"bunny\", 130], (26, False, \"bunny\", 130)),\n        (lit[lit[1]], {1}),\n        (lit[lit[1], 2], {1, 2}),\n        (lit[1, lit[2], 3], {1, 2, 3}),\n        (lit[lit[lit[1], lit[2]], lit[lit[3], lit[4]]], {1, 2, 3, 4}),\n    ]\n    literal_type, flattened_literals = data.draw(st.sampled_from(values))\n    assert data.draw(st.from_type(literal_type)) in flattened_literals\n\n\nclass A(typing.TypedDict):\n    a: int\n\n\n@given(from_type(A))\ndef test_simple_typeddict(value):\n    assert type(value) == dict\n    assert set(value) == {\"a\"}\n    assert isinstance(value[\"a\"], int)\n\n\nclass B(A, total=False):\n    # a is required, b is optional\n    b: bool\n\n\n@given(from_type(B))\ndef test_typeddict_with_optional(value):\n    assert type(value) == dict\n    assert set(value).issubset({\"a\", \"b\"})\n    assert isinstance(value[\"a\"], int)\n    if \"b\" in value:\n        assert isinstance(value[\"b\"], bool)\n\n\ndef test_simple_optional_key_is_optional():\n    # Optional keys are not currently supported, as PEP-589 leaves no traces\n    # at runtime.  See https://github.com/python/cpython/pull/17214\n    find_any(from_type(B), lambda d: \"b\" not in d)\n\n\nclass C(B):\n    # a is required, b is optional, c is required again\n    c: str\n\n\n@given(from_type(C))\ndef test_typeddict_with_optional_then_required_again(value):\n    assert type(value) == dict\n    assert set(value).issubset({\"a\", \"b\", \"c\"})\n    assert isinstance(value[\"a\"], int)\n    if \"b\" in value:\n        assert isinstance(value[\"b\"], bool)\n    assert isinstance(value[\"c\"], str)\n\n\nclass NestedDict(typing.TypedDict):\n    inner: A\n\n\n@given(from_type(NestedDict))\ndef test_typeddict_with_nested_value(value):\n    assert type(value) == dict\n    assert set(value) == {\"inner\"}\n    assert isinstance(value[\"inner\"][\"a\"], int)\n\n\ndef test_layered_optional_key_is_optional():\n    # Optional keys are not currently supported, as PEP-589 leaves no traces\n    # at runtime.  See https://github.com/python/cpython/pull/17214\n    find_any(from_type(C), lambda d: \"b\" not in d)\n\n\n@dataclasses.dataclass(slots=False, frozen=False)\nclass Node:\n    left: typing.Union[\"Node\", int]\n    right: typing.Union[\"Node\", int]\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"takes ~11 mins; datastructure explosion: https://github.com/pschanely/hypothesis-crosshair/issues/27\",\n)\n@given(st.builds(Node))\ndef test_can_resolve_recursive_dataclass(val):\n    assert isinstance(val, Node)\n\n\ndef test_can_register_new_type_for_typeddicts():\n    sentinel = object()\n    with temp_registered(C, st.just(sentinel)):\n        assert_simple_property(st.from_type(C), lambda v: v is sentinel)\n\n\n@pytest.mark.parametrize(\n    \"lam,source\",\n    [\n        ((lambda a, /, b: a), \"lambda a, /, b: a\"),\n        ((lambda a=None, /, b=None: a), \"lambda a=None, /, b=None: a\"),\n    ],\n)\ndef test_posonly_lambda_formatting(lam, source):\n    # Testing posonly lambdas, with and without default values\n    assert get_pretty_function_description(lam) == source\n\n\ndef test_does_not_convert_posonly_to_keyword():\n    args, kws = convert_positional_arguments(lambda x, /: None, (1,), {})\n    assert args\n    assert not kws\n\n\n@given(x=st.booleans())\ndef test_given_works_with_keyword_only_params(*, x):\n    pass\n\n\ndef test_given_works_with_keyword_only_params_some_unbound():\n    @given(x=st.booleans())\n    def test(*, x, y):\n        assert y is None\n\n    test(y=None)\n\n\ndef test_given_works_with_positional_only_params():\n    @given(y=st.booleans())\n    def test(x, /, y):\n        pass\n\n    test(None)\n\n\ndef test_cannot_pass_strategies_by_position_if_there_are_posonly_args():\n    @given(st.booleans())\n    def test(x, /, y):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        test(None)\n\n\n@fails_with(InvalidArgument)\n@given(st.booleans())\ndef test_cannot_pass_strategies_for_posonly_args(x, /):\n    pass\n\n\n@given(y=st.booleans())\ndef has_posonly_args(x, /, y):\n    pass\n\n\n@pytest.mark.xfail(\n    settings.get_current_profile_name() == \"threading\",\n    reason=(\n        \"dynamic @example applications modify the shared \"\n        \"has_posonly_args.hypothesis._given_kwargs.\"\n    ),\n    strict=False,\n)\ndef test_example_argument_validation():\n    example(y=None)(has_posonly_args)(1)  # Basic case is OK\n\n    with pytest.raises(\n        InvalidArgument,\n        match=re.escape(\n            \"Cannot pass positional arguments to @example() when decorating \"\n            \"a test function which has positional-only parameters.\"\n        ),\n    ):\n        example(None)(has_posonly_args)(1)\n\n    with pytest.raises(\n        InvalidArgument,\n        match=re.escape(\n            \"Inconsistent args: @given() got strategies for 'y', \"\n            \"but @example() got arguments for 'x'\"\n        ),\n    ):\n        example(x=None)(has_posonly_args)(1)\n\n\nclass FooProtocol(typing.Protocol):\n    def frozzle(self, x):\n        pass\n\n\nclass BarProtocol(typing.Protocol):\n    def bazzle(self, y):\n        pass\n\n\n@given(st.data())\ndef test_can_resolve_registered_protocol(data):\n    with temp_registered(\n        FooProtocol,\n        st.builds(SimpleNamespace, frozzle=st.functions(like=lambda x: ...)),\n    ):\n        obj = data.draw(st.from_type(FooProtocol))\n    assert obj.frozzle(x=1) is None\n\n\ndef test_cannot_resolve_un_registered_protocol():\n    msg = \"Instance and class checks can only be used with @runtime_checkable protocols\"\n    with pytest.raises(TypeError, match=msg):\n        check_can_generate_examples(st.from_type(BarProtocol))\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_lookup_py39.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport collections.abc\nimport dataclasses\nimport sys\nimport typing\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import InvalidArgument\n\nfrom tests.common.debug import (\n    assert_all_examples,\n    assert_simple_property,\n    check_can_generate_examples,\n    find_any,\n)\nfrom tests.common.utils import temp_registered\n\n# Union[A, B] is not equivalent to A | B until 3.14. We'll continue to test both\n# until then.\n# ruff: noqa: UP007\n\n\n@pytest.mark.parametrize(\n    \"annotated_type,expected_strategy_repr\",\n    [\n        (typing.Annotated[int, \"foo\"], \"integers()\"),\n        (typing.Annotated[list[float], \"foo\"], \"lists(floats())\"),\n        (typing.Annotated[typing.Annotated[str, \"foo\"], \"bar\"], \"text()\"),\n        (\n            typing.Annotated[typing.Annotated[list[dict[str, bool]], \"foo\"], \"bar\"],\n            \"lists(dictionaries(keys=text(), values=booleans()))\",\n        ),\n    ],\n)\ndef test_typing_Annotated(annotated_type, expected_strategy_repr):\n    assert repr(st.from_type(annotated_type)) == expected_strategy_repr\n\n\nPositiveInt = typing.Annotated[int, st.integers(min_value=1)]\nMoreThanTenInt = typing.Annotated[PositiveInt, st.integers(min_value=10 + 1)]\nWithTwoStrategies = typing.Annotated[int, st.integers(), st.none()]\nExtraAnnotationNoStrategy = typing.Annotated[PositiveInt, \"metadata\"]\n\n\ndef arg_positive(x: PositiveInt):\n    assert x > 0\n\n\ndef arg_more_than_ten(x: MoreThanTenInt):\n    assert x > 10\n\n\n@given(st.data())\ndef test_annotated_positive_int(data):\n    data.draw(st.builds(arg_positive))\n\n\n@given(st.data())\ndef test_annotated_more_than_ten(data):\n    data.draw(st.builds(arg_more_than_ten))\n\n\n@given(st.data())\ndef test_annotated_with_two_strategies(data):\n    assert data.draw(st.from_type(WithTwoStrategies)) is None\n\n\n@given(st.data())\ndef test_annotated_extra_metadata(data):\n    assert data.draw(st.from_type(ExtraAnnotationNoStrategy)) > 0\n\n\n@dataclasses.dataclass\nclass User:\n    id: int\n    following: list[\"User\"]  # works with typing.List\n\n\n@pytest.mark.skipif(sys.version_info[:2] >= (3, 11), reason=\"works in new Pythons\")\ndef test_string_forward_ref_message():\n    # See https://github.com/HypothesisWorks/hypothesis/issues/3016\n    s = st.builds(User)\n    with pytest.raises(InvalidArgument, match=\"`from __future__ import annotations`\"):\n        check_can_generate_examples(s)\n\n\n@pytest.mark.parametrize(\"typ\", (typing.Union[list[int], int], list[int] | int))\ndef test_issue_3080(typ):\n    # Check for https://github.com/HypothesisWorks/hypothesis/issues/3080\n    s = st.from_type(typ)\n    find_any(s, lambda x: isinstance(x, int))\n    find_any(s, lambda x: isinstance(x, list))\n\n\n@dataclasses.dataclass\nclass TypingTuple:\n    a: dict[tuple[int, int], str]\n\n\n@dataclasses.dataclass\nclass BuiltinTuple:\n    a: dict[tuple[int, int], str]\n\n\nTestDataClass = typing.Union[TypingTuple, BuiltinTuple]\n\n\n@pytest.mark.parametrize(\"data_class\", [TypingTuple, BuiltinTuple])\n@given(data=st.data())\ndef test_from_type_with_tuple_works(data, data_class: TestDataClass):\n    value: TestDataClass = data.draw(st.from_type(data_class))\n    assert len(value.a) >= 0\n\n\ndef _shorter_lists(list_type):\n    return st.lists(st.from_type(*typing.get_args(list_type)), max_size=2)\n\n\ndef test_can_register_builtin_list():\n    # Regression test for https://github.com/HypothesisWorks/hypothesis/issues/3635\n    with temp_registered(list, _shorter_lists):\n        assert_all_examples(\n            st.from_type(list[int]),\n            lambda ls: len(ls) <= 2 and {type(x) for x in ls}.issubset({int}),\n        )\n\n\nT = typing.TypeVar(\"T\")\n\n\n@typing.runtime_checkable\nclass Fooable(typing.Protocol[T]):\n    def foo(self): ...\n\n\nclass FooableConcrete(tuple):\n    def foo(self):\n        pass\n\n\ndef test_only_tuple_subclasses_in_typing_type():\n    # A generic typing type (such as Fooable) whose only concrete\n    # instantiations are tuples should still generate tuples. This is in\n    # contrast to test_tuple_subclasses_not_generic_sequences, which discards\n    # tuples if there are any alternatives.\n    with temp_registered(FooableConcrete, st.builds(FooableConcrete)):\n        s = st.from_type(Fooable[int])\n        assert_all_examples(s, lambda x: type(x) is FooableConcrete)\n\n\ndef test_lookup_registered_tuple():\n    sentinel = object()\n    typ = tuple[int]\n    with temp_registered(tuple, st.just(sentinel)):\n        assert_simple_property(st.from_type(typ), lambda v: v is sentinel)\n    assert_simple_property(st.from_type(typ), lambda v: v is not sentinel)\n\n\nsentinel = object()\n\n\nclass LazyStrategyAnnotation:\n    __is_annotated_types_grouped_metadata__ = True\n\n    def __iter__(self):\n        return iter([st.just(sentinel)])\n\n\n@given(...)\ndef test_grouped_protocol_strategy(x: typing.Annotated[int, LazyStrategyAnnotation()]):\n    assert x is sentinel\n\n\ndef test_collections_abc_callable_none():\n    # https://github.com/HypothesisWorks/hypothesis/issues/4192\n    s = st.from_type(collections.abc.Callable[[None], None])\n    assert_all_examples(s, lambda x: callable(x) and x(None) is None)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_map.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import assume, given, strategies as st\nfrom hypothesis.strategies._internal.lazy import unwrap_strategies\n\nfrom tests.common.debug import assert_no_examples\n\n\n@given(st.integers().map(lambda x: assume(x % 3 != 0) and x))\ndef test_can_assume_in_map(x):\n    assert x % 3 != 0\n\n\ndef test_assume_in_just_raises_immediately():\n    assert_no_examples(st.just(1).map(lambda x: assume(x == 2)))\n\n\ndef test_identity_map_is_noop():\n    s = unwrap_strategies(st.integers())\n    assert s.map(lambda x: x) is s\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_mock.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"Checks that @given, @mock.patch, and pytest fixtures work as expected.\"\"\"\n\n\nimport math\nfrom unittest import mock\n\ntry:\n    from pytest import Config\nexcept ImportError:  # pytest<7.0.0\n    from _pytest.config import Config\n\nfrom hypothesis import given, strategies as st\n\nfrom tests.common.utils import skipif_threading\n\n\n@given(thing=st.text())\n@mock.patch(\"math.atan\")\n# mock.patch is thread-unsafe. pytest-run-parallel normally detects this and skips\n# the test, but because we set it inside of @given it can't (or doesn't?) peek\n# inside the AST, resulting in a false negative.\n@skipif_threading\ndef test_can_mock_inside_given_without_fixture(atan, thing):\n    assert isinstance(atan, mock.MagicMock)\n    assert isinstance(math.atan, mock.MagicMock)\n\n\n@mock.patch(\"math.atan\")\n@given(thing=st.text())\ndef test_can_mock_outside_given_with_fixture(atan, pytestconfig, thing):\n    assert isinstance(atan, mock.MagicMock)\n    assert isinstance(math.atan, mock.MagicMock)\n    assert isinstance(pytestconfig, Config)\n\n\n@given(thing=st.text())\ndef test_can_mock_within_test_with_fixture(pytestconfig, thing):\n    assert isinstance(pytestconfig, Config)\n    assert not isinstance(math.atan, mock.MagicMock)\n    with mock.patch(\"math.atan\") as atan:\n        assert isinstance(atan, mock.MagicMock)\n        assert isinstance(math.atan, mock.MagicMock)\n    assert not isinstance(math.atan, mock.MagicMock)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_monitoring.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport sys\nfrom contextlib import contextmanager\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import HypothesisWarning\nfrom hypothesis.internal.scrutineer import MONITORING_TOOL_ID\n\n\n@contextmanager\ndef using_tool_id(tool_id, tool_name):\n    try:\n        sys.monitoring.use_tool_id(tool_id, tool_name)\n        yield\n    finally:\n        sys.monitoring.free_tool_id(tool_id)\n\n\n@pytest.mark.skipif(sys.version_info[:2] < (3, 12), reason=\"new namespace\")\ndef test_monitoring_warns_on_registered_tool_id(warns_or_raises):\n\n    # scrutineer can't run if something has already registered its tool id.\n    with (\n        using_tool_id(MONITORING_TOOL_ID, \"rogue\"),\n        warns_or_raises(HypothesisWarning, match=r\"already taken by tool rogue\"),\n    ):\n\n        @given(st.integers())\n        def f(n):\n            raise AssertionError\n\n        with pytest.raises(AssertionError):\n            f()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_nothing.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import InvalidArgument\n\nfrom tests.common.debug import assert_no_examples, minimal\n\n\ndef test_resampling():\n    x = minimal(\n        st.lists(st.integers(), min_size=1).flatmap(\n            lambda x: st.lists(st.sampled_from(x))\n        ),\n        lambda x: len(x) >= 10 and len(set(x)) == 1,\n    )\n    assert x == [0] * 10\n\n\n@given(st.lists(st.nothing()))\ndef test_list_of_nothing(xs):\n    assert xs == []\n\n\n@given(st.sets(st.nothing()))\ndef test_set_of_nothing(xs):\n    assert xs == set()\n\n\ndef test_validates_min_size():\n    with pytest.raises(InvalidArgument):\n        st.lists(st.nothing(), min_size=1).validate()\n\n\ndef test_function_composition():\n    assert st.nothing().map(lambda x: \"hi\").is_empty\n    assert st.nothing().filter(lambda x: True).is_empty\n    assert st.nothing().flatmap(lambda x: st.integers()).is_empty\n\n\ndef test_tuples_detect_empty_elements():\n    assert st.tuples(st.nothing()).is_empty\n\n\ndef test_fixed_dictionaries_detect_empty_values():\n    assert st.fixed_dictionaries({\"a\": st.nothing()}).is_empty\n\n\ndef test_no_examples():\n    assert_no_examples(st.nothing())\n\n\n@pytest.mark.parametrize(\n    \"s\",\n    [\n        st.nothing(),\n        st.nothing().map(lambda x: x),\n        st.nothing().filter(lambda x: True),\n        st.nothing().flatmap(lambda x: st.integers()),\n    ],\n)\ndef test_empty(s):\n    assert s.is_empty\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_numerics.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport decimal\nfrom math import copysign, inf\n\nimport pytest\n\nfrom hypothesis import HealthCheck, assume, given, reject, settings\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.floats import next_down, next_up\nfrom hypothesis.strategies import (\n    booleans,\n    data,\n    decimals,\n    floats,\n    fractions,\n    integers,\n    none,\n    sampled_from,\n    tuples,\n)\n\nfrom tests.common.debug import check_can_generate_examples, find_any, minimal\nfrom tests.common.utils import checks_deprecated_behaviour, skipif_threading\n\n\n@settings(suppress_health_check=list(HealthCheck))\n@given(data())\ndef test_fuzz_floats_bounds(data):\n    width = data.draw(sampled_from([64, 32, 16]))\n    bound = none() | floats(allow_nan=False, width=width)\n    low, high = data.draw(tuples(bound, bound), label=\"low, high\")\n    if low is not None and high is not None and low > high:\n        low, high = high, low\n    if low is not None and high is not None and low > high:\n        low, high = high, low\n    exmin = low is not None and low != inf and data.draw(booleans(), label=\"ex_min\")\n    exmax = high is not None and high != -inf and data.draw(booleans(), label=\"ex_max\")\n\n    if low is not None and high is not None:\n        lo = next_up(low, width) if exmin else low\n        hi = next_down(high, width) if exmax else high\n        # There must actually be floats between these bounds\n        assume(lo <= hi)\n        if lo == hi == 0:\n            assume(not exmin and not exmax and copysign(1.0, lo) <= copysign(1.0, hi))\n\n    s = floats(low, high, exclude_min=exmin, exclude_max=exmax, width=width)\n    val = data.draw(s, label=\"value\")\n    assume(val)  # positive/negative zero is an issue\n\n    if low is not None:\n        assert low <= val\n    if high is not None:\n        assert val <= high\n    if exmin:\n        assert low != val\n    if exmax:\n        assert high != val\n\n\n@given(data())\ndef test_fuzz_fractions_bounds(data):\n    denom = data.draw(none() | integers(1, 100), label=\"denominator\")\n    fracs = none() | fractions(max_denominator=denom)\n    low, high = data.draw(tuples(fracs, fracs), label=\"low, high\")\n    if low is not None and high is not None and low > high:\n        low, high = high, low\n    try:\n        val = data.draw(fractions(low, high, max_denominator=denom), label=\"value\")\n    except InvalidArgument:\n        reject()  # fractions too close for given max_denominator\n    if low is not None:\n        assert low <= val\n    if high is not None:\n        assert val <= high\n    if denom is not None:\n        assert 1 <= val.denominator <= denom\n\n\n@given(data())\ndef test_fuzz_decimals_bounds(data):\n    places = data.draw(none() | integers(0, 20), label=\"places\")\n    finite_decs = (\n        decimals(allow_nan=False, allow_infinity=False, places=places) | none()\n    )\n    low, high = data.draw(tuples(finite_decs, finite_decs), label=\"low, high\")\n    if low is not None and high is not None and low > high:\n        low, high = high, low\n    ctx = decimal.Context(prec=data.draw(integers(1, 100), label=\"precision\"))\n    try:\n        with decimal.localcontext(ctx):\n            strat = decimals(\n                low, high, allow_nan=False, allow_infinity=False, places=places\n            )\n            val = data.draw(strat, label=\"value\")\n    except InvalidArgument:\n        reject()  # decimals too close for given places\n    if low is not None:\n        assert low <= val\n    if high is not None:\n        assert val <= high\n    if places is not None:\n        assert val.as_tuple().exponent == -places\n\n\ndef test_all_decimals_can_be_exact_floats():\n    find_any(\n        decimals(), lambda x: assume(x.is_finite()) and decimal.Decimal(float(x)) == x\n    )\n\n\n@given(fractions(), fractions(), fractions())\ndef test_fraction_addition_is_well_behaved(x, y, z):\n    assert x + y + z == y + x + z\n\n\ndef test_decimals_include_nan():\n    find_any(decimals(), lambda x: x.is_nan())\n\n\ndef test_decimals_include_inf():\n    find_any(decimals(), lambda x: x.is_infinite(), settings(max_examples=10**6))\n\n\n@given(decimals(allow_nan=False))\ndef test_decimals_can_disallow_nan(x):\n    assert not x.is_nan()\n\n\n@given(decimals(allow_infinity=False))\ndef test_decimals_can_disallow_inf(x):\n    assert not x.is_infinite()\n\n\n@pytest.mark.parametrize(\"places\", range(10))\ndef test_decimals_have_correct_places(places):\n    @given(decimals(0, 10, allow_nan=False, places=places))\n    def inner_tst(n):\n        assert n.as_tuple().exponent == -places\n\n    inner_tst()\n\n\n@given(decimals(min_value=\"0.1\", max_value=\"0.2\", allow_nan=False, places=1))\ndef test_works_with_few_values(dec):\n    assert dec in (decimal.Decimal(\"0.1\"), decimal.Decimal(\"0.2\"))\n\n\n@given(decimals(places=3, allow_nan=False, allow_infinity=False))\ndef test_issue_725_regression(x):\n    pass\n\n\n@given(decimals(min_value=\"0.1\", max_value=\"0.3\"))\ndef test_issue_739_regression(x):\n    pass\n\n\ndef test_consistent_decimal_error():\n    bad = \"invalid argument to Decimal\"\n    with pytest.raises(InvalidArgument) as excinfo:\n        check_can_generate_examples(decimals(bad))\n    with (\n        pytest.raises(InvalidArgument) as excinfo2,\n        decimal.localcontext(decimal.Context(traps=[])),\n    ):\n        check_can_generate_examples(decimals(bad))\n    assert str(excinfo.value) == str(excinfo2.value)\n\n\n@pytest.mark.parametrize(\n    \"s, msg\",\n    [\n        (\n            floats(min_value=inf, allow_infinity=False),\n            \"allow_infinity=False excludes min_value=inf\",\n        ),\n        (\n            floats(min_value=next_down(inf), exclude_min=True, allow_infinity=False),\n            \"exclude_min=True turns min_value=.+? into inf, but allow_infinity=False\",\n        ),\n        (\n            floats(max_value=-inf, allow_infinity=False),\n            \"allow_infinity=False excludes max_value=-inf\",\n        ),\n        (\n            floats(max_value=next_up(-inf), exclude_max=True, allow_infinity=False),\n            \"exclude_max=True turns max_value=.+? into -inf, but allow_infinity=False\",\n        ),\n    ],\n)\n@skipif_threading  # strategy instances are shared, which persists .validate_called\ndef test_floats_message(s, msg):\n    # https://github.com/HypothesisWorks/hypothesis/issues/3207\n    with pytest.raises(InvalidArgument, match=msg):\n        s.validate()\n\n\n@pytest.mark.parametrize(\"s\", [decimals(), decimals(places=10)], ids=repr)\ndef test_minimal_nonfinite_decimal_is_inf(s):\n    assert minimal(s.filter(lambda x: not x.is_finite())) == decimal.Decimal(\"Infinity\")\n\n\n@checks_deprecated_behaviour\ndef test_decimals_warns_for_inexact_numeric_bounds():\n    check_can_generate_examples(decimals(min_value=1e-100))\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_observability.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport base64\nimport contextlib\nimport json\nimport math\nimport textwrap\nimport threading\nimport warnings\nfrom collections import defaultdict\nfrom contextlib import nullcontext\n\nimport pytest\n\nimport hypothesis.internal.observability\nfrom hypothesis import (\n    assume,\n    event,\n    example,\n    given,\n    note,\n    seed,\n    settings,\n    strategies as st,\n    target,\n)\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.internal.compat import PYPY\nfrom hypothesis.internal.conjecture.choice import ChoiceNode, choices_key\nfrom hypothesis.internal.conjecture.data import Span\nfrom hypothesis.internal.coverage import IN_COVERAGE_TESTS\nfrom hypothesis.internal.floats import SIGNALING_NAN, float_to_int, int_to_float\nfrom hypothesis.internal.intervalsets import IntervalSet\nfrom hypothesis.internal.observability import (\n    TESTCASE_CALLBACKS,\n    InfoObservation,\n    TestCaseObservation,\n    add_observability_callback,\n    choices_to_json,\n    nodes_to_json,\n    observability_enabled,\n    remove_observability_callback,\n    with_observability_callback,\n)\nfrom hypothesis.stateful import (\n    RuleBasedStateMachine,\n    invariant,\n    rule,\n    run_state_machine_as_test,\n)\nfrom hypothesis.strategies._internal.utils import to_jsonable\n\nfrom tests.common.utils import (\n    Why,\n    capture_observations,\n    checks_deprecated_behaviour,\n    run_concurrently,\n    skipif_threading,\n    xfail_on_crosshair,\n)\nfrom tests.conjecture.common import choices, integer_constr, nodes\n\n\n@seed(\"deterministic so we don't miss some combination of features\")\n@example(l=[1], a=0, x=4, data=None)\n# explicitly set max_examples=100 to override our lower example limit for coverage tests.\n@settings(database=InMemoryExampleDatabase(), deadline=None, max_examples=100)\n@given(st.lists(st.integers()), st.integers(), st.integers(), st.data())\ndef do_it_all(l, a, x, data):\n    event(f\"{x%2=}\")\n    target(x % 5, label=\"x%5\")\n    assume(a % 9)\n    assume(len(l) > 0)\n    if data:\n        data.draw(st.text(\"abcdef\", min_size=a % 3), label=\"interactive\")\n    1 / ((x or 1) % 7)\n\n\n@xfail_on_crosshair(Why.other, strict=False)  # flakey BackendCannotProceed ??\n@skipif_threading  # captures observations from other threads\ndef test_observability():\n    with capture_observations() as ls:\n        with pytest.raises(ZeroDivisionError):\n            do_it_all()\n        with pytest.raises(ZeroDivisionError):\n            do_it_all()\n\n    infos = [t for t in ls if t.type == \"info\"]\n    assert len(infos) == 2\n    assert {t.title for t in infos} == {\"Hypothesis Statistics\"}\n\n    testcases = [t for t in ls if t.type == \"test_case\"]\n    assert len(testcases) > 50\n    assert {t.property for t in testcases} == {do_it_all.__name__}\n    assert len({t.run_start for t in testcases}) == 2\n    assert {t.status for t in testcases} == {\"gave_up\", \"passed\", \"failed\"}\n    for t in testcases:\n        if t.status != \"gave_up\":\n            assert t.timing\n            assert (\"interactive\" in t.arguments) == (\n                \"generate:interactive\" in t.timing\n            )\n\n\n@xfail_on_crosshair(Why.other)\ndef test_capture_unnamed_arguments():\n    @given(st.integers(), st.floats(), st.data())\n    def f(v1, v2, data):\n        data.draw(st.booleans())\n\n    with capture_observations() as observations:\n        f()\n\n    test_cases = [tc for tc in observations if tc.type == \"test_case\"]\n    for test_case in test_cases:\n        assert list(test_case.arguments.keys()) == [\n            \"v1\",\n            \"v2\",\n            \"data\",\n            \"Draw 1\",\n        ], test_case\n\n\n@pytest.mark.skipif(\n    PYPY or IN_COVERAGE_TESTS, reason=\"coverage requires sys.settrace pre-3.12\"\n)\ndef test_failure_includes_explain_phase_comments():\n    @given(st.integers(), st.integers())\n    @settings(database=None)\n    def test_fails(x, y):\n        if x:\n            raise AssertionError\n\n    with capture_observations() as observations, pytest.raises(AssertionError):\n        test_fails()\n\n    test_cases = [tc for tc in observations if tc.type == \"test_case\"]\n    # only the last test case observation, once we've finished shrinking it,\n    # will include explain phase comments.\n    #\n    # Note that the output does *not* include `Explanation:` comments. See\n    # https://github.com/HypothesisWorks/hypothesis/pull/4399#discussion_r2101559648\n    expected = textwrap.dedent(\n        r\"\"\"\n        test_fails(\n            x=1,\n            y=0,  # or any other generated value\n        )\n    \"\"\"\n    ).strip()\n    assert test_cases[-1].representation == expected\n\n\ndef test_failure_includes_notes():\n    @given(st.data())\n    @settings(database=None)\n    def test_fails_with_note(data):\n        note(\"not included 1\")\n        data.draw(st.booleans())\n        note(\"not included 2\")\n        raise AssertionError\n\n    with capture_observations() as observations, pytest.raises(AssertionError):\n        test_fails_with_note()\n\n    expected = textwrap.dedent(\n        \"\"\"\n        test_fails_with_note(\n            data=data(...),\n        )\n        Draw 1: False\n    \"\"\"\n    ).strip()\n    test_cases = [tc for tc in observations if tc.type == \"test_case\"]\n    assert test_cases[-1].representation == expected\n\n\ndef test_normal_representation_includes_draws():\n    @given(st.data())\n    def f(data):\n        b1 = data.draw(st.booleans())\n        note(\"not included\")\n        b2 = data.draw(st.booleans(), label=\"second\")\n        assume(b1 and b2)\n\n    with capture_observations() as observations:\n        f()\n\n    crosshair = settings.get_current_profile_name() == \"crosshair\"\n    expected = textwrap.dedent(\n        f\"\"\"\n        f(\n            data={'<symbolic>' if crosshair else 'data(...)'},\n        )\n        Draw 1: True\n        Draw 2 (second): True\n    \"\"\"\n    ).strip()\n    test_cases = [\n        tc for tc in observations if tc.type == \"test_case\" and tc.status == \"passed\"\n    ]\n    assert test_cases\n    # TODO crosshair has a soundness bug with assume. remove branch when fixed\n    # https://github.com/pschanely/hypothesis-crosshair/issues/34\n    if not crosshair:\n        assert {tc.representation for tc in test_cases} == {expected}\n\n\n@xfail_on_crosshair(Why.other)\ndef test_capture_named_arguments():\n    @given(named1=st.integers(), named2=st.floats(), data=st.data())\n    def f(named1, named2, data):\n        data.draw(st.booleans())\n\n    with capture_observations() as observations:\n        f()\n\n    test_cases = [tc for tc in observations if tc.type == \"test_case\"]\n    for test_case in test_cases:\n        assert list(test_case.arguments.keys()) == [\n            \"named1\",\n            \"named2\",\n            \"data\",\n            \"Draw 1\",\n        ], test_case\n\n\ndef test_assume_has_status_reason():\n    @given(st.booleans())\n    def f(b):\n        assume(b)\n\n    with capture_observations() as ls:\n        f()\n\n    gave_ups = [t for t in ls if t.type == \"test_case\" and t.status == \"gave_up\"]\n    for gave_up in gave_ups:\n        assert gave_up.status_reason.startswith(\"failed to satisfy assume() in f\")\n\n\n@pytest.mark.skipif(\n    PYPY or IN_COVERAGE_TESTS, reason=\"coverage requires sys.settrace pre-3.12\"\n)\ndef test_minimal_failing_observation():\n    @given(st.integers(), st.integers())\n    @settings(database=None)\n    def test_fails(x, y):\n        if x:\n            raise AssertionError\n\n    with capture_observations() as observations, pytest.raises(AssertionError):\n        test_fails()\n\n    observation = [tc for tc in observations if tc.type == \"test_case\"][-1]\n    expected_representation = textwrap.dedent(\n        r\"\"\"\n        test_fails(\n            x=1,\n            y=0,  # or any other generated value\n        )\n    \"\"\"\n    ).strip()\n\n    assert observation.type == \"test_case\"\n    assert observation.property == \"test_fails\"\n    assert observation.status == \"failed\"\n    assert \"AssertionError\" in observation.status_reason\n    assert set(observation.timing.keys()) == {\n        \"execute:test\",\n        \"overall:gc\",\n        \"generate:x\",\n        \"generate:y\",\n    }\n    assert observation.coverage is None\n    assert observation.features == {}\n    assert observation.how_generated == \"minimal failing example\"\n    assert \"AssertionError\" in observation.metadata.traceback\n    assert \"test_fails\" in observation.metadata.traceback\n    assert observation.metadata.reproduction_decorator.startswith(\"@reproduce_failure\")\n    assert observation.representation == expected_representation\n    assert observation.arguments == {\"x\": 1, \"y\": 0}\n\n\n@pytest.mark.skipif(\n    PYPY or IN_COVERAGE_TESTS, reason=\"coverage requires sys.settrace pre-3.12\"\n)\ndef test_all_failing_observations_have_reproduction_decorator():\n    @given(st.integers())\n    def test_fails(x):\n        raise AssertionError\n\n    with capture_observations() as observations, pytest.raises(AssertionError):\n        test_fails()\n\n    # all failed test case observations should have reprodution_decorator\n    for observation in [\n        tc for tc in observations if tc.type == \"test_case\" and tc.status == \"failed\"\n    ]:\n        decorator = observation.metadata.reproduction_decorator\n        assert decorator is not None\n        assert decorator.startswith(\"@reproduce_failure\")\n\n\n@settings(max_examples=20, stateful_step_count=5)\nclass UltraSimpleMachine(RuleBasedStateMachine):\n    value = 0\n\n    @rule()\n    def inc(self):\n        self.value += 1\n\n    @rule()\n    def dec(self):\n        self.value -= 1\n\n    @invariant()\n    def limits(self):\n        assert abs(self.value) <= 100\n\n\n@xfail_on_crosshair(Why.other, strict=False)\ndef test_observability_captures_stateful_reprs():\n    with capture_observations() as ls:\n        run_state_machine_as_test(UltraSimpleMachine)\n\n    for x in ls:\n        if x.type != \"test_case\" or x.status == \"gave_up\":\n            continue\n        r = x.representation\n        assert \"state.limits()\" in r\n        assert \"state.inc()\" in r or \"state.dec()\" in r  # or both\n\n        t = x.timing\n        assert \"execute:invariant:limits\" in t\n        has_inc = \"generate:rule:inc\" in t and \"execute:rule:inc\" in t\n        has_dec = \"generate:rule:dec\" in t and \"execute:rule:dec\" in t\n        assert has_inc or has_dec\n\n\n# BytestringProvider.draw_boolean divides [0, 127] as False and [128, 255]\n# as True\n@pytest.mark.parametrize(\n    \"buffer, expected_status\",\n    [\n        # Status.OVERRUN\n        (b\"\", \"gave_up\"),\n        # Status.INVALID\n        (b\"\\x00\" + bytes([255]), \"gave_up\"),\n        # Status.VALID\n        (b\"\\x00\\x00\", \"passed\"),\n        # Status.INTERESTING\n        (bytes([255]) + b\"\\x00\", \"failed\"),\n    ],\n)\ndef test_fuzz_one_input_status(buffer, expected_status):\n    @given(st.booleans(), st.booleans())\n    def test_fails(should_fail, should_fail_assume):\n        if should_fail:\n            raise AssertionError\n        if should_fail_assume:\n            assume(False)\n\n    with (\n        capture_observations() as ls,\n        pytest.raises(AssertionError) if expected_status == \"failed\" else nullcontext(),\n    ):\n        test_fails.hypothesis.fuzz_one_input(buffer)\n    assert len(ls) == 1\n    assert ls[0].status == expected_status\n    assert ls[0].how_generated == \"fuzz_one_input\"\n\n\ndef _decode_choice(value):\n    if isinstance(value, list):\n        if value[0] == \"integer\":\n            # large integers get cast to string, stored as [\"integer\", str(value)]\n            assert isinstance(value[1], str)\n            return int(value[1])\n        elif value[0] == \"bytes\":\n            assert isinstance(value[1], str)\n            return base64.b64decode(value[1])\n        elif value[0] == \"float\":\n            assert isinstance(value[1], int)\n            choice = int_to_float(value[1])\n            assert math.isnan(choice)\n            return choice\n        else:\n            return value[1]\n\n    return value\n\n\ndef _decode_choices(data):\n    return [_decode_choice(value) for value in data]\n\n\ndef _decode_nodes(data):\n    return [\n        ChoiceNode(\n            type=node[\"type\"],\n            value=_decode_choice(node[\"value\"]),\n            constraints=_decode_constraints(node[\"type\"], node[\"constraints\"]),\n            was_forced=node[\"was_forced\"],\n        )\n        for node in data\n    ]\n\n\ndef _decode_constraints(choice_type, data):\n    if choice_type == \"integer\":\n        return {\n            \"min_value\": _decode_choice(data[\"min_value\"]),\n            \"max_value\": _decode_choice(data[\"max_value\"]),\n            \"weights\": (\n                None\n                if data[\"weights\"] is None\n                else {_decode_choice(k): v for k, v in data[\"weights\"]}\n            ),\n            \"shrink_towards\": _decode_choice(data[\"shrink_towards\"]),\n        }\n    elif choice_type == \"float\":\n        return {\n            \"min_value\": _decode_choice(data[\"min_value\"]),\n            \"max_value\": _decode_choice(data[\"max_value\"]),\n            \"allow_nan\": data[\"allow_nan\"],\n            \"smallest_nonzero_magnitude\": data[\"smallest_nonzero_magnitude\"],\n        }\n    elif choice_type == \"string\":\n        return {\n            \"intervals\": IntervalSet(tuple(data[\"intervals\"])),\n            \"min_size\": _decode_choice(data[\"min_size\"]),\n            \"max_size\": _decode_choice(data[\"max_size\"]),\n        }\n    elif choice_type == \"bytes\":\n        return {\n            \"min_size\": _decode_choice(data[\"min_size\"]),\n            \"max_size\": _decode_choice(data[\"max_size\"]),\n        }\n    elif choice_type == \"boolean\":\n        return {\"p\": data[\"p\"]}\n    else:\n        raise ValueError(f\"unknown choice type {choice_type}\")\n\n\ndef _has_surrogate(choice):\n    return isinstance(choice, str) and any(0xD800 <= ord(c) <= 0xDFFF for c in choice)\n\n\n@example([0.0])\n@example([-0.0])\n@example([SIGNALING_NAN])\n@example([math.nan])\n@example([math.inf])\n@example([-math.inf])\n# json.{loads, dumps} does not roundtrip for surrogate pairs; they are combined\n# into the single code point by json.loads:\n#   json.loads(json.dumps(\"\\udbf4\\udc00\")) == '\\U0010d000'\n#\n# Ignore this case with an `assume`, and add an explicit example to ensure we\n# continue to do so.\n@example([\"\\udbf4\\udc00\"])\n@given(st.lists(choices()))\ndef test_choices_json_roundtrips(choices):\n    assume(not any(_has_surrogate(choice) for choice in choices))\n    choices2 = _decode_choices(json.loads(json.dumps(choices_to_json(choices))))\n    assert choices_key(choices) == choices_key(choices2)\n\n\n@given(st.lists(nodes()))\ndef test_nodes_json_roundtrips(nodes):\n    assume(\n        not any(\n            _has_surrogate(node.value)\n            or any(_has_surrogate(value) for value in node.constraints.values())\n            for node in nodes\n        )\n    )\n    nodes2 = _decode_nodes(json.loads(json.dumps(nodes_to_json(nodes))))\n    assert nodes == nodes2\n\n\n@pytest.mark.parametrize(\n    \"choice, expected\",\n    [\n        (math.nan, [\"float\", float_to_int(math.nan)]),\n        (SIGNALING_NAN, [\"float\", float_to_int(SIGNALING_NAN)]),\n        (1, 1),\n        (-1, -1),\n        (2**63 + 1, [\"integer\", str(2**63 + 1)]),\n        (-(2**63 + 1), [\"integer\", str(-(2**63 + 1))]),\n        (1.0, 1.0),\n        (-0.0, -0.0),\n        (0.0, 0.0),\n        (True, True),\n        (False, False),\n        (b\"a\", [\"bytes\", \"YQ==\"]),\n    ],\n)\ndef test_choices_to_json_explicit(choice, expected):\n    assert choices_to_json([choice]) == [expected]\n\n\n@pytest.mark.parametrize(\n    \"choice_node, expected\",\n    [\n        (\n            ChoiceNode(\n                type=\"integer\",\n                value=2**63 + 1,\n                constraints=integer_constr(),\n                was_forced=False,\n            ),\n            {\n                \"type\": \"integer\",\n                \"value\": [\"integer\", str(2**63 + 1)],\n                \"constraints\": integer_constr(),\n                \"was_forced\": False,\n            },\n        ),\n    ],\n)\ndef test_choice_nodes_to_json_explicit(choice_node, expected):\n    assert nodes_to_json([choice_node]) == [expected]\n\n\ndef test_metadata_to_json():\n    # this is mostly a covering test than testing anything particular about\n    # ObservationMetadata.\n    @given(st.integers())\n    def f(n):\n        pass\n\n    with capture_observations(choices=True) as observations:\n        f()\n\n    observations = [obs for obs in observations if obs.type == \"test_case\"]\n    for observation in observations:\n        assert set(\n            to_jsonable(observation.metadata, avoid_realization=False).keys()\n        ) == {\n            \"traceback\",\n            \"reproduction_decorator\",\n            \"predicates\",\n            \"backend\",\n            \"sys.argv\",\n            \"os.getpid()\",\n            \"imported_at\",\n            \"data_status\",\n            \"phase\",\n            \"interesting_origin\",\n            \"choice_nodes\",\n            \"choice_spans\",\n        }\n        assert observation.metadata.choice_nodes is not None\n\n        for span in observation.metadata.choice_spans:\n            assert isinstance(span, Span)\n            assert 0 <= span.start <= len(observation.metadata.choice_nodes)\n            assert 0 <= span.end <= len(observation.metadata.choice_nodes)\n\n\n@contextlib.contextmanager\ndef restore_callbacks():\n    callbacks = hypothesis.internal.observability._callbacks.copy()\n    callbacks_all = hypothesis.internal.observability._callbacks_all_threads.copy()\n    try:\n        yield\n    finally:\n        hypothesis.internal.observability._callbacks = callbacks\n        hypothesis.internal.observability._callbacks_all_threads = callbacks_all\n\n\n@contextlib.contextmanager\ndef with_collect_coverage(*, value: bool):\n    original_value = hypothesis.internal.observability.OBSERVABILITY_COLLECT_COVERAGE\n    hypothesis.internal.observability.OBSERVABILITY_COLLECT_COVERAGE = value\n    try:\n        yield\n    finally:\n        hypothesis.internal.observability.OBSERVABILITY_COLLECT_COVERAGE = (\n            original_value\n        )\n\n\ndef _callbacks():\n    # respect changes from the restore_callbacks context manager by re-accessing\n    # its namespace, instead of keeping\n    # `from hypothesis.internal.observability import _callbacks` around\n    return hypothesis.internal.observability._callbacks\n\n\n@skipif_threading\ndef test_observability_callbacks():\n    def f(observation):\n        pass\n\n    def g(observation):\n        pass\n\n    thread_id = threading.get_ident()\n\n    with restore_callbacks():\n        assert not observability_enabled()\n\n        add_observability_callback(f)\n        assert _callbacks() == {thread_id: [f]}\n        assert observability_enabled()\n\n        add_observability_callback(g)\n        assert _callbacks() == {thread_id: [f, g]}\n        assert observability_enabled()\n\n        remove_observability_callback(g)\n        assert _callbacks() == {thread_id: [f]}\n        assert observability_enabled()\n\n        remove_observability_callback(g)\n        assert _callbacks() == {thread_id: [f]}\n        assert observability_enabled()\n\n        remove_observability_callback(f)\n        assert _callbacks() == {}\n        assert not observability_enabled()\n\n\n@skipif_threading\ndef test_observability_callbacks_all_threads():\n    thread_id = threading.get_ident()\n\n    def f(observation, thread_id):\n        pass\n\n    with restore_callbacks():\n        assert not observability_enabled()\n\n        add_observability_callback(f, all_threads=True)\n        assert hypothesis.internal.observability._callbacks_all_threads == [f]\n        assert _callbacks() == {}\n        assert observability_enabled()\n\n        add_observability_callback(f)\n        assert hypothesis.internal.observability._callbacks_all_threads == [f]\n        assert _callbacks() == {thread_id: [f]}\n        assert observability_enabled()\n\n        # remove_observability_callback removes it both from per-thread and\n        # all_threads. The semantics of duplicated callbacks is weird enough\n        # that I don't want to commit to anything here, so I'm leaving this as\n        # somewhat undefined behavior, and recommending that users simply not\n        # register a callback both normally and for all threads.\n        remove_observability_callback(f)\n        assert hypothesis.internal.observability._callbacks_all_threads == []\n        assert _callbacks() == {}\n        assert not observability_enabled()\n\n\n@checks_deprecated_behaviour\ndef test_testcase_callbacks_deprecation_bool():\n    bool(TESTCASE_CALLBACKS)\n\n\n@checks_deprecated_behaviour\ndef test_testcase_callbacks_deprecation_append():\n    with restore_callbacks():\n        TESTCASE_CALLBACKS.append(lambda x: None)\n\n\n@checks_deprecated_behaviour\ndef test_testcase_callbacks_deprecation_remove():\n    with restore_callbacks():\n        TESTCASE_CALLBACKS.remove(lambda x: None)\n\n\ndef test_testcase_callbacks():\n    def f(observation):\n        pass\n\n    def g(observation):\n        pass\n\n    thread_id = threading.get_ident()\n\n    with restore_callbacks(), warnings.catch_warnings():\n        # ignore TESTCASE_CALLBACKS deprecation warnings\n        warnings.simplefilter(\"ignore\")\n\n        assert not bool(TESTCASE_CALLBACKS)\n        add_observability_callback(f)\n        assert _callbacks() == {thread_id: [f]}\n\n        assert bool(TESTCASE_CALLBACKS)\n        add_observability_callback(g)\n        assert _callbacks() == {thread_id: [f, g]}\n\n        assert bool(TESTCASE_CALLBACKS)\n        remove_observability_callback(g)\n        assert _callbacks() == {thread_id: [f]}\n\n        assert bool(TESTCASE_CALLBACKS)\n        remove_observability_callback(f)\n        assert _callbacks() == {}\n\n        assert not bool(TESTCASE_CALLBACKS)\n\n\ndef test_only_receives_callbacks_from_this_thread():\n    @given(st.integers())\n    def g(n):\n        pass\n\n    def test():\n        count_observations = 0\n\n        def callback(observation):\n            nonlocal count_observations\n            count_observations += 1\n\n        add_observability_callback(callback)\n\n        with warnings.catch_warnings():\n            g()\n\n        # one per example, plus one for the overall run\n        assert count_observations == settings().max_examples + 1\n\n    with (\n        restore_callbacks(),\n        # Observability tries to record coverage, but we don't currently\n        # support concurrent coverage collection, and issue a warning instead.\n        #\n        # I tried to fix this with:\n        #\n        #    warnings.filterwarnings(\n        #        \"ignore\", message=r\".*tool id \\d+ is already taken by tool scrutineer.*\"\n        #    )\n        #\n        # but that had a race condition somehow and sometimes still didn't work?? The\n        # warnings module is not thread-safe until 3.14, I think.\n        with_collect_coverage(value=False),\n    ):\n        run_concurrently(test, n=5)\n\n\ndef test_all_threads_callback():\n    n_threads = 5\n\n    # thread_id: count\n    calls = defaultdict(int)\n\n    def global_callback(observation, thread_id):\n        assert isinstance(observation, (TestCaseObservation, InfoObservation))\n        assert isinstance(thread_id, int)\n\n        calls[thread_id] += 1\n\n    @given(st.integers())\n    def f(n):\n        pass\n\n    with (\n        with_collect_coverage(value=False),\n        with_observability_callback(global_callback, all_threads=True),\n    ):\n        run_concurrently(f, n=n_threads)\n\n    assert len(calls) == n_threads\n    assert all(count == (settings().max_examples + 1) for count in calls.values())\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_one_of.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\nfrom collections.abc import Sequence\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import InvalidArgument\n\nfrom tests.common.debug import assert_no_examples\n\n\ndef test_one_of_empty():\n    e = st.one_of()\n    assert e.is_empty\n    assert_no_examples(e)\n\n\n@given(st.one_of(st.integers().filter(bool)))\ndef test_one_of_filtered(i):\n    assert bool(i)\n\n\n@given(st.one_of(st.just(100).flatmap(st.integers)))\ndef test_one_of_flatmapped(i):\n    assert i >= 100\n\n\ndef test_one_of_single_strategy_is_noop():\n    s = st.integers()\n    assert st.one_of(s) is s\n    assert st.one_of([s]) is s\n\n\ndef test_one_of_without_strategies_suggests_sampled_from():\n    with pytest.raises(\n        InvalidArgument,\n        match=re.escape(\"Did you mean st.sampled_from([1, 2, 3])?\"),\n    ):\n        st.one_of(1, 2, 3)\n\n\n@pytest.mark.parametrize(\n    \"strategy, count\",\n    [\n        (st.one_of(st.integers(), st.integers(), st.integers()), 1),\n        (st.one_of(st.integers(), st.one_of(st.integers(), st.integers())), 2),\n        ((st.integers() | st.integers()) | st.integers(), 1),\n        (st.integers() | (st.integers() | st.integers()), 1),\n        (st.integers() | st.text() | st.booleans(), 1),\n        (st.from_type(int | Sequence[int]), 2),\n    ],\n)\ndef test_one_of_unwrapping(strategy, count):\n    assert repr(strategy).count(\"one_of(\") == count\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_permutations.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.strategies import permutations\n\nfrom tests.common.debug import check_can_generate_examples, minimal\nfrom tests.common.utils import fails_with\n\n\ndef test_can_find_non_trivial_permutation():\n    x = minimal(permutations(list(range(5))), lambda x: x[0] != 0)\n\n    assert x == [1, 0, 2, 3, 4]\n\n\n@given(permutations(list(\"abcd\")))\ndef test_permutation_values_are_permutations(perm):\n    assert len(perm) == 4\n    assert set(perm) == set(\"abcd\")\n\n\n@given(permutations([]))\ndef test_empty_permutations_are_empty(xs):\n    assert xs == []\n\n\n@fails_with(InvalidArgument)\ndef test_cannot_permute_non_sequence_types():\n    check_can_generate_examples(permutations(set()))\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_phases.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import Phase, example, given, settings, strategies as st\nfrom hypothesis.database import ExampleDatabase, InMemoryExampleDatabase\nfrom hypothesis.errors import InvalidArgument\n\nfrom tests.common.utils import skipif_emscripten\n\n\n@example(11)\n@settings(phases=(Phase.explicit,))\n@given(st.integers())\ndef test_only_runs_explicit_examples(i):\n    assert i == 11\n\n\n@example(\"hello world\")\n@settings(phases=(Phase.reuse, Phase.generate, Phase.shrink))\n@given(st.booleans())\ndef test_does_not_use_explicit_examples(i):\n    assert isinstance(i, bool)\n\n\n@skipif_emscripten  # TODO: actually Pytest 9.0, remove this workaround ASAP\n@settings(phases=(Phase.reuse, Phase.shrink), database=InMemoryExampleDatabase())\n@given(st.booleans())\ndef test_this_would_fail_if_you_ran_it(b):\n    raise AssertionError\n\n\n@pytest.mark.parametrize(\n    \"arg,expected\",\n    [\n        (tuple(Phase)[::-1], tuple(Phase)),\n        ([Phase.explicit, Phase.explicit], (Phase.explicit,)),\n    ],\n)\ndef test_sorts_and_dedupes_phases(arg, expected):\n    assert settings(phases=arg).phases == expected\n\n\ndef test_phases_default_to_all():\n    assert settings().phases == tuple(Phase)\n\n\ndef test_does_not_reuse_saved_examples_if_reuse_not_in_phases():\n    class BadDatabase(ExampleDatabase):\n        def save(self, key, value):\n            pass\n\n        def delete(self, key, value):\n            pass\n\n        def fetch(self, key):\n            raise ValueError\n\n        def close(self):\n            pass\n\n    @settings(database=BadDatabase(), phases=(Phase.generate,))\n    @given(st.integers())\n    def test_usage(i):\n        pass\n\n    test_usage()\n\n\ndef test_will_save_when_reuse_not_in_phases():\n    database = InMemoryExampleDatabase()\n\n    assert not database.data\n\n    @settings(database=database, phases=(Phase.generate,))\n    @given(st.integers())\n    def test_usage(i):\n        raise ValueError\n\n    with pytest.raises(ValueError):\n        test_usage()\n\n    (saved,) = (v for k, v in database.data.items() if b\"pareto\" not in k)\n    assert len(saved) == 1\n\n\ndef test_rejects_non_phases():\n    with pytest.raises(InvalidArgument):\n        settings(phases=[\"cabbage\"])\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_posonly_args_py38.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\n\n\n@st.composite\ndef strat(draw, x=0, /):\n    return draw(st.integers(min_value=x))\n\n\n@given(st.data(), st.integers())\ndef test_composite_with_posonly_args(data, min_value):\n    v = data.draw(strat(min_value))\n    assert min_value <= v\n\n\ndef test_preserves_signature():\n    with pytest.raises(TypeError):\n        strat(x=1)\n\n\ndef test_builds_real_pos_only():\n    with pytest.raises(TypeError):\n        st.builds()  # requires a target!\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_pretty.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"This file originates in the IPython project and is made use of under the\nfollowing licensing terms:\n\nThe IPython licensing terms\nIPython is licensed under the terms of the Modified BSD License (also known as\nNew or Revised or 3-Clause BSD), as follows:\n\nCopyright (c) 2008-2014, IPython Development Team\nCopyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>\nCopyright (c) 2001, Janko Hauser <jhauser@zscout.de>\nCopyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this\nlist of conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright notice, this\nlist of conditions and the following disclaimer in the documentation and/or\nother materials provided with the distribution.\n\nNeither the name of the IPython Development Team nor the names of its\ncontributors may be used to endorse or promote products derived from this\nsoftware without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\"\"\"\n\nimport io\nimport re\nimport struct\nimport warnings\nfrom collections import Counter, OrderedDict, defaultdict, deque\nfrom dataclasses import dataclass, field\nfrom enum import Enum, Flag\nfrom functools import partial\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.control import current_build_context\nfrom hypothesis.internal.compat import PYPY\nfrom hypothesis.internal.conjecture.floats import float_to_lex\nfrom hypothesis.internal.floats import SIGNALING_NAN\nfrom hypothesis.vendor import pretty\n\n\nclass MyList:\n    def __init__(self, content):\n        self.content = content\n\n    def _repr_pretty_(self, p, cycle):\n        if cycle:\n            p.text(\"MyList(...)\")\n        else:\n            with p.group(3, \"MyList(\", \")\"):\n                for i, child in enumerate(self.content):\n                    if i:\n                        p.text(\",\")\n                        p.breakable()\n                    else:\n                        p.breakable(\"\")\n                    p.pretty(child)\n\n\nclass MyDict(dict):\n    def _repr_pretty_(self, p, cycle):\n        p.text(\"MyDict(...)\")\n\n\nclass MyObj:\n    def somemethod(self):\n        pass\n\n\nclass Dummy1:\n    def _repr_pretty_(self, p, cycle):\n        p.text(\"Dummy1(...)\")\n\n\nclass Dummy2:\n    _repr_pretty_ = None\n\n    def __repr__(self):\n        return \"Dummy2()\"\n\n\nclass NoModule:\n    pass\n\n\nNoModule.__module__ = None\n\n\nclass Breaking:\n    def _repr_pretty_(self, p, cycle):\n        with p.group(4, \"TG: \", \":\"):\n            p.text(\"Breaking(\")\n            p.break_()\n            p.text(\")\")\n\n\nclass BreakingRepr:\n    def __repr__(self):\n        return \"Breaking(\\n)\"\n\n\nclass BreakingReprParent:\n    def _repr_pretty_(self, p, cycle):\n        with p.group(4, \"TG: \", \":\"):\n            p.pretty(BreakingRepr())\n\n\nclass BadRepr:\n    def __repr__(self):\n        return 1 / 0\n\n\ndef test_list():\n    assert pretty.pretty([]) == \"[]\"\n    assert pretty.pretty([1]) == \"[1]\"\n\n\ndef test_dict():\n    assert pretty.pretty({}) == \"{}\"\n    assert pretty.pretty({1: 1}) == \"{1: 1}\"\n    assert pretty.pretty({1: 1, 0: 0}) == \"{1: 1, 0: 0}\"\n\n    # Check that pretty-printing doesn't trigger a BytesWarning under `python -bb`\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", BytesWarning)\n        x = {\"\": 0, b\"\": 0}\n    assert pretty.pretty(x) == \"{'': 0, b'': 0}\"\n\n\ndef test_tuple():\n    assert pretty.pretty(()) == \"()\"\n    assert pretty.pretty((1,)) == \"(1,)\"\n    assert pretty.pretty((1, 2)) == \"(1, 2)\"\n\n\nclass ReprDict(dict):\n    def __repr__(self):\n        return \"hi\"\n\n\ndef test_dict_with_custom_repr():\n    assert pretty.pretty(ReprDict()) == \"hi\"\n\n\nclass ReprList(list):\n    def __repr__(self):\n        return \"bye\"\n\n\nclass ReprSet(set):\n    def __repr__(self):\n        return \"cat\"\n\n\ndef test_set_with_custom_repr():\n    assert pretty.pretty(ReprSet()) == \"cat\"\n\n\ndef test_list_with_custom_repr():\n    assert pretty.pretty(ReprList()) == \"bye\"\n\n\ndef test_indentation():\n    \"\"\"Test correct indentation in groups.\"\"\"\n    count = 40\n    gotoutput = pretty.pretty(MyList(range(count)))\n    expectedoutput = \"MyList(\\n\" + \",\\n\".join(f\"   {i}\" for i in range(count)) + \")\"\n\n    assert gotoutput == expectedoutput\n\n\ndef test_dispatch():\n    \"\"\"Test correct dispatching: The _repr_pretty_ method for MyDict must be\n    found before the registered printer for dict.\"\"\"\n    gotoutput = pretty.pretty(MyDict())\n    expectedoutput = \"MyDict(...)\"\n\n    assert gotoutput == expectedoutput\n\n\ndef test_callability_checking():\n    \"\"\"Test that the _repr_pretty_ method is tested for callability and skipped\n    if not.\"\"\"\n    gotoutput = pretty.pretty(Dummy2())\n    expectedoutput = \"Dummy2()\"\n\n    assert gotoutput == expectedoutput\n\n\ndef test_sets():\n    \"\"\"Test that set and frozenset use Python 3 formatting.\"\"\"\n    objects = [\n        set(),\n        frozenset(),\n        {1},\n        frozenset([1]),\n        {1, 2},\n        frozenset([1, 2]),\n        {-1, -2, -3},\n    ]\n    expected = [\n        \"set()\",\n        \"frozenset()\",\n        \"{1}\",\n        \"frozenset({1})\",\n        \"{1, 2}\",\n        \"frozenset({1, 2})\",\n        \"{-3, -2, -1}\",\n    ]\n    for obj, expected_output in zip(objects, expected, strict=True):\n        got_output = pretty.pretty(obj)\n        assert got_output == expected_output\n\n\ndef test_unsortable_set():\n    xs = {1, 2, 3, \"foo\", \"bar\", \"baz\", object()}\n    p = pretty.pretty(xs)\n    for x in xs:\n        assert pretty.pretty(x) in p\n\n\ndef test_unsortable_dict():\n    xs = {k: 1 for k in [1, 2, 3, \"foo\", \"bar\", \"baz\", object()]}\n    p = pretty.pretty(xs)\n    for x in xs:\n        assert pretty.pretty(x) in p\n\n\ndef test_pprint_nomod():\n    \"\"\"Test that pprint works for classes with no __module__.\"\"\"\n    output = pretty.pretty(NoModule)\n    assert output == \"NoModule\"\n\n\ndef test_pprint_break():\n    \"\"\"Test that p.break_ produces expected output.\"\"\"\n    output = pretty.pretty(Breaking())\n    expected = \"TG: Breaking(\\n    ):\"\n    assert output == expected\n\n\ndef test_pprint_break_repr():\n    \"\"\"Test that p.break_ is used in repr.\"\"\"\n    output = pretty.pretty(BreakingReprParent())\n    expected = \"TG: Breaking(\\n    ):\"\n    assert output == expected\n\n\ndef test_bad_repr():\n    \"\"\"Don't catch bad repr errors.\"\"\"\n    with pytest.raises(ZeroDivisionError):\n        pretty.pretty(BadRepr())\n\n\nclass BadException(Exception):\n    def __str__(self):\n        return -1  # noqa\n\n\nclass ReallyBadRepr:\n    __module__ = 1\n\n    @property\n    def __class__(self):\n        raise ValueError(\"I am horrible\")\n\n    def __repr__(self):\n        raise BadException\n\n\ndef test_really_bad_repr():\n    with pytest.raises(BadException):\n        pretty.pretty(ReallyBadRepr())\n\n\nclass SA:\n    pass\n\n\nclass SB(SA):\n    pass\n\n\ntry:\n    super(SA).__self__\n\n    def test_super_repr():\n        output = pretty.pretty(super(SA))\n        assert \"SA\" in output\n\n        sb = SB()\n        output = pretty.pretty(super(SA, sb))\n        assert \"SA\" in output\n\nexcept AttributeError:\n\n    def test_super_repr():\n        pretty.pretty(super(SA))\n        sb = SB()\n        pretty.pretty(super(SA, sb))\n\n\ndef test_long_list():\n    lis = list(range(10000))\n    p = pretty.pretty(lis)\n    last2 = p.rsplit(\"\\n\", 2)[-2:]\n    assert last2 == [\" 999,\", \" ...]\"]\n\n\ndef test_long_set():\n    s = set(range(10000))\n    p = pretty.pretty(s)\n    last2 = p.rsplit(\"\\n\", 2)[-2:]\n    assert last2 == [\" 999,\", \" ...}\"]\n\n\ndef test_long_tuple():\n    tup = tuple(range(10000))\n    p = pretty.pretty(tup)\n    last2 = p.rsplit(\"\\n\", 2)[-2:]\n    assert last2 == [\" 999,\", \" ...)\"]\n\n\ndef test_long_dict():\n    d = {n: n for n in range(10000)}\n    p = pretty.pretty(d)\n    last2 = p.rsplit(\"\\n\", 2)[-2:]\n    assert last2 == [\" 999: 999,\", \" ...}\"]\n\n\ndef test_unbound_method():\n    assert pretty.pretty(MyObj.somemethod) == \"somemethod\"\n\n\nclass MetaClass(type):\n    def __new__(metacls, name):\n        return type.__new__(metacls, name, (object,), {\"name\": name})\n\n    def __repr__(cls):\n        return f\"[CUSTOM REPR FOR CLASS {cls.name}]\"\n\n\nClassWithMeta = MetaClass(\"ClassWithMeta\")\n\n\ndef test_metaclass_repr():\n    output = pretty.pretty(ClassWithMeta)\n    assert output == \"[CUSTOM REPR FOR CLASS ClassWithMeta]\"\n\n\ndef test_unicode_repr():\n    u = \"üniçodé\"\n\n    class C:\n        def __repr__(self):\n            return u\n\n    c = C()\n    p = pretty.pretty(c)\n    assert p == u\n    p = pretty.pretty([c])\n    assert p == f\"[{u}]\"\n\n\ndef test_basic_class():\n    def type_pprint_wrapper(obj, p, cycle):\n        if obj is MyObj:\n            type_pprint_wrapper.called = True\n        return pretty._type_pprint(obj, p, cycle)\n\n    type_pprint_wrapper.called = False\n\n    printer = pretty.RepresentationPrinter()\n    printer.type_pprinters[type] = type_pprint_wrapper\n    printer.pretty(MyObj)\n    output = printer.getvalue()\n\n    assert output == f\"{__name__}.MyObj\"\n    assert type_pprint_wrapper.called\n\n\ndef test_collections_defaultdict():\n    # Create defaultdicts with cycles\n    a = defaultdict()\n    a.default_factory = a\n    b = defaultdict(list)\n    b[\"key\"] = b\n\n    # Dictionary order cannot be relied on, test against single keys.\n    cases = [\n        (defaultdict(list), \"defaultdict(list, {})\"),\n        (\n            defaultdict(list, {\"key\": \"-\" * 50}),\n            \"defaultdict(list,\\n\"\n            \"            {'key': '-----------------------------------------\"\n            \"---------'})\",\n        ),\n        (a, \"defaultdict(defaultdict(...), {})\"),\n        (b, \"defaultdict(list, {'key': defaultdict(...)})\"),\n    ]\n    for obj, expected in cases:\n        assert pretty.pretty(obj) == expected\n\n\n@pytest.mark.skipif(PYPY, reason=\"slightly different on PyPy3\")\ndef test_collections_ordereddict():\n    # Create OrderedDict with cycle\n    a = OrderedDict()\n    a[\"key\"] = a\n\n    cases = [\n        (OrderedDict(), \"OrderedDict()\"),\n        (\n            OrderedDict((i, i) for i in range(1000, 1010)),\n            \"OrderedDict([(1000, 1000),\\n\"\n            \"             (1001, 1001),\\n\"\n            \"             (1002, 1002),\\n\"\n            \"             (1003, 1003),\\n\"\n            \"             (1004, 1004),\\n\"\n            \"             (1005, 1005),\\n\"\n            \"             (1006, 1006),\\n\"\n            \"             (1007, 1007),\\n\"\n            \"             (1008, 1008),\\n\"\n            \"             (1009, 1009)])\",\n        ),\n        (a, \"OrderedDict([('key', OrderedDict(...))])\"),\n    ]\n    for obj, expected in cases:\n        assert pretty.pretty(obj) == expected\n\n\ndef test_collections_deque():\n    # Create deque with cycle\n    a = deque()\n    a.append(a)\n\n    cases = [\n        (deque(), \"deque([])\"),\n        (deque([1, 2, 3]), \"deque([1, 2, 3])\"),\n        (\n            deque(i for i in range(1000, 1020)),\n            \"deque([1000,\\n\"\n            \"       1001,\\n\"\n            \"       1002,\\n\"\n            \"       1003,\\n\"\n            \"       1004,\\n\"\n            \"       1005,\\n\"\n            \"       1006,\\n\"\n            \"       1007,\\n\"\n            \"       1008,\\n\"\n            \"       1009,\\n\"\n            \"       1010,\\n\"\n            \"       1011,\\n\"\n            \"       1012,\\n\"\n            \"       1013,\\n\"\n            \"       1014,\\n\"\n            \"       1015,\\n\"\n            \"       1016,\\n\"\n            \"       1017,\\n\"\n            \"       1018,\\n\"\n            \"       1019])\",\n        ),\n        (a, \"deque([deque(...)])\"),\n    ]\n    for obj, expected in cases:\n        assert pretty.pretty(obj) == expected\n\n\ndef test_collections_counter():\n    class MyCounter(Counter):\n        pass\n\n    cases = [\n        (Counter(), \"Counter()\"),\n        (Counter(a=1), \"Counter({'a': 1})\"),\n        (MyCounter(a=1), \"MyCounter({'a': 1})\"),\n    ]\n    for obj, expected in cases:\n        assert pretty.pretty(obj) == expected\n\n\ndef test_cyclic_list():\n    x = []\n    x.append(x)\n    assert pretty.pretty(x) == \"[[...]]\"\n\n\ndef test_cyclic_dequeue():\n    x = deque()\n    x.append(x)\n    assert pretty.pretty(x) == \"deque([deque(...)])\"\n\n\nclass HashItAnyway:\n    def __init__(self, value):\n        self.value = value\n\n    def __hash__(self):\n        return 0\n\n    def __eq__(self, other):\n        return isinstance(other, HashItAnyway) and self.value == other.value\n\n    def __ne__(self, other):\n        return not self.__eq__(other)\n\n    def _repr_pretty_(self, pretty, cycle):\n        pretty.pretty(self.value)\n\n\ndef test_cyclic_counter():\n    c = Counter()\n    k = HashItAnyway(c)\n    c[k] = 1\n    assert pretty.pretty(c) == \"Counter({Counter(...): 1})\"\n\n\ndef test_cyclic_dict():\n    x = {}\n    k = HashItAnyway(x)\n    x[k] = x\n    assert pretty.pretty(x) == \"{{...}: {...}}\"\n\n\ndef test_cyclic_set():\n    x = set()\n    x.add(HashItAnyway(x))\n    assert pretty.pretty(x) == \"{{...}}\"\n\n\nclass BigList(list):\n    def _repr_pretty_(self, printer, cycle):\n        if cycle:\n            return \"[...]\"\n        else:\n            with printer.group(open=\"[\", close=\"]\"), printer.indent(5):\n                for v in self:\n                    printer.pretty(v)\n                    printer.breakable(\",\")\n\n\ndef test_print_with_indent():\n    pretty.pretty(BigList([1, 2, 3]))\n\n\nclass MyException(Exception):\n    pass\n\n\ndef test_exception():\n    assert pretty.pretty(ValueError(\"hi\")) == \"ValueError('hi')\"\n    assert pretty.pretty(ValueError(\"hi\", \"there\")) == \"ValueError('hi', 'there')\"\n    assert \"test_pretty.\" in pretty.pretty(MyException())\n\n\ndef test_re_evals():\n    for r in [\n        re.compile(r\"hi\"),\n        re.compile(r\"b\\nc\", re.MULTILINE),\n        re.compile(rb\"hi\", 0),\n        re.compile(\"foo\", re.MULTILINE | re.UNICODE),\n    ]:\n        r2 = eval(pretty.pretty(r), globals())\n        assert r.pattern == r2.pattern\n        assert r.flags == r2.flags\n\n\ndef test_print_builtin_function():\n    assert pretty.pretty(abs) == \"abs\"\n\n\ndef test_pretty_function():\n    assert pretty.pretty(test_pretty_function) == \"test_pretty_function\"\n\n\ndef test_breakable_at_group_boundary():\n    assert \"\\n\" in pretty.pretty([[], \"0\" * 80])\n\n\n@pytest.mark.parametrize(\n    \"obj, rep\",\n    [\n        (float(\"nan\"), \"nan\"),\n        (-float(\"nan\"), \"-nan\"),\n        (SIGNALING_NAN, \"struct.unpack('d', struct.pack('Q', 0x7ff8000000000001))[0]\"),\n        (-SIGNALING_NAN, \"struct.unpack('d', struct.pack('Q', 0xfff8000000000001))[0]\"),\n    ],\n)\ndef test_nan_reprs(obj, rep):\n    assert pretty.pretty(obj) == rep\n    assert float_to_lex(obj) == float_to_lex(\n        eval(rep, {\"struct\": struct, \"nan\": float(\"nan\")})\n    )\n\n\ndef _repr_call(*args, **kwargs):\n    p = pretty.RepresentationPrinter()\n    p.repr_call(*args, **kwargs)\n    return p.getvalue()\n\n\n@pytest.mark.parametrize(\"func_name\", [\"f\", \"lambda: ...\", \"lambda *args: ...\"])\ndef test_repr_call(func_name):\n    fn = f\"({func_name})\" if func_name.startswith((\"lambda:\", \"lambda \")) else func_name\n    aas = \"a\" * 100\n    assert _repr_call(func_name, (1, 2), {}) == f\"{fn}(1, 2)\"\n    assert _repr_call(func_name, (aas,), {}) == f\"{fn}(\\n    {aas!r},\\n)\"\n    assert _repr_call(func_name, (), {\"a\": 1, \"b\": 2}) == f\"{fn}(a=1, b=2)\"\n    assert _repr_call(func_name, (), {\"x\": aas}) == f\"{fn}(\\n    x={aas!r},\\n)\"\n\n\nclass AnEnum(Enum):\n    SOME_MEMBER = 1\n\n\nclass Options(Flag):\n    A = 1\n    B = 2\n    C = 4\n\n\nclass EvilReprOptions(Flag):\n    A = 1\n    B = 2\n\n    def __repr__(self):\n        return \"can't parse this nonsense\"\n\n\nclass LyingReprOptions(Flag):\n    A = 1\n    B = 2\n\n    def __repr__(self):\n        return \"LyingReprOptions.A|B|C\"\n\n\n@pytest.mark.parametrize(\n    \"rep\",\n    [\n        \"AnEnum.SOME_MEMBER\",\n        \"Options.A\",\n        \"Options.A | Options.B\",\n        \"Options.A | Options.B | Options.C\",\n        \"Options(0)\",\n        \"EvilReprOptions.A\",\n        \"LyingReprOptions.A\",\n        \"EvilReprOptions.A | EvilReprOptions.B\",\n        \"LyingReprOptions.A | LyingReprOptions.B\",\n    ],\n)\ndef test_pretty_prints_enums_as_code(rep):\n    assert pretty.pretty(eval(rep)) == rep\n\n\nclass Obj:\n    def _repr_pretty_(self, p, cycle):\n        \"\"\"Exercise the IPython callback interface.\"\"\"\n        assert not cycle\n        with p.indent(2):\n            p.text(\"abc,\")\n            p.breakable(\" \")\n            p.break_()\n        p.begin_group(8, \"<\")\n        p.end_group(8, \">\")\n\n\ndef test_supports_ipython_callback():\n    assert pretty.pretty(Obj()) == \"abc, \\n  <>\"\n\n\ndef test_pretty_partial_with_cycle():\n    ls = []\n    p = partial(bool, ls)\n    assert pretty.pretty(p) == \"functools.partial(bool, [])\"\n    ls.append(p)\n    assert pretty.pretty(p) == \"functools.partial(bool, [functools.partial(bool, ...)])\"\n\n\nclass InvalidSyntaxRepr:\n    def __init__(self, val=None) -> None:\n        self.val = val\n\n    def __repr__(self):\n        return \"invalid syntax\"\n\n\nclass ValidSyntaxRepr:\n    def __init__(self, val=None) -> None:\n        self.val = val\n\n    def __repr__(self):\n        return \"ValidSyntaxRepr(...)\"\n\n\n@given(st.data())\ndef test_pprint_with_call_or_repr_as_call(data):\n    # mapped pprint repr only triggers for failing examples - which makes an\n    # end to end test given hypothesis difficult. fake our way around it.\n    current_build_context().is_final = True\n\n    x = data.draw(st.none().map(InvalidSyntaxRepr))\n    p = pretty.RepresentationPrinter(context=current_build_context())\n    p.pretty(x)\n    assert p.getvalue() == \"InvalidSyntaxRepr(None)\"\n\n\n@given(st.just(InvalidSyntaxRepr()).map(ValidSyntaxRepr))\ndef test_pprint_with_call_or_repr_as_repr(x):\n    p = pretty.RepresentationPrinter(context=current_build_context())\n    p.pretty(x)\n    assert p.getvalue() == \"ValidSyntaxRepr(...)\"\n\n\n@given(st.data())\ndef test_pprint_map_with_cycle(data):\n    current_build_context().is_final = True\n    x = data.draw(st.just(ValidSyntaxRepr()).map(lambda x: x))\n\n    p = pretty.RepresentationPrinter(context=current_build_context())\n    p.pretty(x)\n    assert p.getvalue() == \"ValidSyntaxRepr(...)\"\n\n\ndef test_pprint_large_integers():\n    p = pretty.RepresentationPrinter()\n    p.pretty(1234567890)\n    assert p.getvalue() == \"1_234_567_890\"\n\n\ndef test_pprint_extremely_large_integers():\n    x = 10**5000  # repr fails with ddos error\n    p = pretty.RepresentationPrinter()\n    p.pretty(x)\n    got = p.getvalue()\n    assert got == f\"{x:#_x}\"  # hexadecimal with underscores\n    assert eval(got) == x\n\n\nclass ReprDetector:\n    def _repr_pretty_(self, p, cycle):\n        \"\"\"Exercise the IPython callback interface.\"\"\"\n        p.text(\"GOOD\")\n\n    def __repr__(self):\n        return \"BAD\"\n\n\n@dataclass\nclass SomeDataClass:\n    x: object\n\n\ndef test_pretty_prints_data_classes():\n    assert pretty.pretty(SomeDataClass(ReprDetector())) == \"SomeDataClass(x=GOOD)\"\n\n\ndef test_handles_cycles_in_dataclass():\n    x = SomeDataClass(x=1)\n    x.x = x\n\n    assert pretty.pretty(x) == \"SomeDataClass(x=SomeDataClass(...))\"\n\n\n@dataclass\nclass DataClassWithNoInitField:\n    x: int\n    y: int = field(init=False)\n\n\ndef test_does_not_include_no_init_fields_in_dataclass_printing():\n    record = DataClassWithNoInitField(x=1)\n    assert pretty.pretty(record) == \"DataClassWithNoInitField(x=1)\"\n    record.y = 1\n    assert pretty.pretty(record) == \"DataClassWithNoInitField(x=1)\"\n\n\nclass Namespace:\n    @dataclass\n    class DC:\n        x: int\n\n    class E(Enum):\n        A = 1\n\n\nNAMESPACED_VALUES = [\n    Namespace.DC(x=1),\n    Namespace.E.A,\n]\n\n\n@pytest.mark.parametrize(\"obj\", NAMESPACED_VALUES, ids=map(repr, NAMESPACED_VALUES))\ndef test_includes_namespace_classes_in_pretty(obj):\n    assert pretty.pretty(obj).startswith(\"Namespace.\")\n\n\nclass Banana:\n    def _repr_pretty_(self, p, cycle):\n        p.text(\"I am a banana\")\n\n\n@dataclass\nclass InheritsPretty(Banana):\n    x: int\n    y: int\n\n\ndef test_uses_defined_pretty_printing_method():\n    assert pretty.pretty(InheritsPretty(x=1, y=2)) == pretty.pretty(Banana())\n\n\ndef test_prefers_singleton_printing_to_repr_pretty():\n    out = io.StringIO()\n    printer = pretty.RepresentationPrinter(out)\n    banana = Banana()\n    printer.singleton_pprinters[id(banana)] = lambda obj, p, cycle: p.text(\n        \"Actually a fish\"\n    )\n    printer.pretty(banana)\n    assert \"Actually a fish\" in out.getvalue()\n\n\ndef test_tuple_pprinter_cycle():\n    # Test that _tuple_pprinter handles cycles correctly\n    from hypothesis.vendor.pretty import _tuple_pprinter\n\n    t = (1, 2, 3)\n    arg_labels = {\"arg[0]\": (0, 1), \"arg[1]\": (1, 2), \"arg[2]\": (2, 3)}\n    pprinter = _tuple_pprinter(arg_labels)\n\n    out = io.StringIO()\n    p = pretty.RepresentationPrinter(out)\n    # Simulate a cycle by adding the tuple's id to the stack\n    p.stack.append(id(t))\n    pprinter(t, p, cycle=True)\n    p.flush()\n    assert out.getvalue() == \"(...)\"\n\n\ndef test_fixeddict_pprinter_cycle():\n    # Test that _fixeddict_pprinter handles cycles correctly\n    from hypothesis.vendor.pretty import _fixeddict_pprinter\n\n    d = {\"a\": 1, \"b\": 2}\n    mapping = {\"a\": None, \"b\": None}  # dummy mapping for key ordering\n    arg_labels = {\"a\": (0, 1), \"b\": (1, 2)}\n    pprinter = _fixeddict_pprinter(arg_labels, mapping)\n\n    out = io.StringIO()\n    p = pretty.RepresentationPrinter(out)\n    # Simulate a cycle by adding the dict's id to the stack\n    p.stack.append(id(d))\n    pprinter(d, p, cycle=True)\n    p.flush()\n    assert out.getvalue() == \"{...}\"\n\n\ndef test_get_slice_comment_skips_already_commented():\n    # Test that _get_slice_comment returns None for already-commented slices\n    from hypothesis.vendor.pretty import _get_slice_comment\n\n    out = io.StringIO()\n    p = pretty.RepresentationPrinter(out)\n    p.slice_comments = {(0, 5): \"or any other generated value\"}\n    # Mark the slice as already commented\n    p._commented_slices.add((0, 5))\n\n    arg_labels = {\"arg[0]\": (0, 5)}\n    # Should return None because slice is already in _commented_slices\n    result = _get_slice_comment(p, arg_labels, \"arg[0]\")\n    assert result is None\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_provisional_strategies.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\nimport string\n\nimport pytest\n\nfrom hypothesis import given, settings\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.provisional import (\n    FRAGMENT_SAFE_CHARACTERS,\n    _url_fragments_strategy,\n    domains,\n    urls,\n)\n\nfrom tests.common.debug import check_can_generate_examples, find_any\n\n\n@given(urls())\ndef test_is_URL(url):\n    allowed_chars = set(string.ascii_letters + string.digits + \"$-_.+!*'(),~%/\")\n    url_schemeless = url.split(\"://\", 1)[1]\n    components = url_schemeless.split(\"#\", 1)\n\n    domain_path = components[0]\n    path = domain_path.split(\"/\", 1)[1] if \"/\" in domain_path else \"\"\n    assert all(c in allowed_chars for c in path)\n    assert all(\n        re.match(\"^[0-9A-Fa-f]{2}\", after_perc) for after_perc in path.split(\"%\")[1:]\n    )\n\n    fragment = components[1] if \"#\" in url_schemeless else \"\"\n    fragment_allowed_chars = allowed_chars | {\"?\"}\n    assert all(c in fragment_allowed_chars for c in fragment)\n    assert all(\n        re.match(\"^[0-9A-Fa-f]{2}\", after_perc)\n        for after_perc in fragment.split(\"%\")[1:]\n    )\n\n\n@pytest.mark.parametrize(\"max_length\", [-1, 0, 3, 4.0, 256])\n@pytest.mark.parametrize(\"max_element_length\", [-1, 0, 4.0, 64, 128])\ndef test_invalid_domain_arguments(max_length, max_element_length):\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(\n            domains(max_length=max_length, max_element_length=max_element_length)\n        )\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"takes ~300s each; the `sampled_from(get_top_level_domains())` decision is realized via iterative comparisons https://github.com/pschanely/CrossHair/issues/332\",\n)\n@pytest.mark.parametrize(\"max_length\", [None, 4, 8, 255])\n@pytest.mark.parametrize(\"max_element_length\", [None, 1, 2, 4, 8, 63])\ndef test_valid_domains_arguments(max_length, max_element_length):\n    check_can_generate_examples(\n        domains(max_length=max_length, max_element_length=max_element_length)\n    )\n\n\n@pytest.mark.parametrize(\"strategy\", [domains(), urls()])\ndef test_find_any_non_empty(strategy):\n    find_any(strategy, lambda s: len(s) > 0)\n\n\n@given(_url_fragments_strategy)\n# There's a lambda in the implementation that only gets run if we generate at\n# least one percent-escape sequence, so we derandomize to ensure that coverage\n# isn't flaky.\n@settings(derandomize=True)\ndef test_url_fragments_contain_legal_chars(fragment):\n    assert fragment.startswith(\"#\")\n\n    # Strip all legal escape sequences. Any remaining % characters were not\n    # part of a legal escape sequence.\n    without_escapes = re.sub(r\"(?ai)%[0-9a-f][0-9a-f]\", \"\", fragment[1:])\n\n    assert set(without_escapes).issubset(FRAGMENT_SAFE_CHARACTERS)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_random_module.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport gc\nimport random\nimport sys\n\nimport pytest\n\nfrom hypothesis import (\n    Phase,\n    core,\n    find,\n    given,\n    register_random,\n    settings,\n    strategies as st,\n)\nfrom hypothesis.errors import HypothesisWarning, InvalidArgument\nfrom hypothesis.internal import entropy\nfrom hypothesis.internal.compat import GRAALPY, PYPY\nfrom hypothesis.internal.entropy import deterministic_PRNG\n\nfrom tests.common.utils import skipif_threading, xfail_if_gil_disabled\n\n\ndef gc_collect():\n    # CPython uses reference counting, so objects (without circular refs)\n    # are collected immediately on `del`, breaking weak references.\n    # Python implementations with other garbage collection strategies may\n    # or may not, so we use this function in tests before counting the\n    # surviving references to ensure that they're deterministic.\n    if PYPY or GRAALPY:\n        gc.collect()\n\n\ndef test_can_seed_random():\n    @settings(phases=(Phase.generate, Phase.shrink))\n    @given(st.random_module())\n    def test(r):\n        raise AssertionError\n\n    with pytest.raises(AssertionError) as err:\n        test()\n    assert \"RandomSeeder(0)\" in \"\\n\".join(err.value.__notes__)\n\n\n@given(st.random_module(), st.random_module())\ndef test_seed_random_twice(r, r2):\n    assert repr(r) == repr(r2)\n\n\n# ideally we would actually raise the global random warning here, but random_module\n# calls seed_all and restore_all inside the deprecate_random_in_strategy context\n# manager, which never sees the global random interference.\n#\n# But it can sometimes see it under multithreading depending on timing. Until\n# we fix this to also warn in this case, just skip on threading.\n@skipif_threading\n@given(st.random_module())\ndef test_does_not_fail_health_check_if_randomness_is_used(r):\n    random.getrandbits(128)\n\n\ndef test_cannot_register_non_Random():\n    with pytest.raises(InvalidArgument):\n        register_random(\"not a Random instance\")\n\n\n@skipif_threading\ndef test_registering_a_Random_is_idempotent():\n    gc_collect()\n    n_registered = len(entropy.RANDOMS_TO_MANAGE)\n    # on 3.14+, python introduced the LOAD_FAST_BORROW opcode, which does\n    # not increment the refcount. Passing a bare r to register_random here on 3.14+\n    # would use LOAD_FAST_BORROW and entropy.py would see a non-increasing refcount\n    # and hard-error. On 3.13 and earlier, this is a warning instead.\n    #\n    # For compatibility with both versions, this test forces a refcount increment\n    # with a redundant container.\n    container = [random.Random()]\n    r = container[0]\n    register_random(r)\n    register_random(r)\n    assert len(entropy.RANDOMS_TO_MANAGE) == n_registered + 1\n    del container\n    del r\n    gc_collect()\n    assert len(entropy.RANDOMS_TO_MANAGE) == n_registered\n\n\ndef test_manages_registered_Random_instance():\n    r = random.Random()\n    register_random(r)\n    state = r.getstate()\n    result = []\n\n    @given(st.integers())\n    def inner(x):\n        v = r.random()\n        if result:\n            assert v == result[0]\n        else:\n            result.append(v)\n\n    inner()\n    assert state == r.getstate()\n\n\ndef test_registered_Random_is_seeded_by_random_module_strategy():\n    r = random.Random()\n    register_random(r)\n    state = r.getstate()\n    results = set()\n    count = 0\n\n    @given(st.integers())\n    def inner(x):\n        nonlocal count\n        results.add(r.random())\n        count += 1\n\n    inner()\n    assert count > len(results) * 0.9, \"too few unique random numbers\"\n    assert state == r.getstate()\n\n\n@given(st.random_module())\n@skipif_threading  # writing to global random state\ndef test_will_actually_use_the_random_seed(rnd):\n    a = random.randint(0, 100)\n    b = random.randint(0, 100)\n    random.seed(rnd.seed)\n    assert a == random.randint(0, 100)\n    assert b == random.randint(0, 100)\n\n\ndef test_given_does_not_pollute_state():\n    with deterministic_PRNG():\n\n        @given(st.random_module())\n        def test(r):\n            pass\n\n        test()\n        state_a = random.getstate()\n        state_a2 = core.threadlocal._hypothesis_global_random.getstate()\n\n        test()\n        state_b = random.getstate()\n        state_b2 = core.threadlocal._hypothesis_global_random.getstate()\n\n        assert state_a == state_b\n        assert state_a2 != state_b2\n\n\n@skipif_threading  # modifying global random state\ndef test_find_does_not_pollute_state():\n    with deterministic_PRNG():\n        find(st.random_module(), lambda r: True)\n        state_a = random.getstate()\n        state_a2 = core.threadlocal._hypothesis_global_random.getstate()\n\n        find(st.random_module(), lambda r: True)\n        state_b = random.getstate()\n        state_b2 = core.threadlocal._hypothesis_global_random.getstate()\n\n        assert state_a == state_b\n        assert state_a2 != state_b2\n\n\n@skipif_threading  # we assume we're the only writer to entropy.RANDOMS_TO_MANAGE\ndef test_evil_prng_registration_nonsense():\n    # my guess is that other tests may register randoms that are then marked for\n    # deletion (but not actually gc'd yet). Therefore, depending on the order tests\n    # are run, RANDOMS_TO_MANAGE may start with more entries than after a gc. To\n    # force a clean slate for this test, unconditionally gc.\n    gc.collect()\n    # The first test to call deterministic_PRNG registers a new random instance.\n    # If that's this test, it will throw off our n_registered count in the middle.\n    # start with a no-op to ensure this registration has occurred.\n    with deterministic_PRNG():\n        pass\n\n    n_registered = len(entropy.RANDOMS_TO_MANAGE)\n    # put inside a list to increment ref count and avoid our warning/error about no\n    # referrers\n    c1, c2, c3 = [random.Random(1)], [random.Random(2)], [random.Random(3)]\n    r1, r2, r3 = c1[0], c2[0], c3[0]\n    s2 = r2.getstate()\n\n    # We're going to be totally evil here: register two randoms, then\n    # drop one and add another, and finally check that we reset only\n    # the states that we collected before we started\n    register_random(r1)\n    k = max(entropy.RANDOMS_TO_MANAGE)  # get a handle to check if r1 still exists\n    register_random(r2)\n    assert len(entropy.RANDOMS_TO_MANAGE) == n_registered + 2\n\n    with deterministic_PRNG():\n        del r1\n        del c1\n        gc_collect()\n        assert k not in entropy.RANDOMS_TO_MANAGE, \"r1 has been garbage-collected\"\n        assert len(entropy.RANDOMS_TO_MANAGE) == n_registered + 1\n\n        r2.seed(4)\n        register_random(r3)\n        r3.seed(4)\n        s4 = r3.getstate()\n\n    # Implicit check, no exception was raised in __exit__\n    assert r2.getstate() == s2, \"reset previously registered random state\"\n    assert r3.getstate() == s4, \"retained state when registered within the context\"\n\n\n@pytest.mark.skipif(\n    PYPY, reason=\"We can't guard against bad no-reference patterns in pypy.\"\n)\ndef test_passing_unreferenced_instance_raises():\n    with pytest.raises(ReferenceError):\n        register_random(random.Random(0))\n\n\n@xfail_if_gil_disabled\n@pytest.mark.skipif(\n    PYPY, reason=\"We can't guard against bad no-reference patterns in pypy.\"\n)\ndef test_passing_unreferenced_instance_within_function_scope_raises():\n    def f():\n        register_random(random.Random(0))\n\n    with pytest.raises(ReferenceError):\n        f()\n\n    # we have two error paths for register_random: one which warns and one which\n    # errors. We use an alias to bump the refcount while not adding a gc referrer,\n    # which covers the warning path.\n    def f():\n        r = random.Random(0)\n        _r2 = r\n        register_random(r)\n\n    with pytest.warns(\n        HypothesisWarning,\n        match=\"It looks like `register_random` was passed an object that could be\"\n        \" garbage collected\",\n    ):\n        f()\n\n\n@xfail_if_gil_disabled\n@pytest.mark.skipif(\n    PYPY, reason=\"We can't guard against bad no-reference patterns in pypy.\"\n)\n@pytest.mark.skipif(\n    sys.version_info[:2] < (3, 14),\n    reason=\"warns instead of raises on 3.13 or earlier due to gc changes\",\n)\ndef test_passing_referenced_instance_within_function_scope_raises():\n    def f():\n        r = random.Random(0)\n        register_random(r)\n\n    with pytest.raises(\n        ReferenceError,\n        match=r\"`register_random` was passed .* which will be garbage collected\",\n    ):\n        f()\n\n\n@pytest.mark.skipif(\n    PYPY, reason=\"We can't guard against bad no-reference patterns in pypy.\"\n)\n@skipif_threading  # we assume we're the only writer to entropy.RANDOMS_TO_MANAGE\ndef test_register_random_within_nested_function_scope():\n    n_registered = len(entropy.RANDOMS_TO_MANAGE)\n\n    def f():\n        # put inside a list to increment ref count and avoid our warning/error about no\n        # referrers\n        container = [random.Random()]\n        r = container[0]\n        register_random(r)\n        assert len(entropy.RANDOMS_TO_MANAGE) == n_registered + 1\n\n    f()\n    gc_collect()\n    assert len(entropy.RANDOMS_TO_MANAGE) == n_registered\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_randoms.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport inspect\nimport math\nfrom copy import copy\n\nimport pytest\n\nfrom hypothesis import HealthCheck, assume, given, settings, strategies as st\nfrom hypothesis.internal.compat import ExceptionGroup\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.strategies._internal.random import (\n    RANDOM_METHODS,\n    ArtificialRandom,\n    HypothesisRandom,\n    TrueRandom,\n    convert_kwargs,\n    normalize_zero,\n)\n\nfrom tests.common.debug import assert_all_examples, find_any\nfrom tests.common.utils import Why, xfail_on_crosshair\n\n\ndef test_implements_all_random_methods():\n    for name in dir(HypothesisRandom):\n        if not name.startswith(\"_\") or name == \"_randbelow\":\n            f = getattr(HypothesisRandom, name)\n            if inspect.isfunction(f):\n                assert f.__module__ == \"hypothesis.strategies._internal.random\", name\n\n\nany_random = st.randoms(use_true_random=False) | st.randoms(use_true_random=True)\n\nbeta_param = st.floats(0.01, 1000)\nseq_param = st.lists(st.integers(), min_size=1)\n\n\nMETHOD_STRATEGIES = {}\n\n\ndef define_method_strategy(name, **kwargs):\n    METHOD_STRATEGIES[name] = kwargs\n\n\ndefine_method_strategy(\"betavariate\", alpha=beta_param, beta=beta_param)\ndefine_method_strategy(\"binomialvariate\", n=st.integers(min_value=1), p=st.floats(0, 1))\ndefine_method_strategy(\"gammavariate\", alpha=beta_param, beta=beta_param)\ndefine_method_strategy(\"weibullvariate\", alpha=beta_param, beta=beta_param)\ndefine_method_strategy(\"choice\", seq=seq_param)\ndefine_method_strategy(\"choices\", population=seq_param, k=st.integers(1, 100))\ndefine_method_strategy(\"expovariate\", lambd=beta_param)\ndefine_method_strategy(\"_randbelow\", n=st.integers(1, 2**64))\ndefine_method_strategy(\"random\")\ndefine_method_strategy(\"getrandbits\", n=st.integers(1, 128))\ndefine_method_strategy(\"gauss\", mu=st.floats(-1000, 1000), sigma=beta_param)\ndefine_method_strategy(\"normalvariate\", mu=st.floats(-1000, 1000), sigma=beta_param)\n# the standard library lognormalvariate is weirdly bad at handling large floats\ndefine_method_strategy(\n    \"lognormvariate\", mu=st.floats(0.1, 10), sigma=st.floats(0.1, 10)\n)\ndefine_method_strategy(\n    \"vonmisesvariate\", mu=st.floats(0, math.pi * 2), kappa=beta_param\n)\n# Small alpha may raise ZeroDivisionError, see https://bugs.python.org/issue41421\ndefine_method_strategy(\"paretovariate\", alpha=st.floats(min_value=1.0))\ndefine_method_strategy(\"shuffle\", x=st.lists(st.integers()))\ndefine_method_strategy(\"randbytes\", n=st.integers(0, 100))\n\n\nINT64 = st.integers(-(2**63), 2**63 - 1)\n\n\n@st.composite\ndef any_call_of_method(draw, method):\n    if method == \"sample\":\n        population = draw(seq_param)\n        k = draw(st.integers(0, len(population)))\n        kwargs = {\"population\": population, \"k\": k}\n    elif method == \"randint\":\n        a = draw(INT64)\n        b = draw(INT64)\n        a, b = sorted((a, b))\n        kwargs = {\"a\": a, \"b\": b}\n    elif method == \"randrange\":\n        a = draw(INT64)\n        b = draw(INT64)\n        assume(a != b)\n        a, b = sorted((a, b))\n        kwargs = {\"start\": a, \"stop\": b, \"step\": draw(st.integers(1, 3))}\n    elif method == \"triangular\":\n        a = normalize_zero(draw(st.floats(allow_infinity=False, allow_nan=False)))\n        b = normalize_zero(draw(st.floats(allow_infinity=False, allow_nan=False)))\n        a, b = sorted((a, b))\n        if draw(st.booleans()):\n            draw(st.floats(a, b))\n        kwargs = {\"low\": a, \"high\": b, \"mode\": None}\n    elif method == \"uniform\":\n        a = normalize_zero(draw(st.floats(allow_infinity=False, allow_nan=False)))\n        b = normalize_zero(draw(st.floats(allow_infinity=False, allow_nan=False)))\n        a, b = sorted((a, b))\n        kwargs = {\"a\": a, \"b\": b}\n    else:\n        kwargs = draw(st.fixed_dictionaries(METHOD_STRATEGIES[method]))\n\n    args, kwargs = convert_kwargs(method, kwargs)\n\n    return (args, kwargs)\n\n\n@st.composite\ndef any_call(draw):\n    method = draw(st.sampled_from(RANDOM_METHODS))\n    return (method, *draw(any_call_of_method(method)))\n\n\n@pytest.mark.parametrize(\"method\", RANDOM_METHODS)\n@given(any_random, st.data())\ndef test_call_all_methods(method, rnd, data):\n    args, kwargs = data.draw(any_call_of_method(method))\n    getattr(rnd, method)(*args, **kwargs)\n\n\n@given(any_random, st.integers(1, 100))\ndef test_rand_below(rnd, n):\n    assert rnd._randbelow(n) < n\n\n\n@given(any_random, beta_param, beta_param)\ndef test_beta_in_range(rnd, a, b):\n    assert 0 <= rnd.betavariate(a, b) <= 1\n\n\ndef test_multiple_randoms_are_unrelated():\n    @given(st.randoms(use_true_random=False), st.randoms(use_true_random=False))\n    def test(r1, r2):\n        assert r1.random() == r2.random()\n\n    with pytest.raises(AssertionError):\n        test()\n\n\n@pytest.mark.parametrize(\"use_true_random\", [False, True])\n@given(data=st.data())\ndef test_randoms_can_be_synced(use_true_random, data):\n    r1 = data.draw(st.randoms(use_true_random=use_true_random))\n    r2 = data.draw(st.randoms(use_true_random=use_true_random))\n    r2.setstate(r1.getstate())\n    assert r1.random() == r2.random()\n\n\n@pytest.mark.parametrize(\"use_true_random\", [False, True])\n@given(data=st.data(), method_call=any_call())\ndef test_seeding_to_same_value_synchronizes(use_true_random, data, method_call):\n    r1 = data.draw(st.randoms(use_true_random=use_true_random))\n    r2 = data.draw(st.randoms(use_true_random=use_true_random))\n    method, args, kwargs = method_call\n    r1.seed(0)\n    r2.seed(0)\n    assert getattr(r1, method)(*args, **kwargs) == getattr(r2, method)(*args, **kwargs)\n\n\n@given(any_random, any_call())\ndef test_copying_synchronizes(r1, method_call):\n    method, args, kwargs = method_call\n    r2 = copy(r1)\n    assert getattr(r1, method)(*args, **kwargs) == getattr(r2, method)(*args, **kwargs)\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)\n@pytest.mark.parametrize(\"use_true_random\", [True, False])\ndef test_seeding_to_different_values_does_not_synchronize(use_true_random):\n    @given(\n        st.randoms(use_true_random=use_true_random),\n        st.randoms(use_true_random=use_true_random),\n    )\n    def test(r1, r2):\n        r1.seed(0)\n        r2.seed(1)\n        assert r1.random() == r2.random()\n\n    with pytest.raises(AssertionError):\n        test()\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)\n@pytest.mark.parametrize(\"use_true_random\", [True, False])\ndef test_unrelated_calls_desynchronizes(use_true_random):\n    @given(\n        st.randoms(use_true_random=use_true_random),\n        st.randoms(use_true_random=use_true_random),\n    )\n    def test(r1, r2):\n        r1.seed(0)\n        r2.seed(0)\n        r1.randrange(1, 10)\n        r2.getrandbits(128)\n        assert r1.random() == r2.random()\n\n    with pytest.raises(AssertionError):\n        test()\n\n\n@given(st.randoms(use_true_random=False), st.randoms(use_true_random=False))\ndef test_state_is_consistent(r1, r2):\n    r2.setstate(r1.getstate())\n    assert r1.getstate() == r2.getstate()\n\n\n@given(st.randoms())\ndef test_does_not_use_true_random_by_default(rnd):\n    assert not isinstance(rnd, TrueRandom)\n\n\n@given(st.randoms(use_true_random=False))\ndef test_handles_singleton_uniforms_correctly(rnd):\n    assert rnd.uniform(1.0, 1.0) == 1.0\n    assert rnd.uniform(0.0, 0.0) == 0.0\n    assert rnd.uniform(-0.0, -0.0) == 0.0\n    assert rnd.uniform(0.0, -0.0) == 0.0\n\n\n@given(st.randoms(use_true_random=False))\ndef test_handles_singleton_regions_of_triangular_correctly(rnd):\n    assert rnd.triangular(1.0, 1.0) == 1.0\n    assert rnd.triangular(0.0, 0.0) == 0.0\n    assert rnd.triangular(-0.0, -0.0) == 0.0\n    assert rnd.triangular(0.0, -0.0) == 0.0\n\n\n@given(st.randoms(use_true_random=False))\ndef test_triangular_with_mode(rnd):\n    x = rnd.triangular(0.0, 1.0, mode=0.5)\n    assert 0.0 <= x <= 1.0\n\n\n@pytest.mark.parametrize(\"use_true_random\", [False, True])\ndef test_outputs_random_calls(use_true_random):\n    @given(st.randoms(use_true_random=use_true_random, note_method_calls=True))\n    def test(rnd):\n        rnd.uniform(0.1, 0.5)\n        raise AssertionError\n\n    with pytest.raises(AssertionError) as err:\n        test()\n    assert \".uniform(0.1, 0.5)\" in \"\\n\".join(err.value.__notes__)\n\n\n@pytest.mark.skipif(\n    \"choices\" not in RANDOM_METHODS,\n    reason=\"choices not supported on this Python version\",\n)\n@pytest.mark.parametrize(\"use_true_random\", [False, True])\ndef test_converts_kwargs_correctly_in_output(use_true_random):\n    @given(st.randoms(use_true_random=use_true_random, note_method_calls=True))\n    def test(rnd):\n        rnd.choices([1, 2, 3, 4], k=2)\n        raise AssertionError\n\n    with pytest.raises(AssertionError) as err:\n        test()\n    assert \".choices([1, 2, 3, 4], k=2)\" in \"\\n\".join(err.value.__notes__)\n\n\n@given(st.randoms(use_true_random=False))\ndef test_some_ranges_are_in_range(rnd):\n    assert 0 <= rnd.randrange(10) < 10\n    assert 11 <= rnd.randrange(11, 20) < 20\n    assert rnd.randrange(1, 100, 3) in range(1, 100, 3)\n    assert rnd.randrange(100, step=3) in range(0, 100, 3)\n\n\ndef test_invalid_range():\n    @given(st.randoms(use_true_random=False))\n    def test(rnd):\n        rnd.randrange(1, 1)\n\n    with pytest.raises(ValueError):\n        test()\n\n\ndef test_invalid_sample():\n    @given(st.randoms(use_true_random=False))\n    def test(rnd):\n        rnd.sample([1, 2], 3)\n\n    with pytest.raises(ValueError):\n        test()\n\n\ndef test_triangular_modes():\n    @settings(report_multiple_bugs=True)\n    @given(st.randoms(use_true_random=False))\n    def test(rnd):\n        x = rnd.triangular(0.0, 1.0, mode=0.5)\n        assert x < 0.5\n        assert x > 0.5\n\n    with pytest.raises(ExceptionGroup):\n        test()\n\n\n@given(st.randoms(use_true_random=False), any_call_of_method(\"sample\"))\ndef test_samples_have_right_length(rnd, sample):\n    (seq, k), _ = sample\n    assert len(rnd.sample(seq, k)) == k\n\n\n@given(st.randoms(use_true_random=False), any_call_of_method(\"choices\"))\ndef test_choices_have_right_length(rnd, choices):\n    args, kwargs = choices\n\n    seq = args[0]\n    k = kwargs.get(\"k\", 1)\n    assert len(rnd.choices(seq, k=k)) == k\n\n\n@given(any_random, st.integers(0, 100))\ndef test_randbytes_have_right_length(rnd, n):\n    assert len(rnd.randbytes(n)) == n\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"takes hours; may get faster after https://github.com/pschanely/CrossHair/issues/332\",\n)\n@given(any_random)\ndef test_can_manage_very_long_ranges_with_step(rnd):\n    i = rnd.randrange(0, 2**256, 3)\n\n    assert i % 3 == 0\n    assert 0 <= i < 2**256\n    assert i in range(0, 2**256, 3)\n\n\n@settings(suppress_health_check=[HealthCheck.too_slow])\n@given(any_random, st.data())\ndef test_range_with_arbitrary_step_is_in_range(rnd, data):\n    endpoints = st.integers(-100, 100)\n    step = data.draw(st.integers(1, 3))\n    start, stop = sorted((data.draw(endpoints), data.draw(endpoints)))\n    assume(start < stop)\n    i = rnd.randrange(start, stop, step)\n    assert i in range(start, stop, step)\n\n\n@given(any_random, st.integers(min_value=1))\ndef test_range_with_only_stop(rnd, n):\n    assert 0 <= rnd.randrange(n) < n\n\n\ndef test_can_find_end_of_range():\n    find_any(\n        st.randoms(use_true_random=False).map(lambda r: r.randrange(0, 11, 2)),\n        lambda n: n == 10,\n    )\n    find_any(\n        st.randoms(use_true_random=False).map(lambda r: r.randrange(0, 10, 2)),\n        lambda n: n == 8,\n    )\n\n\n@given(st.randoms(use_true_random=False))\ndef test_can_sample_from_whole_range(rnd):\n    xs = list(map(str, range(10)))\n    ys = rnd.sample(xs, len(xs))\n    assert sorted(ys) == sorted(xs)\n\n\n@given(st.randoms(use_true_random=False))\ndef test_can_sample_from_large_subset(rnd):\n    xs = list(map(str, range(10)))\n    n = len(xs) // 3\n    ys = rnd.sample(xs, n)\n    assert set(ys).issubset(set(xs))\n    assert len(ys) == len(set(ys)) == n\n\n\n@given(st.randoms(use_true_random=False))\ndef test_can_draw_empty_from_empty_sequence(rnd):\n    assert rnd.sample([], 0) == []\n\n\ndef test_random_includes_zero_excludes_one():\n    strat = st.randoms(use_true_random=False).map(lambda r: r.random())\n    assert_all_examples(strat, lambda x: 0 <= x < 1)\n    find_any(strat, lambda x: x == 0)\n\n\ndef test_betavariate_includes_zero_and_one():\n    # https://github.com/HypothesisWorks/hypothesis/issues/4297#issuecomment-2720144709\n    strat = st.randoms(use_true_random=False).flatmap(\n        lambda r: st.builds(\n            r.betavariate, alpha=st.just(1.0) | beta_param, beta=beta_param\n        )\n    )\n    assert_all_examples(strat, lambda x: 0 <= x <= 1)\n    find_any(strat, lambda x: x == 0)\n    find_any(strat, lambda x: x == 1)\n\n\ndef test_artificial_random_with_already_initialized_states_for_ids():\n    # covering test for calling .getstate when data.states_for_ids is not None.\n    data = ConjectureData.for_choices([])\n    data.states_for_ids = {}\n    r = ArtificialRandom(note_method_calls=False, data=data)\n    r.getstate()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_recursive.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given, note, settings, strategies as st\nfrom hypothesis.errors import HypothesisWarning, InvalidArgument\n\nfrom tests.common.debug import (\n    assert_all_examples,\n    assert_no_examples,\n    check_can_generate_examples,\n    find_any,\n    minimal,\n)\nfrom tests.common.utils import checks_deprecated_behaviour\n\n\n@given(st.recursive(st.booleans(), st.lists, max_leaves=10))\ndef test_respects_leaf_limit(xs):\n    def flatten(x):\n        if isinstance(x, list):\n            return sum(map(flatten, x), [])\n        else:\n            return [x]\n\n    assert len(flatten(xs)) <= 10\n\n\ndef test_can_find_nested():\n    x = minimal(\n        st.recursive(st.booleans(), lambda x: st.tuples(x, x)),\n        lambda x: isinstance(x, tuple) and isinstance(x[0], tuple),\n    )\n\n    assert x == ((False, False), False)\n\n\ndef test_recursive_call_validates_expand_returns_strategies():\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(st.recursive(st.booleans(), lambda x: 1))\n\n\ndef test_recursive_call_validates_base_is_strategy():\n    x = st.recursive(1, lambda x: st.none())\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(x)\n\n\ndef test_can_find_exactly_max_leaves():\n    strat = st.recursive(st.none(), lambda x: st.tuples(x, x), max_leaves=5)\n\n    def enough_leaves(t):\n        print(t)\n        count = 0\n        stack = [t]\n        while stack:\n            s = stack.pop()\n            if s is None:\n                count += 1\n            else:\n                stack.extend(s)\n        return count >= 5\n\n    find_any(strat, enough_leaves)\n\n\n@given(st.recursive(st.none(), lambda x: st.tuples(x, x), max_leaves=1))\ndef test_can_exclude_branching_with_max_leaves(t):\n    assert t is None\n\n\n@given(st.recursive(st.none(), lambda x: st.one_of(x, x)))\ndef test_issue_1502_regression(s):\n    pass\n\n\ndef test_recursive_can_generate_varied_structures():\n    values = st.recursive(st.none(), st.lists)\n\n    find_any(values, lambda x: x is None)\n    find_any(values, lambda x: isinstance(x, list))\n    find_any(\n        values, lambda x: isinstance(x, list) and any(isinstance(y, list) for y in x)\n    )\n\n\n@checks_deprecated_behaviour\ndef test_recursive_can_generate_varied_structures_without_using_leaves():\n    values = st.recursive(st.none(), lambda _: st.lists(st.none()))\n\n    find_any(values, lambda x: x is None)\n    find_any(values, lambda x: isinstance(x, list))\n    # The bad `extend` function means we can't actually recurse!\n    assert_no_examples(\n        values, lambda x: isinstance(x, list) and any(isinstance(y, list) for y in x)\n    )\n\n\n@pytest.mark.parametrize(\n    \"s\",\n    [\n        st.recursive(None, st.lists),\n        st.recursive(st.none(), lambda x: None),\n        st.recursive(st.none(), st.lists, max_leaves=-1),\n        st.recursive(st.none(), st.lists, max_leaves=0),\n        st.recursive(st.none(), st.lists, max_leaves=1.0),\n        st.recursive(st.none(), st.lists, min_leaves=-1),\n        st.recursive(st.none(), st.lists, min_leaves=0),\n        st.recursive(st.none(), st.lists, min_leaves=1.0),\n        st.recursive(st.none(), st.lists, min_leaves=10, max_leaves=5),\n        st.recursive(st.none(), lambda _: st.lists(st.none()), min_leaves=1),\n    ],\n)\ndef test_invalid_args(s):\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(s)\n\n\ndef _count_leaves(tree):\n    if isinstance(tree, tuple):\n        return sum(_count_leaves(child) for child in tree)\n    return 1\n\n\n@given(st.data())\n@settings(max_examples=5, suppress_health_check=[\"filter_too_much\"])\ndef test_respects_min_leaves(data):\n    min_leaves = data.draw(st.integers(1, 20))\n    max_leaves = data.draw(st.integers(min_leaves, 40))\n    note(f\"{min_leaves=}\")\n    note(f\"{max_leaves=}\")\n    s = st.recursive(\n        st.none(),\n        lambda x: st.tuples(x, x),\n        min_leaves=min_leaves,\n        max_leaves=max_leaves,\n    )\n    assert_all_examples(s, lambda tree: min_leaves <= _count_leaves(tree) <= max_leaves)\n\n\n@given(st.recursive(st.none(), lambda x: st.tuples(x, x), min_leaves=5, max_leaves=5))\n@settings(suppress_health_check=[\"filter_too_much\"])\ndef test_can_set_exact_leaf_count(tree):\n    assert _count_leaves(tree) == 5\n\n\ndef test_identity_extend_warns():\n    with pytest.warns(HypothesisWarning, match=\"extend=lambda x: x is a no-op\"):\n        st.recursive(st.none(), lambda x: x).validate()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_reflection.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport sys\nfrom copy import deepcopy\nfrom datetime import time\nfrom functools import partial, wraps\nfrom inspect import Parameter, Signature, signature\nfrom textwrap import dedent\nfrom unittest.mock import MagicMock, Mock, NonCallableMagicMock, NonCallableMock\n\nimport pytest\nfrom pytest import raises\n\nfrom hypothesis import assume, example, given, strategies as st\nfrom hypothesis.errors import HypothesisWarning\nfrom hypothesis.internal import lambda_sources, reflection\nfrom hypothesis.internal.reflection import (\n    convert_keyword_arguments,\n    convert_positional_arguments,\n    define_function_signature,\n    function_digest,\n    get_pretty_function_description,\n    get_signature,\n    is_first_param_referenced_in_function,\n    is_identity_function,\n    is_mock,\n    proxies,\n    repr_call,\n    required_args,\n    source_exec_as_module,\n)\nfrom hypothesis.strategies._internal.lazy import LazyStrategy\n\n\ndef do_conversion_test(f, args, kwargs):\n    result = f(*args, **kwargs)\n\n    cargs, ckwargs = convert_keyword_arguments(f, args, kwargs)\n    assert result == f(*cargs, **ckwargs)\n\n    cargs2, ckwargs2 = convert_positional_arguments(f, args, kwargs)\n    assert result == f(*cargs2, **ckwargs2)\n\n\ndef test_simple_conversion():\n    def foo(a, b, c):\n        return (a, b, c)\n\n    assert convert_keyword_arguments(foo, (1, 2, 3), {}) == ((1, 2, 3), {})\n    assert convert_keyword_arguments(foo, (), {\"a\": 3, \"b\": 2, \"c\": 1}) == (\n        (3, 2, 1),\n        {},\n    )\n\n    do_conversion_test(foo, (1, 0), {\"c\": 2})\n    do_conversion_test(foo, (1,), {\"c\": 2, \"b\": \"foo\"})\n\n\ndef test_leaves_unknown_kwargs_in_dict():\n    def bar(x, **kwargs):\n        pass\n\n    assert convert_keyword_arguments(bar, (1,), {\"foo\": \"hi\"}) == ((1,), {\"foo\": \"hi\"})\n    assert convert_keyword_arguments(bar, (), {\"x\": 1, \"foo\": \"hi\"}) == (\n        (1,),\n        {\"foo\": \"hi\"},\n    )\n    do_conversion_test(bar, (1,), {})\n    do_conversion_test(bar, (), {\"x\": 1, \"y\": 1})\n\n\ndef test_errors_on_bad_kwargs():\n    def bar():\n        pass\n\n    with raises(TypeError):\n        convert_keyword_arguments(bar, (), {\"foo\": 1})\n\n\ndef test_passes_varargs_correctly():\n    def foo(*args):\n        pass\n\n    assert convert_keyword_arguments(foo, (1, 2, 3), {}) == ((1, 2, 3), {})\n\n    do_conversion_test(foo, (1, 2, 3), {})\n\n\ndef test_errors_if_keyword_precedes_positional():\n    def foo(x, y):\n        pass\n\n    with raises(TypeError):\n        convert_keyword_arguments(foo, (1,), {\"x\": 2})\n\n\ndef test_errors_if_not_enough_args():\n    def foo(a, b, c, d=1):\n        pass\n\n    with raises(TypeError):\n        convert_keyword_arguments(foo, (1, 2), {\"d\": 4})\n\n\ndef test_errors_on_extra_kwargs():\n    def foo(a):\n        pass\n\n    with raises(TypeError, match=\"keyword\"):\n        convert_keyword_arguments(foo, (1,), {\"b\": 1})\n\n    with raises(TypeError, match=\"keyword\"):\n        convert_keyword_arguments(foo, (1,), {\"b\": 1, \"c\": 2})\n\n\ndef test_positional_errors_if_too_many_args():\n    def foo(a):\n        pass\n\n    with raises(TypeError, match=\"too many positional arguments\"):\n        convert_positional_arguments(foo, (1, 2), {})\n\n\ndef test_positional_errors_if_too_few_args():\n    def foo(a, b, c):\n        pass\n\n    with raises(TypeError):\n        convert_positional_arguments(foo, (1, 2), {})\n\n\ndef test_positional_does_not_error_if_extra_args_are_kwargs():\n    def foo(a, b, c):\n        pass\n\n    convert_positional_arguments(foo, (1, 2), {\"c\": 3})\n\n\ndef test_positional_errors_if_given_bad_kwargs():\n    def foo(a):\n        pass\n\n    with raises(TypeError, match=\"missing a required argument: 'a'\"):\n        convert_positional_arguments(foo, (), {\"b\": 1})\n\n\ndef test_positional_errors_if_given_duplicate_kwargs():\n    def foo(a):\n        pass\n\n    with raises(TypeError, match=\"multiple values\"):\n        convert_positional_arguments(foo, (2,), {\"a\": 1})\n\n\ndef test_names_of_functions_are_pretty():\n    assert (\n        get_pretty_function_description(test_names_of_functions_are_pretty)\n        == \"test_names_of_functions_are_pretty\"\n    )\n\n\nclass Foo:\n    @classmethod\n    def bar(cls):\n        pass\n\n    def baz(cls):\n        pass\n\n    def __repr__(self):\n        return \"SoNotFoo()\"\n\n\ndef test_class_names_are_not_included_in_class_method_prettiness():\n    assert get_pretty_function_description(Foo.bar) == \"bar\"\n\n\ndef test_repr_is_included_in_bound_method_prettiness():\n    assert get_pretty_function_description(Foo().baz) == \"SoNotFoo().baz\"\n\n\ndef test_class_is_not_included_in_unbound_method():\n    assert get_pretty_function_description(Foo.baz) == \"baz\"\n\n\ndef test_does_not_error_on_confused_sources():\n    def ed(f, *args):\n        return f\n\n    x = ed(\n        lambda x, y: (x * y).conjugate() == x.conjugate() * y.conjugate(),\n        complex,\n        complex,\n    )\n\n    get_pretty_function_description(x)\n\n\ndef test_digests_are_reasonably_unique():\n    assert function_digest(test_simple_conversion) != function_digest(\n        test_does_not_error_on_confused_sources\n    )\n\n\ndef test_digest_returns_the_same_value_for_two_calls():\n    assert function_digest(test_simple_conversion) == function_digest(\n        test_simple_conversion\n    )\n\n\ndef test_can_digest_a_built_in_function():\n    import math\n\n    assert function_digest(math.isnan) != function_digest(range)\n\n\ndef test_can_digest_a_unicode_lambda():\n    function_digest(lambda x: \"☃\" in str(x))\n\n\ndef test_can_digest_a_function_with_no_name():\n    def foo(x, y):\n        pass\n\n    function_digest(partial(foo, 1))\n\n\ndef test_arg_string_is_in_order():\n    def foo(c, a, b, f, a1):\n        pass\n\n    assert repr_call(foo, (1, 2, 3, 4, 5), {}) == \"foo(c=1, a=2, b=3, f=4, a1=5)\"\n    assert (\n        repr_call(foo, (1, 2), {\"b\": 3, \"f\": 4, \"a1\": 5})\n        == \"foo(c=1, a=2, b=3, f=4, a1=5)\"\n    )\n\n\ndef test_varkwargs_are_sorted_and_after_real_kwargs():\n    def foo(d, e, f, **kwargs):\n        pass\n\n    assert (\n        repr_call(foo, (), {\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4, \"e\": 5, \"f\": 6})\n        == \"foo(d=4, e=5, f=6, a=1, b=2, c=3)\"\n    )\n\n\ndef test_varargs_come_without_equals():\n    def foo(a, *args):\n        pass\n\n    assert repr_call(foo, (1, 2, 3, 4), {}) == \"foo(2, 3, 4, a=1)\"\n\n\ndef test_can_mix_varargs_and_varkwargs():\n    def foo(*args, **kwargs):\n        pass\n\n    assert repr_call(foo, (1, 2, 3), {\"c\": 7}) == \"foo(1, 2, 3, c=7)\"\n\n\ndef test_arg_string_does_not_include_unprovided_defaults():\n    def foo(a, b, c=9, d=10):\n        pass\n\n    assert repr_call(foo, (1,), {\"b\": 1, \"d\": 11}) == \"foo(a=1, b=1, d=11)\"\n\n\ndef universal_acceptor(*args, **kwargs):\n    return args, kwargs\n\n\ndef has_one_arg(hello):\n    pass\n\n\ndef has_two_args(hello, world):\n    pass\n\n\ndef has_a_default(x, y, z=1):\n    pass\n\n\ndef has_varargs(*args):\n    pass\n\n\ndef has_kwargs(**kwargs):\n    pass\n\n\n@pytest.mark.parametrize(\"f\", [has_one_arg, has_two_args, has_varargs, has_kwargs])\ndef test_copying_preserves_signature(f):\n    af = get_signature(f)\n    t = define_function_signature(\"foo\", \"docstring\", af)(universal_acceptor)\n    at = get_signature(t)\n    assert af == at\n\n\ndef test_name_does_not_clash_with_function_names():\n    def f():\n        pass\n\n    @define_function_signature(\"f\", \"A docstring for f\", signature(f))\n    def g():\n        pass\n\n    g()\n\n\ndef test_copying_sets_name():\n    f = define_function_signature(\n        \"hello_world\", \"A docstring for hello_world\", signature(has_two_args)\n    )(universal_acceptor)\n    assert f.__name__ == \"hello_world\"\n\n\ndef test_copying_sets_docstring():\n    f = define_function_signature(\n        \"foo\", \"A docstring for foo\", signature(has_two_args)\n    )(universal_acceptor)\n    assert f.__doc__ == \"A docstring for foo\"\n\n\ndef test_uses_defaults():\n    f = define_function_signature(\n        \"foo\", \"A docstring for foo\", signature(has_a_default)\n    )(universal_acceptor)\n    assert f(3, 2) == ((3, 2, 1), {})\n\n\ndef test_uses_varargs():\n    f = define_function_signature(\"foo\", \"A docstring for foo\", signature(has_varargs))(\n        universal_acceptor\n    )\n    assert f(1, 2) == ((1, 2), {})\n\n\nDEFINE_FOO_FUNCTION = \"\"\"\ndef foo(x):\n    return x\n\"\"\"\n\n\ndef test_exec_as_module_execs():\n    m = source_exec_as_module(DEFINE_FOO_FUNCTION)\n    assert m.foo(1) == 1\n\n\ndef test_exec_as_module_caches():\n    assert source_exec_as_module(DEFINE_FOO_FUNCTION) is source_exec_as_module(\n        DEFINE_FOO_FUNCTION\n    )\n\n\ndef test_exec_leaves_sys_path_unchanged():\n    old_path = deepcopy(sys.path)\n    source_exec_as_module(\"hello_world = 42\")\n    assert sys.path == old_path\n\n\ndef test_define_function_signature_works_with_conflicts():\n    def accepts_everything(*args, **kwargs):\n        pass\n\n    define_function_signature(\n        \"hello\",\n        \"A docstring for hello\",\n        Signature(parameters=[Parameter(\"f\", Parameter.POSITIONAL_OR_KEYWORD)]),\n    )(accepts_everything)(1)\n\n    define_function_signature(\n        \"hello\",\n        \"A docstring for hello\",\n        Signature(parameters=[Parameter(\"f\", Parameter.VAR_POSITIONAL)]),\n    )(accepts_everything)(1)\n\n    define_function_signature(\n        \"hello\",\n        \"A docstring for hello\",\n        Signature(parameters=[Parameter(\"f\", Parameter.VAR_KEYWORD)]),\n    )(accepts_everything)()\n\n    define_function_signature(\n        \"hello\",\n        \"A docstring for hello\",\n        Signature(\n            parameters=[\n                Parameter(\"f\", Parameter.POSITIONAL_OR_KEYWORD),\n                Parameter(\"f_3\", Parameter.POSITIONAL_OR_KEYWORD),\n                Parameter(\"f_1\", Parameter.VAR_POSITIONAL),\n                Parameter(\"f_2\", Parameter.VAR_KEYWORD),\n            ]\n        ),\n    )(accepts_everything)(1, 2)\n\n\ndef test_define_function_signature_validates_function_name():\n    define_function_signature(\"hello_world\", None, Signature())\n    with raises(ValueError):\n        define_function_signature(\"hello world\", None, Signature())\n\n\nclass Container:\n    def funcy(self):\n        pass\n\n\ndef test_can_proxy_functions_with_mixed_args_and_varargs():\n    def foo(a, *args):\n        return (a, args)\n\n    @proxies(foo)\n    def bar(*args, **kwargs):\n        return foo(*args, **kwargs)\n\n    assert bar(1, 2) == (1, (2,))\n\n\ndef test_can_delegate_to_a_function_with_no_positional_args():\n    def foo(a, b):\n        return (a, b)\n\n    @proxies(foo)\n    def bar(**kwargs):\n        return foo(**kwargs)\n\n    assert bar(2, 1) == (2, 1)\n\n\n@pytest.mark.parametrize(\n    \"func,args,expected\",\n    [\n        (lambda: None, (), None),\n        (lambda a: a**2, (2,), 4),\n        (lambda *a: a, [1, 2, 3], (1, 2, 3)),\n    ],\n)\ndef test_can_proxy_lambdas(func, args, expected):\n    @proxies(func)\n    def wrapped(*args, **kwargs):\n        return func(*args, **kwargs)\n\n    assert wrapped.__name__ == \"<lambda>\"\n    assert wrapped(*args) == expected\n\n\nclass Snowman:\n    def __repr__(self):\n        return \"☃\"\n\n\nclass BittySnowman:\n    def __repr__(self):\n        return \"☃\"\n\n\ndef test_can_handle_unicode_repr():\n    def foo(x):\n        pass\n\n    assert repr_call(foo, [Snowman()], {}) == \"foo(x=☃)\"\n    assert repr_call(foo, [], {\"x\": Snowman()}) == \"foo(x=☃)\"\n\n\nclass NoRepr:\n    pass\n\n\ndef test_can_handle_repr_on_type():\n    def foo(x):\n        pass\n\n    assert repr_call(foo, [Snowman], {}) == \"foo(x=Snowman)\"\n    assert repr_call(foo, [NoRepr], {}) == \"foo(x=NoRepr)\"\n\n\ndef test_can_handle_repr_of_none():\n    def foo(x):\n        pass\n\n    assert repr_call(foo, [None], {}) == \"foo(x=None)\"\n    assert repr_call(foo, [], {\"x\": None}) == \"foo(x=None)\"\n\n\ndef test_kwargs_appear_in_arg_string():\n    def varargs(*args, **kwargs):\n        pass\n\n    assert \"x=1\" in repr_call(varargs, (), {\"x\": 1})\n\n\ndef test_is_mock_with_negative_cases():\n    assert not is_mock(None)\n    assert not is_mock(1234)\n    assert not is_mock(is_mock)\n    assert not is_mock(BittySnowman())\n    assert not is_mock(\"foobar\")\n    assert not is_mock(Mock(spec=BittySnowman))\n    assert not is_mock(MagicMock(spec=BittySnowman))\n\n\ndef test_is_mock_with_positive_cases():\n    assert is_mock(Mock())\n    assert is_mock(MagicMock())\n    assert is_mock(NonCallableMock())\n    assert is_mock(NonCallableMagicMock())\n\n\nclass Target:\n    def __init__(self, a, b):\n        pass\n\n    def method(self, a, b):\n        pass\n\n\n@pytest.mark.parametrize(\"target\", [Target, Target(1, 2).method])\n@pytest.mark.parametrize(\n    \"args,kwargs,expected\",\n    [\n        ((), {}, set(\"ab\")),\n        ((1,), {}, set(\"b\")),\n        ((1, 2), {}, set()),\n        ((), {\"a\": 1}, set(\"b\")),\n        ((), {\"b\": 2}, set(\"a\")),\n        ((), {\"a\": 1, \"b\": 2}, set()),\n    ],\n)\ndef test_required_args(target, args, kwargs, expected):\n    # Mostly checking that `self` (and only self) is correctly excluded\n    assert required_args(target, args, kwargs) == expected\n\n\ndef test_can_handle_unicode_identifier_in_same_line_as_lambda_def():\n    # fmt: off\n    pi = \"π\"; is_str_pi = lambda x: x == pi  # noqa: E702\n    # fmt: on\n    assert get_pretty_function_description(is_str_pi) == \"lambda x: x == pi\"\n\n\ndef test_too_many_posargs_fails():\n    with pytest.raises(TypeError):\n        st.times(time.min, time.max, st.none(), st.none()).validate()\n\n\ndef test_overlapping_posarg_kwarg_fails():\n    with pytest.raises(TypeError):\n        st.times(time.min, time.max, st.none(), timezones=st.just(None)).validate()\n\n\ndef test_inline_given_handles_self():\n    # Regression test for https://github.com/HypothesisWorks/hypothesis/issues/961\n    class Cls:\n        def method(self, **kwargs):\n            assert isinstance(self, Cls)\n            assert kwargs[\"k\"] is sentinel\n\n    sentinel = object()\n    given(k=st.just(sentinel))(Cls().method)()\n\n\ndef logged(f):\n    @wraps(f)\n    def wrapper(*a, **kw):\n        return f(*a, **kw)\n\n    return wrapper\n\n\nclass Bar:\n    @logged\n    def __init__(self, i: int):\n        pass\n\n\n@given(st.builds(Bar))\ndef test_issue_2495_regression(_):\n    \"\"\"See https://github.com/HypothesisWorks/hypothesis/issues/2495\"\"\"\n\n\n@pytest.mark.skipif(\n    sys.version_info[:2] >= (3, 11),\n    reason=\"handled upstream in https://github.com/python/cpython/pull/92065\",\n)\ndef test_error_on_keyword_parameter_name():\n    def f(source):\n        pass\n\n    f.__signature__ = Signature(\n        parameters=[Parameter(\"from\", Parameter.KEYWORD_ONLY)],\n        return_annotation=Parameter.empty,\n    )\n\n    with pytest.raises(ValueError, match=\"SyntaxError because `from` is a keyword\"):\n        get_signature(f)\n\n\ndef test_param_is_called_within_func():\n    def f(any_name):\n        any_name()\n\n    assert is_first_param_referenced_in_function(f)\n\n\ndef test_param_is_called_within_subfunc():\n    def f(any_name):\n        def f2():\n            any_name()\n\n    assert is_first_param_referenced_in_function(f)\n\n\ndef test_param_is_not_called_within_func():\n    def f(any_name):\n        pass\n\n    assert not is_first_param_referenced_in_function(f)\n\n\ndef test_param_called_within_defaults_on_error():\n    # Create a function object for which we cannot retrieve the source.\n    f = compile(\"lambda: ...\", \"_.py\", \"eval\")\n    assert is_first_param_referenced_in_function(f)\n\n\ndef _prep_source(*pairs):\n    return [\n        pytest.param(\n            dedent(x).strip(), dedent(y).strip().encode(), id=f\"case-{i}\", marks=marks\n        )\n        for i, (x, y, *marks) in enumerate(pairs)\n    ]\n\n\n@pytest.mark.parametrize(\n    \"src, clean\",\n    _prep_source(\n        (\"\", \"\"),\n        (\"def test(): pass\", \"def test(): pass\"),\n        (\"def invalid syntax\", \"def invalid syntax\"),\n        (\"def also invalid(\", \"def also invalid(\"),\n        (\n            \"\"\"\n            @example(1)\n            @given(st.integers())\n            def test(x):\n                # line comment\n                assert x  # end-of-line comment\n\n\n                \"Had some blank lines above\"\n            \"\"\",\n            \"\"\"\n            def test(x):\n                assert x\n                \"Had some blank lines above\"\n            \"\"\",\n        ),\n        (\n            \"\"\"\n            @dec\n            async def f():\n                pass\n            \"\"\",\n            \"\"\"\n            async def f():\n                pass\n            \"\"\",\n        ),\n    ),\n)\ndef test_clean_source(src, clean):\n    assert reflection._clean_source(src).splitlines() == clean.splitlines()\n\n\ndef test_overlong_repr_warns():\n    with pytest.warns(HypothesisWarning, match=\"overly large\"):\n        repr(LazyStrategy(st.one_of, [st.none()] * 10000, {}))\n\n\ndef identity(x):\n    return x\n\n\nclass Identity:\n    def __call__(self, x):\n        return x\n\n    def instance_identity(self, x):\n        return x\n\n    def instance_self(self):\n        return self\n\n    @staticmethod\n    def static_identity(x):\n        return x\n\n    @classmethod\n    def class_identity(cls, x):\n        return x\n\n\n@pytest.mark.parametrize(\n    \"f\",\n    [\n        lambda x: x,\n        identity,\n        Identity(),\n        Identity().instance_identity,\n        Identity.static_identity,\n        Identity.class_identity,\n    ],\n)\ndef test_is_identity(f):\n    assert is_identity_function(f)\n\n\n@example(Identity().instance_self)\n@example(lambda x, y: x)\n@example(lambda: None)\n@given(st.functions(like=identity, returns=st.from_type(type).flatmap(st.from_type)))\ndef test_is_not_identity(f):\n    obj = object()\n    try:\n        assume(f(obj) is not obj)  # not necessary but ...\n    except TypeError:\n        pass\n    assert not is_identity_function(f)\n\n\n@pytest.mark.parametrize(\n    \"f\",\n    [\n        lambda x, y=None: x,  # this one would be fairly easy to recognize\n        lambda x, y=None: y or x,  # ... but the general case is impossible\n    ],\n)\ndef test_is_unrecognized_identity(f):\n    assert not is_identity_function(f)\n\n\ndef test_cache_key_size_is_bounded():\n    # Modify co_consts because (\"c\" * 1000) may not be evaluated at compile time\n    f = lambda x=\"a\" * 1000, *, y=\"b\" * 1000: \"c\"\n    f.__code__ = f.__code__.replace(\n        co_consts=tuple(c * 1000 if c == \"c\" else c for c in f.__code__.co_consts)\n    )\n    assert len(repr(lambda_sources._function_key(f))) > 3000\n    assert len(repr(lambda_sources._function_key(f, bounded_size=True))) < 1000\n\n\ndef test_function_key_distinguishes_alpha_renames():\n    # these terms are equivalent under the lambda calculus, but their\n    # representations are not, so they should be cached differently.\n    assert lambda_sources._function_key(lambda x: x) != lambda_sources._function_key(\n        lambda y: y\n    )\n\n\ndef test_import():\n    import time as t\n\n    f = lambda: t.ctime()\n    assert get_pretty_function_description(f) == \"lambda: t.ctime()\"\n\n\n@pytest.mark.parametrize(\"nop_on_f\", [True, False])\ndef test_code_normalization(nop_on_f):\n    f = lambda x: x\n    g = lambda x: x\n    h = f if nop_on_f else g\n    assert lambda_sources._function_key(f) == lambda_sources._function_key(g)\n\n    # Append a NOP to one of the bytecodes\n    NOP_instr = bytes([lambda_sources._op.NOP, 0])\n    h.__code__ = h.__code__.replace(co_code=h.__code__.co_code + NOP_instr)\n    assert lambda_sources._function_key(f) != lambda_sources._function_key(g)\n\n    # ...and then normalize g to match f (adding or removing a NOP)\n    g.__code__ = lambda_sources._normalize_code(f, g)\n    assert lambda_sources._function_key(f) == lambda_sources._function_key(g)\n\n\n@pytest.mark.parametrize(\n    \"f, source\",\n    [\n        (lambda x=1, *, y=2: (x, y), \"lambda x=1, *, y=2: (x, y)\"),\n        (lambda x=1, *, y: (x, y), \"lambda x=1, *, y: (x, y)\"),\n        (lambda x, *, y=2: (x, y), \"lambda x, *, y=2: (x, y)\"),\n        (lambda x, *, y: (x, y), \"lambda x, *, y: (x, y)\"),\n        (lambda *, y=2: (x, y), \"lambda *, y=2: (x, y)\"),  # noqa: F821\n        (lambda *, y: (x, y), \"lambda *, y: (x, y)\"),  # noqa: F821\n        (lambda x, /, y=1: (x, y), \"lambda x, /, y=1: (x, y)\"),\n        (lambda x, /, y: (x, y), \"lambda x, /, y: (x, y)\"),\n        (lambda x, /: (x, y), \"lambda x, /: (x, y)\"),  # noqa: F821\n        (lambda x=1, /, y=2: (x, y), \"lambda x=1, /, y=2: (x, y)\"),\n        (lambda x=1, /: (x, y), \"lambda x=1, /: (x, y)\"),  # noqa: F821\n    ],\n)\ndef test_lambda_mimicry_with_arg_defaults(f, source):\n    assert get_pretty_function_description(f) == source\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_regex.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\nimport sys\nimport unicodedata\n\nimport pytest\n\nfrom hypothesis import HealthCheck, assume, given, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.compat import PYPY\nfrom hypothesis.strategies._internal.regex import (\n    SPACE_CHARS,\n    UNICODE_DIGIT_CATEGORIES,\n    UNICODE_SPACE_CATEGORIES,\n    UNICODE_SPACE_CHARS,\n    UNICODE_WORD_CATEGORIES,\n    base_regex_strategy,\n    regex_strategy,\n)\n\nfrom tests.common.debug import (\n    assert_all_examples,\n    assert_no_examples,\n    check_can_generate_examples,\n    find_any,\n)\n\n\ndef is_ascii(s):\n    return all(ord(c) < 128 for c in s)\n\n\ndef is_digit(s):\n    return all(unicodedata.category(c) in UNICODE_DIGIT_CATEGORIES for c in s)\n\n\ndef is_space(s):\n    return all(c in SPACE_CHARS for c in s)\n\n\ndef is_unicode_space(s):\n    return all(\n        unicodedata.category(c) in UNICODE_SPACE_CATEGORIES or c in UNICODE_SPACE_CHARS\n        for c in s\n    )\n\n\ndef is_word(s):\n    return all(\n        c == \"_\" or unicodedata.category(c) in UNICODE_WORD_CATEGORIES for c in s\n    )\n\n\ndef ascii_regex(pattern):\n    return re.compile(pattern, re.ASCII)\n\n\ndef unicode_regex(pattern):\n    return re.compile(pattern, re.UNICODE)\n\n\ndef _test_matching_pattern(pattern, *, isvalidchar, is_unicode=False):\n    r = unicode_regex(pattern) if is_unicode else ascii_regex(pattern)\n\n    codepoints = range(sys.maxunicode + 1) if is_unicode else range(1, 128)\n    for c in [chr(x) for x in codepoints]:\n        if isvalidchar(c):\n            msg = \"%r supposed to match %r (%r, category %r), but it doesn't\"\n            assert r.search(c), msg % (pattern, c, c, unicodedata.category(c))\n        else:\n            assert not r.search(c), (\n                f'\"{pattern}\" supposed not to match {c!r} (category '\n                f\"{unicodedata.category(c)!r}), but it does\"\n            )\n\n\n@pytest.mark.parametrize(\n    \"category,predicate\", [(r\"\\w\", is_word), (r\"\\d\", is_digit), (r\"\\s\", None)]\n)\n@pytest.mark.parametrize(\"invert\", [False, True])\n@pytest.mark.parametrize(\"is_unicode\", [False, True])\ndef test_matching(category, predicate, invert, is_unicode):\n    if predicate is None:\n        # Special behaviour due to \\x1c, INFORMATION SEPARATOR FOUR\n        predicate = is_unicode_space if is_unicode else is_space\n    if invert:\n        category = category.swapcase()\n\n        def pred(s):\n            return not predicate(s)\n\n    else:\n        pred = predicate\n\n    _test_matching_pattern(category, isvalidchar=pred, is_unicode=is_unicode)\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"takes ~30s each; CrossHair strings just aren't fast enough\",\n)\n@pytest.mark.parametrize(\n    \"pattern\",\n    [\n        \".\",  # anything\n        \"a\",\n        \"abc\",\n        \"[a][b][c]\",\n        \"[^a][^b][^c]\",  # literals\n        \"[a-z0-9_]\",\n        \"[^a-z0-9_]\",  # range and negative range\n        \"ab?\",\n        \"ab*\",\n        \"ab+\",  # quantifiers\n        \"ab{5}\",\n        \"ab{5,10}\",\n        \"ab{,10}\",\n        \"ab{5,}\",  # repeaters\n        \"ab|cd|ef\",  # branch\n        \"(foo)+\",\n        \"(['\\\"])[a-z]+\\\\1\",\n        \"(?:[a-z])(['\\\"])[a-z]+\\\\1\",\n        \"(?P<foo>['\\\"])[a-z]+(?P=foo)\",  # groups\n        \"^abc\",  # beginning\n        \"\\\\d\",\n        \"[\\\\d]\",\n        \"[^\\\\D]\",\n        \"\\\\w\",\n        \"[\\\\w]\",\n        \"[^\\\\W]\",\n        \"\\\\s\",\n        \"[\\\\s]\",\n        \"[^\\\\S]\",  # categories\n    ],\n)\n@pytest.mark.parametrize(\"encode\", [None, False, True])\ndef test_can_generate(pattern, encode):\n    alphabet = st.characters(max_codepoint=1000) if encode is None else None\n    if encode:\n        pattern = pattern.encode(\"ascii\")\n    assert_all_examples(\n        st.from_regex(pattern, alphabet=alphabet),\n        re.compile(pattern).search,\n        settings=settings(suppress_health_check=[HealthCheck.data_too_large]),\n    )\n\n\n@pytest.mark.parametrize(\n    \"pattern\",\n    [\n        re.compile(\"\\\\Aa\\\\Z\", re.IGNORECASE),\n        \"(?i)\\\\Aa\\\\Z\",\n        re.compile(\"\\\\A[ab]\\\\Z\", re.IGNORECASE),\n        \"(?i)\\\\A[ab]\\\\Z\",\n    ],\n)\ndef test_literals_with_ignorecase(pattern):\n    strategy = st.from_regex(pattern)\n\n    find_any(strategy, lambda s: s == \"a\")\n    find_any(strategy, lambda s: s == \"A\")\n\n\n@pytest.mark.parametrize(\n    \"pattern\", [re.compile(\"\\\\A[^a][^b]\\\\Z\", re.IGNORECASE), \"(?i)\\\\A[^a][^b]\\\\Z\"]\n)\ndef test_not_literal_with_ignorecase(pattern):\n    assert_all_examples(\n        st.from_regex(pattern),\n        lambda s: s[0] not in (\"a\", \"A\") and s[1] not in (\"b\", \"B\"),\n    )\n\n\ndef test_any_doesnt_generate_newline():\n    assert_all_examples(st.from_regex(\"\\\\A.\\\\Z\"), lambda s: s != \"\\n\")\n\n\n@pytest.mark.parametrize(\"pattern\", [re.compile(\"\\\\A.\\\\Z\", re.DOTALL), \"(?s)\\\\A.\\\\Z\"])\ndef test_any_with_dotall_generate_newline(pattern):\n    find_any(st.from_regex(pattern), lambda s: s == \"\\n\", settings(max_examples=10**6))\n\n\n@pytest.mark.parametrize(\"pattern\", [re.compile(b\"\\\\A.\\\\Z\", re.DOTALL), b\"(?s)\\\\A.\\\\Z\"])\ndef test_any_with_dotall_generate_newline_binary(pattern):\n    find_any(st.from_regex(pattern), lambda s: s == b\"\\n\", settings(max_examples=10**6))\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"takes ~30s each; CrossHair strings just aren't fast enough\",\n)\n@pytest.mark.parametrize(\n    \"pattern\",\n    [\"\\\\d\", \"[\\\\d]\", \"[^\\\\D]\", \"\\\\w\", \"[\\\\w]\", \"[^\\\\W]\", \"\\\\s\", \"[\\\\s]\", \"[^\\\\S]\"],\n)\n@pytest.mark.parametrize(\"is_unicode\", [False, True])\n@pytest.mark.parametrize(\"invert\", [False, True])\ndef test_groups(pattern, is_unicode, invert):\n    if \"d\" in pattern.lower():\n        group_pred = is_digit\n    elif \"w\" in pattern.lower():\n        group_pred = is_word\n    else:\n        # Special behaviour due to \\x1c, INFORMATION SEPARATOR FOUR\n        group_pred = is_unicode_space if is_unicode else is_space\n\n    if invert:\n        pattern = pattern.swapcase()\n        _p = group_pred\n\n        def group_pred(s):\n            return not _p(s)\n\n    pattern = f\"^{pattern}\\\\Z\"\n\n    compiler = unicode_regex if is_unicode else ascii_regex\n    strategy = st.from_regex(compiler(pattern))\n\n    find_any(strategy.filter(group_pred), is_ascii)\n    if is_unicode:\n        find_any(strategy, lambda s: group_pred(s) and not is_ascii(s))\n\n    assert_all_examples(strategy, group_pred)\n\n\ndef test_caret_in_the_middle_does_not_generate_anything():\n    r = re.compile(\"a^b\")\n\n    assert_no_examples(st.from_regex(r))\n\n\ndef test_end_with_terminator_does_not_pad():\n    assert_all_examples(st.from_regex(\"abc\\\\Z\"), lambda x: x[-3:] == \"abc\")\n\n\ndef test_end():\n    strategy = st.from_regex(\"\\\\Aabc$\")\n\n    find_any(strategy, lambda s: s == \"abc\")\n    find_any(strategy, lambda s: s == \"abc\\n\")\n\n\ndef test_groupref_exists():\n    assert_all_examples(\n        st.from_regex(\"^(<)?a(?(1)>)$\"), lambda s: s in (\"a\", \"a\\n\", \"<a>\", \"<a>\\n\")\n    )\n    assert_all_examples(\n        st.from_regex(\"^(a)?(?(1)b|c)$\"), lambda s: s in (\"ab\", \"ab\\n\", \"c\", \"c\\n\")\n    )\n\n\ndef test_impossible_negative_lookahead():\n    assert_no_examples(st.from_regex(\"(?!foo)foo\"))\n\n\n@given(st.from_regex(\"(\\\\Afoo\\\\Z)\"))\ndef test_can_handle_boundaries_nested(s):\n    assert s == \"foo\"\n\n\ndef test_groupref_not_shared_between_regex():\n    # If group references are (incorrectly!) shared between regex, this would\n    # fail as the would only be one reference.\n    check_can_generate_examples(\n        st.tuples(st.from_regex(\"(a)\\\\1\"), st.from_regex(\"(b)\\\\1\"))\n    )\n\n\n@pytest.mark.skipif(\n    PYPY,  # Skip for now so we can test the rest\n    reason=r\"Triggers bugs in poor handling of unicode in re for these implementations\",\n)\n@given(st.data())\ndef test_group_ref_is_not_shared_between_identical_regex(data):\n    pattern = re.compile(\"^(.+)\\\\1\\\\Z\", re.UNICODE)\n    x = data.draw(base_regex_strategy(pattern, alphabet=st.characters()))\n    y = data.draw(base_regex_strategy(pattern, alphabet=st.characters()))\n    assume(x != y)\n    assert pattern.match(x).end() == len(x)\n    assert pattern.match(y).end() == len(y)\n\n\n@given(st.data())\ndef test_does_not_leak_groups(data):\n    a = data.draw(base_regex_strategy(re.compile(\"^(a)\\\\Z\"), alphabet=st.characters()))\n    assert a == \"a\"\n    b = data.draw(\n        base_regex_strategy(re.compile(\"^(?(1)a|b)(.)\\\\Z\"), alphabet=st.characters())\n    )\n    assert b[0] == \"b\"\n\n\ndef test_positive_lookbehind():\n    find_any(st.from_regex(\".*(?<=ab)c\"), lambda s: s.endswith(\"abc\"))\n\n\ndef test_positive_lookahead():\n    find_any(st.from_regex(\"a(?=bc).*\"), lambda s: s.startswith(\"abc\"))\n\n\ndef test_negative_lookbehind():\n    # no efficient support\n    strategy = st.from_regex(\"[abc]*(?<!abc)d\")\n\n    assert_all_examples(strategy, lambda s: not s.endswith(\"abcd\"))\n    assert_no_examples(strategy, lambda s: s.endswith(\"abcd\"))\n\n\ndef test_negative_lookahead():\n    # no efficient support\n    strategy = st.from_regex(\"^ab(?!cd)[abcd]*\")\n\n    assert_all_examples(strategy, lambda s: not s.startswith(\"abcd\"))\n    assert_no_examples(strategy, lambda s: s.startswith(\"abcd\"))\n\n\n@given(st.from_regex(\"^a+\\\\Z\"))\ndef test_generates_only_the_provided_characters_given_boundaries(xs):\n    assert set(xs) == {\"a\"}\n\n\n@given(st.from_regex(\"^(.)?\\\\1\\\\Z\"))\ndef test_group_backref_may_not_be_present(s):\n    assert len(s) == 2\n    assert s[0] == s[1]\n\n\ndef test_subpattern_flags():\n    strategy = st.from_regex(\"(?i)\\\\Aa(?-i:b)\\\\Z\")\n\n    # \"a\" is case insensitive\n    find_any(strategy, lambda s: s[0] == \"a\")\n    find_any(strategy, lambda s: s[0] == \"A\")\n    # \"b\" is case sensitive\n    find_any(strategy, lambda s: s[1] == \"b\")\n\n    assert_no_examples(strategy, lambda s: s[1] == \"B\")\n\n\ndef test_can_handle_binary_regex_which_is_not_ascii():\n    bad = b\"\\xad\"\n    assert_all_examples(st.from_regex(bad), lambda x: bad in x)\n\n\n@pytest.mark.parametrize(\"pattern\", [b\".\", \".\"])\ndef test_regex_have_same_type_as_pattern(pattern):\n    @given(st.from_regex(pattern))\n    def test_result_type(s):\n        assert type(s) == type(pattern)\n\n    test_result_type()\n\n\ndef test_can_pad_strings_arbitrarily():\n    find_any(st.from_regex(\"a\"), lambda x: x[0] != \"a\")\n    find_any(st.from_regex(\"a\"), lambda x: x[-1] != \"a\")\n\n\ndef test_can_pad_empty_strings():\n    find_any(st.from_regex(\"\"), bool)\n    find_any(st.from_regex(b\"\"), bool)\n\n\ndef test_can_pad_strings_with_newlines():\n    find_any(st.from_regex(\"^$\"), bool)\n    find_any(st.from_regex(b\"^$\"), bool)\n\n\ndef test_given_multiline_regex_can_insert_after_dollar():\n    find_any(\n        st.from_regex(re.compile(\"\\\\Ahi$\", re.MULTILINE)),\n        lambda x: \"\\n\" in x and x.split(\"\\n\")[1],\n    )\n\n\ndef test_given_multiline_regex_can_insert_before_caret():\n    find_any(\n        st.from_regex(re.compile(\"^hi\\\\Z\", re.MULTILINE)),\n        lambda x: \"\\n\" in x and x.split(\"\\n\")[0],\n    )\n\n\ndef test_does_not_left_pad_beginning_of_string_marker():\n    assert_all_examples(st.from_regex(\"\\\\Afoo\"), lambda x: x.startswith(\"foo\"))\n\n\ndef test_bare_caret_can_produce():\n    find_any(st.from_regex(\"^\"), bool)\n\n\ndef test_bare_dollar_can_produce():\n    find_any(st.from_regex(\"$\"), bool)\n\n\ndef test_shared_union():\n    # This gets parsed as [(ANY, None), (BRANCH, (None, [[], []]))], the\n    # interesting feature of which is that it contains empty sub-expressions\n    # in the branch.\n    find_any(st.from_regex(\".|.\"))\n\n\n@given(st.data())\ndef test_issue_992_regression(data):\n    strat = st.from_regex(\n        re.compile(\n            r\"\"\"\\d +  # the integral part\n            \\.    # the decimal point\n            \\d *  # some fractional digits\"\"\",\n            re.VERBOSE,\n        )\n    )\n    data.draw(strat)\n\n\n@pytest.mark.parametrize(\n    \"pattern,matching_str\",\n    [\n        (\"a\", \"a\"),\n        (\"[Aa]\", \"A\"),\n        (\"[ab]*\", \"abb\"),\n        (b\"[Aa]\", b\"A\"),\n        (b\"[ab]*\", b\"abb\"),\n        (re.compile(\"[ab]*\", re.IGNORECASE), \"aBb\"),\n        (re.compile(b\"[ab]\", re.IGNORECASE), b\"A\"),\n    ],\n)\ndef test_fullmatch_generates_example(pattern, matching_str):\n    find_any(\n        st.from_regex(pattern, fullmatch=True),\n        lambda s: s == matching_str,\n    )\n\n\n@pytest.mark.parametrize(\n    \"pattern,eqiv_pattern\",\n    [\n        (r\"\", r\"\\A\\Z\"),\n        (b\"\", rb\"\\A\\Z\"),\n        (r\"(?#comment)\", r\"\\A\\Z\"),\n        (rb\"(?#comment)\", rb\"\\A\\Z\"),\n        (\"a\", \"\\\\Aa\\\\Z\"),\n        (\"[Aa]\", \"\\\\A[Aa]\\\\Z\"),\n        (\"[ab]*\", \"\\\\A[ab]*\\\\Z\"),\n        (b\"[Aa]\", rb\"\\A[Aa]\\Z\"),\n        (b\"[ab]*\", rb\"\\A[ab]*\\Z\"),\n        (re.compile(\"[ab]*\", re.IGNORECASE), re.compile(\"\\\\A[ab]*\\\\Z\", re.IGNORECASE)),\n        (re.compile(rb\"[ab]\", re.IGNORECASE), re.compile(rb\"\\A[ab]\\Z\", re.IGNORECASE)),\n    ],\n)\ndef test_fullmatch_matches(pattern, eqiv_pattern):\n    assert_all_examples(\n        st.from_regex(pattern, fullmatch=True), lambda s: re.match(eqiv_pattern, s)\n    )\n\n\ndef test_fullmatch_must_be_bool():\n    with pytest.raises(InvalidArgument):\n        st.from_regex(\"a\", fullmatch=None).validate()\n\n\ndef test_issue_1786_regression():\n    st.from_regex(re.compile(\"\\\\\\\\\", flags=re.IGNORECASE)).validate()\n\n\ndef test_sets_allow_multichar_output_in_ignorecase_mode():\n    # CharacterBuilder.strategy includes logic to add multi-character strings\n    # via sampled_from(), if any are whitelisted as matching.  See issue #2657.\n    find_any(\n        st.from_regex(re.compile(\"[\\u0130_]\", re.IGNORECASE)),\n        lambda s: len(s) > 1,\n    )\n\n\ndef test_internals_can_disable_newline_from_dollar_for_jsonschema():\n    pattern = \"^abc$\"\n    find_any(st.from_regex(pattern), lambda s: s == \"abc\\n\")\n    assert_all_examples(\n        regex_strategy(\n            pattern,\n            False,\n            alphabet=st.characters(),\n            _temp_jsonschema_hack_no_end_newline=True,\n        ),\n        lambda s: s == \"abc\",\n    )\n\n\n@given(st.from_regex(r\"[^.].*\", alphabet=st.sampled_from(\"abc\") | st.just(\".\")))\ndef test_can_pass_union_for_alphabet(_):\n    pass\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_regressions.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pickle\nimport random\nfrom datetime import timedelta\nfrom unittest.mock import Mock\n\nimport pytest\n\nfrom hypothesis import (\n    Verbosity,\n    assume,\n    errors,\n    given,\n    seed,\n    settings,\n    strategies as st,\n)\nfrom hypothesis.internal import compat\nfrom hypothesis.internal.escalation import InterestingOrigin\n\nfrom tests.common.utils import skipif_threading\n\n\ndef strat():\n    return st.builds(dict, one=strat_one())\n\n\n@st.composite\ndef strat_one(draw):\n    return draw(st.builds(dict, val=st.builds(dict, two=strat_two())))\n\n\n@st.composite\ndef strat_two(draw):\n    return draw(st.builds(dict, some_text=st.text(min_size=1)))\n\n\n@given(strat())\ndef test_issue751(v):\n    pass\n\n\ndef test_can_find_non_zero():\n    # This future proofs against a possible failure mode where the depth bound\n    # is triggered but we've fixed the behaviour of min_size so that it can\n    # handle that: We want to make sure that we're really not depth bounding\n    # the text in the leaf nodes.\n\n    @settings(verbosity=Verbosity.quiet)\n    @given(strat())\n    def test(v):\n        assert \"0\" in v[\"one\"][\"val\"][\"two\"][\"some_text\"]\n\n    with pytest.raises(AssertionError):\n        test()\n\n\ndef test_mock_injection():\n    \"\"\"Ensure that it's possible for mechanisms like `pytest.fixture` and\n    `patch` to inject mocks into hypothesis test functions without side\n    effects.\n\n    (covers https://github.com/HypothesisWorks/hypothesis-\n    python/issues/491)\n    \"\"\"\n\n    class Bar:\n        pass\n\n    @given(inp=st.integers())\n    def test_foo_spec(bar, inp):\n        pass\n\n    test_foo_spec(Bar())\n    test_foo_spec(Mock(Bar))\n    test_foo_spec(Mock())\n\n\ndef test_regression_issue_1230():\n    strategy = st.builds(\n        lambda x, y: dict(list(x.items()) + list(y.items())),\n        st.fixed_dictionaries({\"0\": st.text()}),\n        st.builds(\n            lambda dictionary, keys: {key: dictionary[key] for key in keys},\n            st.fixed_dictionaries({\"1\": st.lists(elements=st.sampled_from([\"a\"]))}),\n            st.sets(elements=st.sampled_from([\"1\"])),\n        ),\n    )\n\n    @seed(81581571036124932593143257836081491416)\n    @settings(database=None)\n    @given(strategy)\n    def test_false_is_false(params):\n        assume(params.get(\"0\") not in (\"\", \"\\x00\"))\n        raise ValueError\n\n    with pytest.raises(ValueError):\n        test_false_is_false()\n\n\n@given(st.integers())\ndef random_func(x):\n    random.random()\n\n\n@skipif_threading\ndef test_prng_state_unpolluted_by_given_issue_1266():\n    # Checks that @given doesn't leave the global PRNG in a particular\n    # modified state; there may be no effect or random effect but not\n    # a consistent end-state.\n    first = random.getstate()\n    random_func()\n    second = random.getstate()\n    random_func()\n    third = random.getstate()\n    if first == second:\n        assert second == third\n    else:\n        assert second != third\n\n\nexc_instances = [\n    errors.NoSuchExample(\"foobar\", extra=\"baz\"),\n    errors.DeadlineExceeded(\n        runtime=timedelta(seconds=1.5), deadline=timedelta(seconds=1.0)\n    ),\n    errors.RewindRecursive(int),\n    errors.UnsatisfiedAssumption(\"reason for unsatisfied\"),\n    errors.FlakyReplay(\n        \"reason\",\n        interesting_origins=[InterestingOrigin.from_exception(BaseException())],\n    ),\n    errors.FlakyFailure(\"check with BaseException\", [BaseException()]),\n    errors.BackendCannotProceed(\"verified\"),\n]\n\n\n@pytest.mark.parametrize(\"exc\", exc_instances, ids=repr)\ndef test_exceptions_are_picklable(exc):\n    # See https://github.com/HypothesisWorks/hypothesis/issues/3426\n    pickle.loads(pickle.dumps(exc))\n\n\ndef test_no_missed_custom_init_exceptions():\n    untested_errors_with_custom_init = {\n        et\n        for et in vars(errors).values()\n        if isinstance(et, type)\n        and et not in vars(compat).values()  # skip types imported for compatibility\n        and issubclass(et, Exception)\n        and (\"__init__\" in vars(et) or \"__new__\" in vars(et))\n    } - {type(exc) for exc in exc_instances}\n    print(untested_errors_with_custom_init)\n    assert not untested_errors_with_custom_init\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_replay_logic.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.internal.compat import ExceptionGroup\n\n\ndef test_does_not_shrink_on_replay():\n    database = InMemoryExampleDatabase()\n\n    call_count = 0\n\n    is_first = True\n    last = None\n\n    @settings(\n        database=database,\n        report_multiple_bugs=False,\n        derandomize=False,\n        max_examples=1000,\n    )\n    @given(st.lists(st.integers(), unique=True, min_size=3))\n    def test(ls):\n        nonlocal call_count, is_first, last\n        if is_first and last is not None:\n            assert ls == last\n        is_first = False\n        last = ls\n        call_count += 1\n        raise AssertionError\n\n    with pytest.raises(AssertionError):\n        test()\n\n    assert last is not None\n\n    call_count = 0\n    is_first = True\n\n    with pytest.raises(AssertionError):\n        test()\n\n    assert call_count == 2\n\n\ndef test_does_not_shrink_on_replay_with_multiple_bugs():\n    database = InMemoryExampleDatabase()\n    call_count = 0\n    raised = False\n    marker = 1000093\n\n    @settings(\n        database=database,\n        report_multiple_bugs=True,\n        derandomize=False,\n        max_examples=1000,\n    )\n    @given(st.integers())\n    def test(n):\n        nonlocal call_count, raised\n        call_count += 1\n        if n >= marker:\n            raised = True\n            raise AssertionError\n        elif n < marker and raised:\n            raise AssertionError\n\n    with pytest.raises(ExceptionGroup):\n        test()\n\n    call_count = 0\n\n    with pytest.raises(ExceptionGroup):\n        test()\n\n    assert call_count == 4\n\n\ndef test_will_always_shrink_if_previous_example_does_not_replay():\n    database = InMemoryExampleDatabase()\n\n    good = set()\n    last = None\n\n    @settings(\n        database=database,\n        report_multiple_bugs=True,\n        derandomize=False,\n        max_examples=1000,\n    )\n    @given(st.integers(min_value=0))\n    def test(n):\n        nonlocal last\n        if n not in good:\n            last = n\n            raise AssertionError\n\n    for i in range(20):\n        with pytest.raises(AssertionError):\n            test()\n        assert last == i\n        good.add(last)\n\n\ndef test_will_shrink_if_the_previous_example_does_not_look_right():\n    database = InMemoryExampleDatabase()\n\n    last = None\n\n    first_test = True\n\n    @settings(database=database, report_multiple_bugs=True, derandomize=False)\n    @given(st.data())\n    def test(data):\n        nonlocal last\n        m = data.draw(st.integers())\n        last = m\n        if first_test:\n            data.draw(st.integers())\n            assert m < 10000\n        else:\n            raise AssertionError\n\n    with pytest.raises(AssertionError):\n        test()\n\n    assert last is not None\n    assert last > 0\n\n    first_test = False\n\n    with pytest.raises(AssertionError):\n        test()\n\n    assert last == 0\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_reporting.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport sys\n\nimport pytest\n\nfrom hypothesis import given, reporting\nfrom hypothesis._settings import Verbosity, settings\nfrom hypothesis.reporting import debug_report, verbose_report\nfrom hypothesis.strategies import integers\n\nfrom tests.common.utils import capture_out\n\n\ndef test_prints_output_by_default():\n    @given(integers())\n    def test_int(x):\n        raise AssertionError\n\n    with pytest.raises(AssertionError) as err:\n        test_int()\n    assert \"Falsifying example\" in \"\\n\".join(err.value.__notes__)\n\n\ndef test_does_not_print_debug_in_verbose():\n    @given(integers())\n    @settings(verbosity=Verbosity.verbose)\n    def f(x):\n        debug_report(\"Hi\")\n\n    with capture_out() as o:\n        f()\n    assert \"Hi\" not in o.getvalue()\n\n\ndef test_does_print_debug_in_debug():\n    @given(integers())\n    @settings(verbosity=Verbosity.debug)\n    def f(x):\n        debug_report(\"Hi\")\n\n    with capture_out() as o:\n        f()\n    assert \"Hi\" in o.getvalue()\n\n\ndef test_does_print_verbose_in_debug():\n    @given(integers())\n    @settings(verbosity=Verbosity.debug)\n    def f(x):\n        verbose_report(\"Hi\")\n\n    with capture_out() as o:\n        f()\n    assert \"Hi\" in o.getvalue()\n\n\ndef test_can_report_when_system_locale_is_ascii(monkeypatch):\n    read, write = os.pipe()\n    with (\n        open(read, encoding=\"ascii\") as read,\n        open(write, \"w\", encoding=\"ascii\") as write,\n    ):\n        monkeypatch.setattr(sys, \"stdout\", write)\n        reporting.default(\"☃\")\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_reproduce_failure.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport base64\nimport re\nimport zlib\n\nimport pytest\n\nfrom hypothesis import (\n    Verbosity,\n    __version__,\n    example,\n    given,\n    reject,\n    reproduce_failure,\n    settings,\n    strategies as st,\n)\nfrom hypothesis.core import decode_failure, encode_failure\nfrom hypothesis.errors import DidNotReproduce, InvalidArgument, UnsatisfiedAssumption\nfrom hypothesis.internal.conjecture.choice import choice_equal\n\nfrom tests.common.utils import Why, capture_out, no_shrink, xfail_on_crosshair\nfrom tests.conjecture.common import nodes, nodes_inline\n\n\n@example(nodes_inline(\"0\" * 100))  # shorter compressed than not\n@given(st.lists(nodes()))\ndef test_encoding_loop(nodes):\n    choices = [n.value for n in nodes]\n    looped = decode_failure(encode_failure(choices))\n    assert len(choices) == len(looped)\n    for pre, post in zip(choices, looped, strict=True):\n        assert choice_equal(pre, post)\n\n\n@example(base64.b64encode(b\"\\2\\3\\4\"))\n@example(b\"\\t\")\n@example(base64.b64encode(b\"\\1\\0\"))  # zlib error\n@example(base64.b64encode(b\"\\1\" + zlib.compress(b\"\\xff\")))  # choices_from_bytes error\n@given(st.binary())\ndef test_decoding_may_fail(t):\n    try:\n        decode_failure(t)\n        reject()\n    except UnsatisfiedAssumption:\n        raise  # don't silence the reject()\n    except InvalidArgument:\n        pass\n    except Exception as e:\n        raise AssertionError(\"Expected an InvalidArgument exception\") from e\n\n\ndef test_invalid_base_64_gives_invalid_argument():\n    with pytest.raises(InvalidArgument) as exc_info:\n        decode_failure(b\"/\")\n    assert \"Invalid base64 encoded\" in exc_info.value.args[0]\n\n\ndef test_reproduces_the_failure():\n    b = b\"hello world\"\n    n = len(b)\n\n    @reproduce_failure(__version__, encode_failure([b]))\n    @given(st.binary(min_size=n, max_size=n))\n    def test_outer(x):\n        assert x != b\n\n    @given(st.binary(min_size=n, max_size=n))\n    @reproduce_failure(__version__, encode_failure([b]))\n    def test_inner(x):\n        assert x != b\n\n    with pytest.raises(AssertionError):\n        test_outer()\n    with pytest.raises(AssertionError):\n        test_inner()\n\n\ndef test_errors_if_provided_example_does_not_reproduce_failure():\n    b = b\"hello world\"\n    n = len(b)\n\n    @reproduce_failure(__version__, encode_failure([b]))\n    @given(st.binary(min_size=n, max_size=n))\n    def test(x):\n        assert x == b\n\n    with pytest.raises(DidNotReproduce):\n        test()\n\n\ndef test_errors_with_did_not_reproduce_if_the_shape_changes():\n    b = b\"hello world\"\n    n = len(b)\n\n    @reproduce_failure(__version__, encode_failure([b]))\n    @given(st.binary(min_size=n, max_size=n) | st.integers())\n    def test(v):\n        assert v == b\n\n    with pytest.raises(DidNotReproduce):\n        test()\n\n\ndef test_errors_with_did_not_reproduce_if_rejected():\n    b = b\"hello world\"\n    n = len(b)\n\n    @reproduce_failure(__version__, encode_failure([b]))\n    @given(st.binary(min_size=n, max_size=n))\n    def test(x):\n        reject()\n\n    with pytest.raises(DidNotReproduce):\n        test()\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context)\ndef test_prints_reproduction_if_requested():\n    failing_example = None\n\n    @settings(print_blob=True, database=None, max_examples=100)\n    @given(st.integers())\n    def test(i):\n        nonlocal failing_example\n        if failing_example is None and i != 0:\n            failing_example = i\n        assert i != failing_example\n\n    with pytest.raises(AssertionError) as err:\n        test()\n    notes = \"\\n\".join(err.value.__notes__)\n    assert \"@reproduce_failure\" in notes\n\n    exp = re.compile(r\"reproduce_failure\\(([^)]+)\\)\", re.MULTILINE)\n    extract = exp.search(notes)\n    reproduction = eval(extract.group(0))\n    test = reproduction(test)\n\n    with pytest.raises(AssertionError):\n        test()\n\n\ndef test_does_not_print_reproduction_for_simple_examples_by_default():\n    @settings(print_blob=False)\n    @given(st.integers())\n    def test(i):\n        raise AssertionError\n\n    with capture_out() as o, pytest.raises(AssertionError):\n        test()\n    assert \"@reproduce_failure\" not in o.getvalue()\n\n\ndef test_does_not_print_reproduction_for_simple_data_examples_by_default():\n    @settings(print_blob=False)\n    @given(st.data())\n    def test(data):\n        data.draw(st.integers())\n        raise AssertionError\n\n    with capture_out() as o, pytest.raises(AssertionError):\n        test()\n    assert \"@reproduce_failure\" not in o.getvalue()\n\n\ndef test_does_not_print_reproduction_for_large_data_examples_by_default():\n    @settings(phases=no_shrink, print_blob=False)\n    @given(st.data())\n    def test(data):\n        b = data.draw(st.binary(min_size=1000, max_size=1000))\n        if len(zlib.compress(b)) > 1000:\n            raise ValueError\n\n    with capture_out() as o, pytest.raises(ValueError):\n        test()\n    assert \"@reproduce_failure\" not in o.getvalue()\n\n\nclass Foo:\n    def __repr__(self):\n        return \"not a valid python expression\"\n\n\ndef test_does_not_print_reproduction_if_told_not_to():\n    @settings(print_blob=False)\n    @given(st.integers().map(lambda x: Foo()))\n    def test(i):\n        raise ValueError\n\n    with capture_out() as o, pytest.raises(ValueError):\n        test()\n\n    assert \"@reproduce_failure\" not in o.getvalue()\n\n\ndef test_raises_invalid_if_wrong_version():\n    b = b\"hello world\"\n    n = len(b)\n\n    @reproduce_failure(\"1.0.0\", encode_failure([b]))\n    @given(st.binary(min_size=n, max_size=n))\n    def test(x):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        test()\n\n\ndef test_does_not_print_reproduction_if_verbosity_set_to_quiet():\n    @given(st.data())\n    @settings(verbosity=Verbosity.quiet, print_blob=False)\n    def test_always_fails(data):\n        assert data.draw(st.just(False))\n\n    with capture_out() as out, pytest.raises(AssertionError):\n        test_always_fails()\n\n    assert \"@reproduce_failure\" not in out.getvalue()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_runner_strategy.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom unittest import TestCase\n\nimport pytest\n\nfrom hypothesis import find, given, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.stateful import RuleBasedStateMachine, rule\n\n\ndef test_cannot_use_without_a_runner():\n    @given(st.runner())\n    def f(x):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        f()\n\n\ndef test_cannot_use_in_find_without_default():\n    with pytest.raises(InvalidArgument):\n        find(st.runner(), lambda x: True)\n\n\ndef test_is_default_in_find():\n    t = object()\n    assert find(st.runner(default=t), lambda x: True) == t\n\n\n@given(st.runner(default=1))\ndef test_is_default_without_self(runner):\n    assert runner == 1\n\n\nclass TestStuff(TestCase):\n    @given(st.runner())\n    def test_runner_is_self(self, runner):\n        assert runner is self\n\n    @given(st.runner(default=3))\n    def test_runner_is_self_even_with_default(self, runner):\n        assert runner is self\n\n\nclass RunnerStateMachine(RuleBasedStateMachine):\n    @rule(runner=st.runner())\n    def step(self, runner):\n        assert runner is self\n\n\nTestState = RunnerStateMachine.TestCase\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_sampled_from.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport collections\nimport enum\nimport operator\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis.errors import (\n    FailedHealthCheck,\n    InvalidArgument,\n    StopTest,\n    Unsatisfiable,\n)\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.strategies import sampled_from\nfrom hypothesis.strategies._internal.misc import JustStrategy\nfrom hypothesis.strategies._internal.strategies import (\n    FilteredStrategy,\n    filter_not_satisfied,\n)\n\nfrom tests.common.debug import (\n    assert_all_examples,\n    assert_simple_property,\n    check_can_generate_examples,\n)\nfrom tests.common.utils import fails_with\n\nan_enum = enum.Enum(\"A\", \"a b c\")\na_flag = enum.Flag(\"A\", \"a b c\")\n# named zero state is required for empty flags from around py3.11/3.12\nan_empty_flag = enum.Flag(\"EmptyFlag\", {\"a\": 0})\n\nan_ordereddict = collections.OrderedDict([(\"a\", 1), (\"b\", 2), (\"c\", 3)])\n\n\n@fails_with(InvalidArgument)\ndef test_cannot_sample_sets():\n    check_can_generate_examples(sampled_from(set(\"abc\")))\n\n\ndef test_can_sample_sequence_without_warning():\n    check_can_generate_examples(sampled_from([1, 2, 3]))\n\n\ndef test_can_sample_ordereddict_without_warning():\n    check_can_generate_examples(sampled_from(an_ordereddict))\n\n\n@pytest.mark.parametrize(\"enum_class\", [an_enum, a_flag, an_empty_flag])\ndef test_can_sample_enums(enum_class):\n    assert_all_examples(sampled_from(enum_class), lambda x: isinstance(x, enum_class))\n\n\n@fails_with(FailedHealthCheck)\n@settings(suppress_health_check=[])\n@given(sampled_from(range(10)).filter(lambda x: x < 0))\ndef test_unsat_filtered_sampling(x):\n    raise AssertionError\n\n\n@fails_with(Unsatisfiable)\n@settings(suppress_health_check=[])\n@given(sampled_from(range(2)).filter(lambda x: x < 0))\ndef test_unsat_filtered_sampling_in_rejection_stage(x):\n    # Rejecting all possible indices before we calculate the allowed indices\n    # takes an early exit path, so we need this test to cover that branch.\n    raise AssertionError\n\n\ndef test_easy_filtered_sampling():\n    assert_simple_property(\n        sampled_from(range(100)).filter(lambda x: x == 0), lambda x: x == 0\n    )\n\n\n@given(sampled_from(range(100)).filter(lambda x: x == 99))\ndef test_filtered_sampling_finds_rare_value(x):\n    assert x == 99\n\n\n@given(st.sets(st.sampled_from(range(50)), min_size=50))\ndef test_efficient_sets_of_samples(x):\n    assert x == set(range(50))\n\n\n@given(st.dictionaries(keys=st.sampled_from(range(50)), values=st.none(), min_size=50))\ndef test_efficient_dicts_with_sampled_keys(x):\n    assert set(x) == set(range(50))\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"takes 3-5 mins and raises Unsatisfiable\",\n)\n@pytest.mark.parametrize(\n    \"fn\", [lambda asdf: asdf[0], (operator.itemgetter(0), lambda x: x[0])]\n)\n@given(st.data())\ndef test_efficient_lists_of_tuples_first_element_sampled_from(fn, data):\n    elems = st.tuples(st.sampled_from(range(20)), st.builds(list))\n    x = data.draw(st.lists(elems, min_size=20, unique_by=fn))\n    assert {first for first, *_ in x} == set(range(20))\n\n\n@given(st.lists(st.sampled_from([0] * 100), unique=True))\ndef test_does_not_include_duplicates_even_when_duplicated_in_collection(ls):\n    assert len(ls) <= 1\n\n\n@given(\n    st.sets(\n        st.sampled_from(range(50))\n        .map(lambda x: x * 2)\n        .filter(lambda x: x % 3)\n        .map(lambda x: x // 2),\n        min_size=33,\n    )\n)\ndef test_efficient_sets_of_samples_with_chained_transformations(x):\n    assert x == {x for x in range(50) if (x * 2) % 3}\n\n\n@st.composite\ndef stupid_sampled_sets(draw):\n    result = set()\n    s = st.sampled_from(range(20)).filter(lambda x: x % 3).map(lambda x: x * 2)\n    while len(result) < 13:\n        result.add(draw(s.filter(lambda x: x not in result)))\n    return result\n\n\n@given(stupid_sampled_sets())\ndef test_efficient_sets_of_samples_with_chained_transformations_slow_path(x):\n    # This deliberately exercises the standard filtering logic without going\n    # through the special-case handling of UniqueSampledListStrategy.\n    assert x == {x * 2 for x in range(20) if x % 3}\n\n\n@fails_with(Unsatisfiable)\n@given(FilteredStrategy(st.sampled_from([None, False, \"\"]), conditions=(bool,)))\ndef test_unsatisfiable_explicit_filteredstrategy_sampled(x):\n    raise AssertionError(\"Unreachable because there are no valid examples\")\n\n\n@fails_with(Unsatisfiable)\n@given(FilteredStrategy(st.none(), conditions=(bool,)))\ndef test_unsatisfiable_explicit_filteredstrategy_just(x):\n    raise AssertionError(\"Unreachable because there are no valid examples\")\n\n\ndef test_transformed_just_strategy():\n    data = ConjectureData.for_choices([])\n    s = JustStrategy([1]).map(lambda x: x * 2)\n    assert s.do_draw(data) == 2\n    sf = s.filter(lambda x: False)\n    assert isinstance(sf, JustStrategy)\n    assert sf.do_filtered_draw(data) == filter_not_satisfied\n    with pytest.raises(StopTest):\n        sf.do_draw(data)\n\n\n@given(st.lists(st.sampled_from(range(100)), max_size=3, unique=True))\ndef test_max_size_is_respected_with_unique_sampled_from(ls):\n    assert len(ls) <= 3\n\n\n@given(st.lists(st.sampled_from([0, 0.0]), unique=True, min_size=1))\ndef test_issue_2247_regression(ls):\n    assert len(ls) == 1\n\n\n@given(st.data())\ndef test_mutability_1(data):\n    # See https://github.com/HypothesisWorks/hypothesis/issues/2507\n    x = [1]\n    s = st.sampled_from(x)\n    x.append(2)\n    assert data.draw(s) != 2\n\n\n@given(st.data())\ndef test_mutability_2(data):\n    x = [1]\n    s = st.sampled_from(x)\n    assert data.draw(s) != 2\n    x.append(2)\n    assert data.draw(s) != 2\n\n\nclass AnnotationsInsteadOfElements(enum.Enum):\n    a: \"int\"\n\n\ndef test_suggests_elements_instead_of_annotations():\n    with pytest.raises(InvalidArgument, match=r\"Cannot sample.*annotations.*dataclass\"):\n        check_can_generate_examples(st.sampled_from(AnnotationsInsteadOfElements))\n\n\nclass TestErrorNoteBehavior3819:\n    elements = (st.booleans(), st.decimals(), st.integers(), st.text())\n\n    @staticmethod\n    @given(st.data())\n    def direct_without_error(data):\n        data.draw(st.sampled_from((st.floats(), st.binary())))\n\n    @staticmethod\n    @given(st.data())\n    def direct_with_non_type_error(data):\n        data.draw(st.sampled_from(st.characters(), st.floats()))\n        raise Exception(\"Contains SearchStrategy, but no note addition!\")\n\n    @staticmethod\n    @given(st.data())\n    def direct_with_type_error_without_substring(data):\n        data.draw(st.sampled_from(st.booleans(), st.binary()))\n        raise TypeError(\"Substring not in message!\")\n\n    @staticmethod\n    @given(st.data())\n    def direct_with_type_error_with_substring_but_not_all_strategies(data):\n        data.draw(st.sampled_from(st.booleans(), False, True))\n        raise TypeError(\"Contains SearchStrategy, but no note addition!\")\n\n    @staticmethod\n    @given(st.data())\n    def direct_all_strategies_with_type_error_with_substring(data):\n        data.draw(st.sampled_from((st.dates(), st.datetimes())))\n        raise TypeError(\"This message contains SearchStrategy as substring!\")\n\n    @staticmethod\n    @given(st.lists(st.sampled_from(elements)))\n    def indirect_without_error(_):\n        return\n\n    @staticmethod\n    @given(st.lists(st.sampled_from(elements)))\n    def indirect_with_non_type_error(_):\n        raise Exception(\"Contains SearchStrategy, but no note addition!\")\n\n    @staticmethod\n    @given(st.lists(st.sampled_from(elements)))\n    def indirect_with_type_error_without_substring(_):\n        raise TypeError(\"Substring not in message!\")\n\n    @staticmethod\n    @given(st.lists(st.sampled_from((*elements, False, True))))\n    def indirect_with_type_error_with_substring_but_not_all_strategies(_):\n        raise TypeError(\"Contains SearchStrategy, but no note addition!\")\n\n    @staticmethod\n    @given(st.lists(st.sampled_from(elements), min_size=1))\n    def indirect_all_strategies_with_type_error_with_substring(objs):\n        raise TypeError(\"Contains SearchStrategy in message, trigger note!\")\n\n    @pytest.mark.parametrize(\n        [\"func_to_call\", \"exp_err_cls\", \"should_exp_msg\"],\n        [\n            pytest.param(f.__func__, err, msg_exp, id=f.__func__.__name__)\n            for f, err, msg_exp in [\n                (f, TypeError, True)\n                for f in (\n                    direct_all_strategies_with_type_error_with_substring,\n                    indirect_all_strategies_with_type_error_with_substring,\n                )\n            ]\n            + [\n                (f, TypeError, False)\n                for f in (\n                    direct_with_type_error_without_substring,\n                    direct_with_type_error_with_substring_but_not_all_strategies,\n                    indirect_with_type_error_without_substring,\n                    indirect_with_type_error_with_substring_but_not_all_strategies,\n                )\n            ]\n            + [\n                (f, Exception, False)\n                for f in (\n                    direct_with_non_type_error,\n                    indirect_with_non_type_error,\n                )\n            ]\n            + [\n                (f, None, False)\n                for f in (\n                    direct_without_error,\n                    indirect_without_error,\n                )\n            ]\n        ],\n    )\n    def test_error_appropriate_error_note_3819(\n        self, func_to_call, exp_err_cls, should_exp_msg\n    ):\n        if exp_err_cls is None:\n            # Here we only care that no exception was raised, so nothing to assert.\n            func_to_call()\n        else:\n            with pytest.raises(exp_err_cls) as err_ctx:\n                func_to_call()\n            notes = getattr(err_ctx.value, \"__notes__\", [])\n            matching_messages = [\n                n\n                for n in notes\n                if n.startswith(\"sampled_from was given a collection of strategies\")\n                and n.endswith(\"Was one_of intended?\")\n            ]\n            assert len(matching_messages) == (1 if should_exp_msg else 0)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_searchstrategy.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport functools\nimport random\nimport sys\nfrom collections import defaultdict, namedtuple\nfrom dataclasses import dataclass\nfrom typing import Any\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import InvalidArgument, Unsatisfiable\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.reflection import get_pretty_function_description\nfrom hypothesis.strategies._internal.utils import to_jsonable\nfrom hypothesis.utils.conventions import UniqueIdentifier\n\nfrom tests.common.debug import assert_simple_property, check_can_generate_examples\nfrom tests.common.utils import checks_deprecated_behaviour\n\n\ndef test_or_errors_when_given_non_strategy():\n    bools = st.tuples(st.booleans())\n    with pytest.raises(ValueError):\n        bools | \"foo\"\n\n\nSomeNamedTuple = namedtuple(\"SomeNamedTuple\", (\"a\", \"b\"))\n\n\ndef last(xs):\n    t = None\n    for x in xs:\n        t = x\n    return t\n\n\ndef test_just_strategy_uses_repr():\n    class WeirdRepr:\n        def __repr__(self):\n            return \"ABCDEFG\"\n\n    assert repr(st.just(WeirdRepr())) == f\"just({WeirdRepr()!r})\"\n\n\ndef test_just_strategy_does_not_draw():\n    data = ConjectureData.for_choices([])\n    s = st.just(\"hello\")\n    assert s.do_draw(data) == \"hello\"\n\n\ndef test_none_strategy_does_not_draw():\n    data = ConjectureData.for_choices([])\n    s = st.none()\n    assert s.do_draw(data) is None\n\n\ndef test_can_map():\n    s = st.integers().map(pack=lambda t: \"foo\")\n    assert_simple_property(s, lambda v: v == \"foo\")\n\n\ndef test_example_raises_unsatisfiable_when_too_filtered():\n    with pytest.raises(Unsatisfiable):\n        check_can_generate_examples(st.integers().filter(lambda x: False))\n\n\ndef nameless_const(x):\n    def f(u, v):\n        return u\n\n    return functools.partial(f, x)\n\n\ndef test_can_map_nameless():\n    f = nameless_const(2)\n    assert get_pretty_function_description(f) in repr(st.integers().map(f))\n\n\ndef test_can_flatmap_nameless():\n    f = nameless_const(st.just(3))\n    assert get_pretty_function_description(f) in repr(st.integers().flatmap(f))\n\n\ndef test_flatmap_with_invalid_expand():\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(st.just(100).flatmap(lambda n: \"a\"))\n\n\n_bad_random_strategy = st.lists(st.integers(), min_size=1).map(random.choice)\n\n\n@checks_deprecated_behaviour\ndef test_use_of_global_random_is_deprecated_in_given():\n    check_can_generate_examples(_bad_random_strategy)\n\n\n@checks_deprecated_behaviour\ndef test_use_of_global_random_is_deprecated_in_interactive_draws():\n    @given(st.data())\n    def inner(d):\n        d.draw(_bad_random_strategy)\n\n    inner()\n\n\ndef test_jsonable():\n    assert to_jsonable(object(), avoid_realization=True) == \"<symbolic>\"\n    assert isinstance(to_jsonable(object(), avoid_realization=False), str)\n\n\n@dataclass\nclass HasDefaultDict:\n    x: defaultdict\n\n\ndef test_jsonable_defaultdict():\n    obj = HasDefaultDict(defaultdict(list))\n    obj.x[\"a\"] = [42]\n    assert to_jsonable(obj, avoid_realization=False) == {\"x\": {\"a\": [42]}}\n\n\ndef test_jsonable_namedtuple():\n    Obj = namedtuple(\"Obj\", (\"x\"))\n    obj = Obj(10)\n    assert to_jsonable(obj, avoid_realization=False) == {\"x\": 10}\n\n\ndef test_jsonable_small_ints_are_ints():\n    n = 2**62\n    for avoid in (True, False):\n        assert isinstance(to_jsonable(n, avoid_realization=avoid), int)\n        assert to_jsonable(n, avoid_realization=avoid) == n\n\n\ndef test_jsonable_large_ints_are_floats():\n    n = 2**63\n    assert isinstance(to_jsonable(n, avoid_realization=False), float)\n    assert to_jsonable(n, avoid_realization=False) == float(n)\n    assert to_jsonable(n, avoid_realization=True) == \"<symbolic>\"\n\n\ndef test_jsonable_very_large_ints():\n    # previously caused OverflowError when casting to float.\n    n = 2**1024\n    assert to_jsonable(n, avoid_realization=False) == sys.float_info.max\n    assert to_jsonable(n, avoid_realization=True) == \"<symbolic>\"\n\n\n@dataclass\nclass HasCustomJsonFormat:\n    x: str\n\n    def to_json(self):\n        return \"surprise!\"\n\n\ndef test_jsonable_override():\n    obj = HasCustomJsonFormat(\"expected\")\n    assert to_jsonable(obj, avoid_realization=False) == \"surprise!\"\n    assert to_jsonable(obj, avoid_realization=True) == \"<symbolic>\"\n\n\n@dataclass\nclass Inner:\n    value: int\n\n    def to_json(self):\n        return \"custom\"\n\n\n@dataclass\nclass Outer:\n    inner: Inner\n\n\ndef test_jsonable_to_json_nested():\n    obj = Outer(Inner(42))\n    assert to_jsonable(obj, avoid_realization=False) == {\"inner\": \"custom\"}\n    assert to_jsonable(obj, avoid_realization=True) == \"<symbolic>\"\n\n\nrecursive_list = []\nrecursive_list.append(recursive_list)\n\nrecursive_dict = {}\nrecursive_dict[\"a\"] = recursive_dict\n\nmutual1 = []\nmutual2 = [mutual1]\nmutual1.append(mutual2)\n\nshared = UniqueIdentifier(\"shared\")\n\n\n@dataclass\nclass A:\n    a: Any\n    b: Any\n\n\n@pytest.mark.parametrize(\n    \"obj, value\",\n    [\n        (recursive_list, [\"[...]\"]),\n        (recursive_dict, {\"a\": \"{...}\"}),\n        (mutual1, [[\"[...]\"]]),\n        (mutual2, [[\"[...]\"]]),\n        # same id object in different fields. no cycle\n        (A(a=shared, b=shared), {\"a\": \"shared\", \"b\": \"shared\"}),\n        (A(a=recursive_list, b=recursive_dict), {\"a\": [\"[...]\"], \"b\": {\"a\": \"{...}\"}}),\n    ],\n)\ndef test_to_jsonable_handles_reference_cycles(obj, value):\n    assert to_jsonable(obj, avoid_realization=False) == value\n\n\ndef test_deferred_strategy_draw():\n    strategy = st.deferred(lambda: st.integers())\n    assert strategy.do_draw(ConjectureData.for_choices([0])) == 0\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_seed_printing.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport time\n\nimport pytest\n\nfrom hypothesis import Verbosity, assume, core, given, settings, strategies as st\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.errors import FailedHealthCheck\n\nfrom tests.common.utils import all_values, capture_out\n\n\n@pytest.mark.parametrize(\"in_pytest\", [False, True])\n@pytest.mark.parametrize(\"fail_healthcheck\", [False, True])\n@pytest.mark.parametrize(\"verbosity\", [Verbosity.normal, Verbosity.quiet])\ndef test_prints_seed_only_on_healthcheck(\n    monkeypatch, in_pytest, fail_healthcheck, verbosity\n):\n    monkeypatch.setattr(core, \"running_under_pytest\", in_pytest)\n\n    strategy = st.integers()\n    if fail_healthcheck:\n\n        def slow_map(i):\n            time.sleep(10)\n            return i\n\n        strategy = strategy.map(slow_map)\n        expected_exc = FailedHealthCheck\n    else:\n        expected_exc = AssertionError\n\n    @settings(database=None, verbosity=verbosity, suppress_health_check=())\n    @given(strategy)\n    def test(i):\n        assert fail_healthcheck\n\n    with capture_out() as o, pytest.raises(expected_exc):\n        test()\n\n    output = o.getvalue()\n\n    seed = test._hypothesis_internal_use_generated_seed\n    assert seed is not None\n    if fail_healthcheck and verbosity != Verbosity.quiet:\n        assert f\"@seed({seed})\" in output\n        contains_pytest_instruction = f\"--hypothesis-seed={seed}\" in output\n        assert contains_pytest_instruction == in_pytest\n    else:\n        assert \"@seed\" not in output\n        assert f\"--hypothesis-seed={seed}\" not in output\n\n\ndef test_uses_global_force(monkeypatch):\n    monkeypatch.setattr(core, \"global_force_seed\", 42)\n\n    @given(st.integers())\n    def test(i):\n        raise ValueError\n\n    output = []\n\n    for _ in range(2):\n        with capture_out() as o, pytest.raises(ValueError):\n            test()\n        output.append(o.getvalue())\n\n    assert output[0] == output[1]\n    assert \"@seed\" not in output[0]\n\n\ndef test_does_print_on_reuse_from_database():\n    passes_healthcheck = False\n\n    database = InMemoryExampleDatabase()\n\n    @settings(database=database, suppress_health_check=[])\n    @given(st.integers())\n    def test(i):\n        assume(passes_healthcheck)\n        raise ValueError\n\n    with capture_out() as o, pytest.raises(FailedHealthCheck):\n        test()\n\n    assert \"@seed\" in o.getvalue()\n\n    passes_healthcheck = True\n\n    with capture_out() as o, pytest.raises(ValueError):\n        test()\n\n    assert all_values(database)\n    assert \"@seed\" not in o.getvalue()\n\n    passes_healthcheck = False\n\n    with capture_out() as o, pytest.raises(FailedHealthCheck):\n        test()\n\n    assert \"@seed\" in o.getvalue()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_settings.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport datetime\nimport os\nimport subprocess\nimport sys\nfrom contextlib import contextmanager\nfrom threading import RLock\nfrom unittest import TestCase\n\nimport pytest\n\nfrom hypothesis import example, given, strategies as st\nfrom hypothesis._settings import (\n    _CI_VARS,\n    HealthCheck,\n    Phase,\n    Verbosity,\n    default_variable,\n    local_settings,\n    settings,\n)\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.errors import (\n    HypothesisDeprecationWarning,\n    InvalidArgument,\n)\nfrom hypothesis.stateful import RuleBasedStateMachine, rule\nfrom hypothesis.utils.conventions import not_set\nfrom hypothesis.utils.deprecation import note_deprecation\n\nfrom tests.common.utils import (\n    checks_deprecated_behaviour,\n    counts_calls,\n    fails_with,\n    skipif_emscripten,\n    skipif_threading,\n    validate_deprecation,\n)\n\noriginal_default = settings.get_profile(\"default\").max_examples\n_temp_register_profile_lock = RLock()\n\n\n@contextmanager\ndef temp_register_profile(name, parent, **kwargs):\n    with _temp_register_profile_lock:\n        try:\n            settings.register_profile(name, parent, **kwargs)\n            yield\n        finally:\n            settings._profiles.pop(name)\n\n\n_restore_profile_lock = RLock()\n\n\n@contextmanager\ndef restore_profile():\n    with _restore_profile_lock:\n        # avoid polluting global state by resetting the loaded profile back to its\n        # previous value in tests which use load_profile\n        current_profile = settings.get_current_profile_name()\n        try:\n            yield\n        finally:\n            settings.load_profile(current_profile)\n\n\ndef test_cannot_set_non_settings():\n    s = settings()\n    with pytest.raises(AttributeError):\n        s.databas_file = \"some_file\"\n\n\ndef test_settings_uses_defaults():\n    s = settings()\n    assert s.max_examples == settings.default.max_examples\n\n\ndef test_raises_attribute_error():\n    with pytest.raises(AttributeError):\n        settings().kittens\n\n\ndef test_respects_none_database():\n    assert settings(database=None).database is None\n\n\ndef test_can_repeatedly_push_the_same_thing():\n    s = settings(max_examples=12)\n    t = settings(max_examples=17)\n    original = settings().max_examples\n    with local_settings(s):\n        assert settings().max_examples == 12\n        with local_settings(t):\n            assert settings().max_examples == 17\n            with local_settings(s):\n                assert settings().max_examples == 12\n                with local_settings(t):\n                    assert settings().max_examples == 17\n                assert settings().max_examples == 12\n            assert settings().max_examples == 17\n        assert settings().max_examples == 12\n    assert settings().max_examples == original\n\n\ndef test_can_set_verbosity():\n    settings(verbosity=Verbosity.quiet)\n    settings(verbosity=Verbosity.normal)\n    settings(verbosity=Verbosity.verbose)\n    settings(verbosity=Verbosity.debug)\n\n\ndef test_can_not_set_verbosity_to_non_verbosity():\n    with pytest.raises(InvalidArgument):\n        settings(verbosity=\"kittens\")\n\n\n@pytest.mark.parametrize(\"db\", [None, InMemoryExampleDatabase()])\ndef test_inherits_an_empty_database(db):\n    with local_settings(settings(database=InMemoryExampleDatabase())):\n        assert settings.default.database is not None\n        s = settings(database=db)\n        assert s.database is db\n        with local_settings(s):\n            t = settings()\n        assert t.database is db\n\n\n@pytest.mark.parametrize(\"db\", [None, InMemoryExampleDatabase()])\ndef test_can_assign_database(db):\n    x = settings(database=db)\n    assert x.database is db\n\n\ndef test_will_reload_profile_when_default_is_absent():\n    original = settings.default\n    default_variable.value = None\n    assert settings.default is original\n\n\ndef test_load_profile():\n    with restore_profile():\n        settings.load_profile(\"default\")\n        assert settings.default.max_examples == original_default\n        assert settings.default.stateful_step_count == 50\n\n        settings.register_profile(\n            \"test\", settings(max_examples=10), stateful_step_count=5\n        )\n        settings.load_profile(\"test\")\n\n        assert settings.default.max_examples == 10\n        assert settings.default.stateful_step_count == 5\n\n        settings.load_profile(\"default\")\n\n        assert settings.default.max_examples == original_default\n        assert settings.default.stateful_step_count == 50\n\n\ndef test_profile_names_must_be_strings():\n    with pytest.raises(InvalidArgument):\n        settings.register_profile(5)\n    with pytest.raises(InvalidArgument):\n        settings.get_profile(5)\n    with pytest.raises(InvalidArgument):\n        settings.load_profile(5)\n\n\ndef test_loading_profile_keeps_expected_behaviour():\n    with restore_profile():\n        settings.register_profile(\"ci\", settings(max_examples=10000))\n        settings.load_profile(\"ci\")\n        assert settings().max_examples == 10000\n        with local_settings(settings(max_examples=5)):\n            assert settings().max_examples == 5\n        assert settings().max_examples == 10000\n\n\ndef test_load_non_existent_profile():\n    with pytest.raises(InvalidArgument):\n        settings.get_profile(\"nonsense\")\n\n\ndef test_cannot_set_settings():\n    x = settings()\n    with pytest.raises(AttributeError):\n        x.max_examples = \"foo\"\n    with pytest.raises(AttributeError):\n        x.database = \"foo\"\n    assert x.max_examples != \"foo\"\n    assert x.database != \"foo\"\n\n\ndef test_can_have_none_database():\n    assert settings(database=None).database is None\n\n\n@pytest.mark.parametrize(\"db\", [None, InMemoryExampleDatabase()])\n@pytest.mark.parametrize(\"bad_db\", [\":memory:\", \".hypothesis/examples\"])\ndef test_database_type_must_be_ExampleDatabase(db, bad_db):\n    with local_settings(settings(database=db)):\n        settings_property_db = settings.database\n        with pytest.raises(InvalidArgument):\n            settings(database=bad_db)\n        assert settings.database is settings_property_db\n\n\ndef test_cannot_assign_default():\n    with pytest.raises(AttributeError):\n        settings.default = settings(max_examples=3)\n    assert settings().max_examples != 3\n\n\n@settings(max_examples=7)\n@given(st.builds(lambda: settings.default))\ndef test_settings_in_strategies_are_from_test_scope(s):\n    assert s.max_examples == 7\n\n\nTEST_SETTINGS_ALONE = \"\"\"\nfrom hypothesis import settings\nfrom hypothesis.strategies import integers\n\n@settings()\ndef test_settings_alone():\n    pass\n\"\"\"\n\n\n# runpytest_inprocess uses invalidate_caches in pytest, which is not thread safe\n# (I presume; produces keyerrors).\n@skipif_threading\ndef test_settings_alone(pytester):\n    # Disable cacheprovider, since we don't need it and it's flaky on pyodide\n    script = pytester.makepyfile(TEST_SETTINGS_ALONE)\n    result = pytester.runpytest_inprocess(script, \"-p\", \"no:cacheprovider\")\n    out = \"\\n\".join(result.stdout.lines)\n    msg = \"Using `@settings` on a test without `@given` is completely pointless.\"\n    assert msg in out\n    assert \"InvalidArgument\" in out\n    assert result.ret == 1\n\n\n@fails_with(InvalidArgument)\ndef test_settings_applied_twice_is_error():\n    @given(st.integers())\n    @settings()\n    @settings()\n    def test_nothing(x):\n        pass\n\n\n@settings()\n@given(st.integers())\ndef test_outer_ok(x):\n    pass\n\n\n@given(st.integers())\n@settings()\ndef test_inner_ok(x):\n    pass\n\n\ndef test_settings_as_decorator_must_be_on_callable():\n    with pytest.raises(InvalidArgument):\n        settings()(1)\n\n\nASSERT_DATABASE_PATH = \"\"\"\nimport tempfile\nfrom hypothesis import settings\nfrom hypothesis.configuration import set_hypothesis_home_dir\nfrom hypothesis.database import DirectoryBasedExampleDatabase\n\nsettings.load_profile(\"default\")\nsettings.default.database\n\nif __name__ == '__main__':\n    new_home = tempfile.mkdtemp()\n    set_hypothesis_home_dir(new_home)\n    db = settings.default.database\n    assert isinstance(db, DirectoryBasedExampleDatabase), db\n    assert db.path.is_relative_to(new_home), (db.path, new_home)\n\"\"\"\n\n\n@skipif_emscripten\ndef test_puts_the_database_in_the_home_dir_by_default(tmp_path):\n    script = tmp_path / \"assertlocation.py\"\n    script.write_text(ASSERT_DATABASE_PATH, encoding=\"utf-8\")\n    subprocess.check_call([sys.executable, str(script)])\n\n\ndef test_database_is_reference_preserved():\n    s = settings(database=not_set)\n\n    assert s.database is s.database\n\n\n@settings(verbosity=Verbosity.verbose)\n@example(x=99)\n@given(st.integers())\ndef test_settings_apply_for_explicit_examples(x):\n    # Regression test for #1521\n    assert settings.default.verbosity == Verbosity.verbose\n\n\nclass TestGivenExampleSettingsExplicitCalled(TestCase):\n    \"\"\"Real nasty edge case here.\n\n    in #2160, if ``example`` is after ``given`` but before ``settings``,\n    it will be completely ignored.\n\n    If we set phases to only ``explicit``, the test case will never be called!\n\n    We have to run an assertion outside of the test case itself.\n    \"\"\"\n\n    @counts_calls\n    def call_target(self):\n        pass\n\n    @given(st.booleans())\n    @example(True)\n    @settings(phases=[Phase.explicit])\n    # counts_calls is not thread safe (modifying global f.calls attr)\n    @skipif_threading\n    def test_example_explicit(self, x):\n        self.call_target()\n\n    def tearDown(self):\n        # In #2160, this is 0.\n        assert self.call_target.calls == 1\n\n\ndef test_setattr_on_settings_singleton_is_error():\n    # https://github.com/pandas-dev/pandas/pull/22679#issuecomment-420750921\n    # Should be setting attributes on settings.default, not settings!\n    with pytest.raises(AttributeError):\n        settings.max_examples = 10\n\n\ndef test_deadline_given_none():\n    x = settings(deadline=None).deadline\n    assert x is None\n\n\ndef test_deadline_given_valid_int():\n    x = settings(deadline=1000).deadline\n    assert isinstance(x, datetime.timedelta)\n    assert x.days == 0\n    assert x.seconds == 1\n    assert x.microseconds == 0\n\n\ndef test_deadline_given_valid_float():\n    x = settings(deadline=2050.25).deadline\n    assert isinstance(x, datetime.timedelta)\n    assert x.days == 0\n    assert x.seconds == 2\n    assert x.microseconds == 50250\n\n\ndef test_deadline_given_valid_timedelta():\n    x = settings(deadline=datetime.timedelta(days=1, microseconds=15030000)).deadline\n    assert isinstance(x, datetime.timedelta)\n    assert x.days == 1\n    assert x.seconds == 15\n    assert x.microseconds == 30000\n\n\n@pytest.mark.parametrize(\"value\", [\"always\"])\ndef test_can_not_set_print_blob_to_non_print_settings(value):\n    with pytest.raises(InvalidArgument):\n        settings(print_blob=value)\n\n\nsettings_step_count = 1\n\n\n@settings(stateful_step_count=settings_step_count)\nclass StepCounter(RuleBasedStateMachine):\n    def __init__(self):\n        super().__init__()\n        self.step_count = 0\n\n    @rule()\n    def count_step(self):\n        self.step_count += 1\n\n    def teardown(self):\n        assert self.step_count <= settings_step_count\n\n\ntest_settings_decorator_applies_to_rule_based_state_machine_class = StepCounter.TestCase\n\n\ndef test_two_settings_decorators_applied_to_state_machine_class_raises_error():\n    with pytest.raises(InvalidArgument):\n\n        @settings()\n        @settings()\n        class StatefulTest(RuleBasedStateMachine):\n            pass\n\n\ndef test_settings_decorator_applied_to_non_state_machine_class_raises_error():\n    with pytest.raises(InvalidArgument):\n\n        @settings()\n        class NonStateMachine:\n            pass\n\n\ndef test_assigning_to_settings_attribute_on_state_machine_raises_error():\n    class StateMachine(RuleBasedStateMachine):\n        @rule(x=st.none())\n        def a_rule(self, x):\n            assert x is None\n\n    with pytest.raises(AttributeError):\n        StateMachine.settings = settings()\n\n    state_machine_instance = StateMachine()\n    state_machine_instance.settings = \"any value\"\n\n\ndef test_derandomise_with_explicit_database_is_invalid():\n    with pytest.raises(InvalidArgument):\n        settings(derandomize=True, database=InMemoryExampleDatabase())\n\n\n@pytest.mark.parametrize(\n    \"kwargs\",\n    [\n        {\"max_examples\": -1},\n        {\"max_examples\": 2.5},\n        {\"stateful_step_count\": -1},\n        {\"stateful_step_count\": 2.5},\n        {\"deadline\": -1},\n        {\"deadline\": 0},\n        {\"deadline\": -0.7},\n        {\"deadline\": 86400000000000000.2},\n        {\"deadline\": datetime.timedelta(microseconds=-1)},\n        {\"deadline\": datetime.timedelta(0)},\n        {\"deadline\": True},\n        {\"deadline\": False},\n        {\"backend\": \"nonexistent_backend\"},\n        {\"suppress_health_check\": [\"nonexistent_healthcheck\"]},\n        {\"phases\": [\"nonexistent_phase\"]},\n        {\"phases\": 0},\n        {\"verbosity\": -1},\n        {\"verbosity\": \"nonexistent_verbosity\"},\n    ],\n)\ndef test_invalid_settings_are_errors(kwargs):\n    with pytest.raises(InvalidArgument):\n        settings(**kwargs)\n\n\ndef test_invalid_parent():\n    class NotSettings:\n        def __repr__(self):\n            return \"(not settings repr)\"\n\n    not_settings = NotSettings()\n\n    with pytest.raises(InvalidArgument, match=r\"parent=\\(not settings repr\\)\"):\n        settings(not_settings)\n\n\ndef test_default_settings_do_not_use_ci():\n    assert settings.get_profile(\"default\").suppress_health_check == ()\n\n\ndef test_show_changed():\n    s = settings(settings.get_profile(\"default\"), max_examples=999, database=None)\n    assert s.show_changed() == \"database=None, max_examples=999\"\n\n\ndef test_note_deprecation_checks_date():\n    with pytest.warns(HypothesisDeprecationWarning) as rec:\n        note_deprecation(\"This is bad\", since=\"RELEASEDAY\", has_codemod=False)\n    assert len(rec) == 1\n    with pytest.raises(AssertionError):\n        note_deprecation(\"This is way too old\", since=\"1999-12-31\", has_codemod=False)\n\n\ndef test_note_deprecation_checks_has_codemod():\n    with pytest.warns(\n        HypothesisDeprecationWarning,\n        match=\"The `hypothesis codemod` command-line tool\",\n    ):\n        note_deprecation(\"This is bad\", since=\"2021-01-01\", has_codemod=True)\n\n\ndef test_deprecated_settings_warn_on_set_settings():\n    with validate_deprecation():\n        settings(suppress_health_check=[HealthCheck.return_value])\n    with validate_deprecation():\n        settings(suppress_health_check=[HealthCheck.not_a_test_method])\n\n\n@checks_deprecated_behaviour\ndef test_deprecated_settings_not_in_settings_all_list():\n    al = HealthCheck.all()\n    ls = list(HealthCheck)\n    assert al == ls\n    assert HealthCheck.return_value not in ls\n    assert HealthCheck.not_a_test_method not in ls\n\n\n@skipif_emscripten\ndef test_check_defaults_to_derandomize_when_running_on_ci():\n    env = dict(os.environ)\n    env[\"CI\"] = \"true\"\n\n    assert (\n        subprocess.check_output(\n            [\n                sys.executable,\n                \"-c\",\n                \"from hypothesis import settings\\nprint(settings().derandomize)\",\n            ],\n            env=env,\n            text=True,\n            encoding=\"utf-8\",\n        ).strip()\n        == \"True\"\n    )\n\n\n@skipif_emscripten\ndef test_check_defaults_to_randomize_when_not_running_on_ci():\n    env = dict(os.environ)\n    for key in _CI_VARS:\n        env.pop(key, None)\n\n    assert (\n        subprocess.check_output(\n            [\n                sys.executable,\n                \"-c\",\n                \"from hypothesis import settings\\nprint(settings().derandomize)\",\n            ],\n            env=env,\n            text=True,\n            encoding=\"utf-8\",\n        ).strip()\n        == \"False\"\n    )\n\n\n@skipif_threading  # modifying global state (profiles) during testing\ndef test_reloads_the_loaded_profile_if_registered_again():\n    with restore_profile():\n        test_profile = \"some nonsense profile purely for this test\"\n        test_value = 123456\n        settings.register_profile(test_profile, settings(max_examples=test_value))\n        settings.load_profile(test_profile)\n        assert settings.default.max_examples == test_value\n        test_value_2 = 42\n        settings.register_profile(test_profile, settings(max_examples=test_value_2))\n        assert settings.default.max_examples == test_value_2\n\n\nCI_TESTING_SCRIPT = \"\"\"\nfrom hypothesis import settings\n\nif __name__ == '__main__':\n    settings.register_profile(\"ci\", settings(max_examples=42))\n    assert settings.default.max_examples == 42\n\"\"\"\n\n\n@skipif_emscripten\ndef test_will_automatically_pick_up_changes_to_ci_profile_in_ci():\n    env = dict(os.environ)\n    env[\"CI\"] = \"true\"\n    subprocess.check_call(\n        [sys.executable, \"-c\", CI_TESTING_SCRIPT],\n        env=env,\n        text=True,\n        encoding=\"utf-8\",\n    )\n\n\ndef test_register_profile_avoids_intermediate_profiles():\n    parent = settings()\n    s = settings(parent, max_examples=10)\n    with temp_register_profile(\"for_intermediate_test\", s):\n        assert settings.get_profile(\"for_intermediate_test\")._fallback is parent\n\n\n@checks_deprecated_behaviour\n@settings(max_examples=10)\n@given(st.integers())\ndef test_cannot_register_profile_from_inside_test(x):\n    settings.register_profile(\"problematic\", settings(max_examples=20))\n\n\ndef test_can_set_verbosity_to_strings():\n    assert settings(verbosity=\"quiet\").verbosity is Verbosity.quiet\n    assert settings(verbosity=\"normal\").verbosity is Verbosity.normal\n    assert settings(verbosity=\"verbose\").verbosity is Verbosity.verbose\n    assert settings(verbosity=\"debug\").verbosity is Verbosity.debug\n\n\ndef test_can_set_phase_to_strings():\n    assert settings(phases=[\"reuse\"]).phases == (Phase.reuse,)\n    assert settings(phases=[\"reuse\", \"explicit\"]).phases == (\n        Phase.explicit,\n        Phase.reuse,\n    )\n\n\ndef test_can_set_suppressions_to_strings():\n    assert settings(\n        suppress_health_check=[\"filter_too_much\"]\n    ).suppress_health_check == (HealthCheck.filter_too_much,)\n    assert settings(\n        suppress_health_check=[\"filter_too_much\", \"too_slow\"]\n    ).suppress_health_check == (HealthCheck.filter_too_much, HealthCheck.too_slow)\n\n\ndef test_verbosity_is_comparable():\n    assert Verbosity.quiet < Verbosity.normal\n    assert Verbosity.quiet <= Verbosity.quiet\n    assert Verbosity.quiet == Verbosity.quiet\n    assert Verbosity.quiet >= Verbosity.quiet\n    assert Verbosity.debug > Verbosity.quiet\n\n    # make sure we're comparing by int value, not by str value\n    assert Verbosity.quiet < Verbosity.normal < Verbosity.verbose < Verbosity.debug\n\n    # also comparable with other ints\n    assert Verbosity.quiet < 1\n    assert Verbosity.quiet <= 1\n    assert Verbosity.quiet == 0\n    assert Verbosity.quiet >= 0\n    assert Verbosity.normal > 0\n\n\n@checks_deprecated_behaviour\ndef test_can_set_verbosity_to_integers():\n    assert Verbosity(0) is Verbosity.quiet\n    assert Verbosity(1) is Verbosity.normal\n    assert Verbosity(2) is Verbosity.verbose\n    assert Verbosity(3) is Verbosity.debug\n\n\n@checks_deprecated_behaviour\ndef test_can_set_phase_to_integers():\n    assert Phase(0) is Phase.explicit\n    assert Phase(1) is Phase.reuse\n    assert Phase(2) is Phase.generate\n    assert Phase(4) is Phase.shrink\n\n\n@checks_deprecated_behaviour\ndef test_can_set_suppressions_to_integers():\n    assert HealthCheck(1) is HealthCheck.data_too_large\n    assert HealthCheck(2) is HealthCheck.filter_too_much\n    assert HealthCheck(3) is HealthCheck.too_slow\n\n\ndef test_invalid_integer_phase_raises():\n    with pytest.raises(ValueError):\n        Phase(99)\n\n\ndef test_invalid_integer_healthcheck_raises():\n    with pytest.raises(ValueError):\n        HealthCheck(99)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_setup_teardown.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import HealthCheck, assume, given, settings\nfrom hypothesis.strategies import integers, text\n\n\nclass HasSetup:\n    def setup_example(self):\n        self.setups = getattr(self, \"setups\", 0)\n        self.setups += 1\n\n\nclass HasTeardown:\n    def teardown_example(self, ex):\n        self.teardowns = getattr(self, \"teardowns\", 0)\n        self.teardowns += 1\n\n\nclass SomeGivens:\n    @given(integers())\n    @settings(suppress_health_check=[HealthCheck.differing_executors])\n    def give_me_an_int(self, x):\n        pass\n\n    @given(text())\n    def give_me_a_string(self, x):\n        pass\n\n    @given(integers())\n    @settings(max_examples=1000)\n    def give_me_a_positive_int(self, x):\n        assert x >= 0\n\n    @given(integers().map(lambda x: x.nope))\n    def fail_in_reify(self, x):\n        pass\n\n    @given(integers())\n    @settings(suppress_health_check=[HealthCheck.filter_too_much])\n    def assume_some_stuff(self, x):\n        assume(x > 0)\n\n    @given(integers().filter(lambda x: x > 0))\n    def assume_in_reify(self, x):\n        pass\n\n\nclass HasSetupAndTeardown(HasSetup, HasTeardown, SomeGivens):\n    pass\n\n\ndef test_calls_setup_and_teardown_on_self_as_first_argument():\n    x = HasSetupAndTeardown()\n    x.give_me_an_int()\n    x.give_me_a_string()\n    assert x.setups > 0\n    assert x.teardowns == x.setups\n\n\ndef test_calls_setup_and_teardown_on_self_unbound():\n    x = HasSetupAndTeardown()\n    HasSetupAndTeardown.give_me_an_int(x)\n    assert x.setups > 0\n    assert x.teardowns == x.setups\n\n\ndef test_calls_setup_and_teardown_on_failure():\n    x = HasSetupAndTeardown()\n    with pytest.raises(AssertionError):\n        x.give_me_a_positive_int()\n    assert x.setups > 0\n    assert x.teardowns == x.setups\n\n\ndef test_still_tears_down_on_error_in_generation():\n    x = HasSetupAndTeardown()\n    with pytest.raises(AttributeError):\n        x.fail_in_reify()\n    assert x.setups > 0\n    assert x.teardowns == x.setups\n\n\ndef test_still_tears_down_on_failed_assume():\n    x = HasSetupAndTeardown()\n    x.assume_some_stuff()\n    assert x.setups > 0\n    assert x.teardowns == x.setups\n\n\ndef test_still_tears_down_on_failed_assume_in_reify():\n    x = HasSetupAndTeardown()\n    x.assume_in_reify()\n    assert x.setups > 0\n    assert x.teardowns == x.setups\n\n\ndef test_sets_up_without_teardown():\n    class Foo(HasSetup, SomeGivens):\n        pass\n\n    x = Foo()\n    x.give_me_an_int()\n    assert x.setups > 0\n    assert not hasattr(x, \"teardowns\")\n\n\ndef test_tears_down_without_setup():\n    class Foo(HasTeardown, SomeGivens):\n        pass\n\n    x = Foo()\n    x.give_me_an_int()\n    assert x.teardowns > 0\n    assert not hasattr(x, \"setups\")\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_shrink_budgeting.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport sys\n\nimport pytest\n\nfrom hypothesis.internal.conjecture.shrinking import Integer, Ordering\n\n\n@pytest.mark.parametrize(\n    \"Shrinker, value\",\n    [\n        (Integer, 2**16),\n        (Integer, int(sys.float_info.max)),\n        (Ordering, [(100,) * 10]),\n        (Ordering, [i * 100 for i in (range(5))]),\n        (Ordering, [i * 100 for i in reversed(range(5))]),\n    ],\n)\ndef test_meets_budgetary_requirements(Shrinker, value):\n    shrinker = Shrinker(value, lambda x: x == value)\n    shrinker.run()\n    assert shrinker.calls <= 10\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_sideeffect_warnings.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport _hypothesis_globals\nimport pytest\n\nfrom hypothesis import configuration as fs, strategies as st\nfrom hypothesis.errors import HypothesisSideeffectWarning\n\nIN_INITIALIZATION_ATTR = \"in_initialization\"\n\n# These tests use the pytest plugin enabling infrastructure to restart the side-effect warnings,\n# rather than trying to induce side-effects during import (and entrypoint loading) itself, which is\n# hard to do.  Manual verification of behaviour during initial import can be done by just injecting\n# one of the side-effect-inducing statements below directly into hypothesis.entry_points.run().\n# Manual validation can also be done by inspecting the relevant state during import and verify that\n# it is the same as tested here\n# (_hypothesis_globals.in_initialization > 0, hypothesis.configuration._first_postinit_what is None)\n\n\n@pytest.fixture\ndef _extend_initialization(monkeypatch):\n    assert getattr(_hypothesis_globals, IN_INITIALIZATION_ATTR) <= 0\n    monkeypatch.setattr(_hypothesis_globals, IN_INITIALIZATION_ATTR, 1)\n    fs.notice_initialization_restarted(warn=False)\n    assert fs._first_postinit_what is None  # validates state as given in comment above\n\n\n@pytest.mark.parametrize(\n    \"sideeffect, warning_text\",\n    [\n        # the inner lambda ensures the lazy strategy can't be cached\n        (lambda: st.builds(lambda: None).wrapped_strategy, \"lazy evaluation\"),\n        (lambda: st.deferred(st.none).wrapped_strategy, \"deferred evaluation\"),\n        (fs.storage_directory, \"accessing storage\"),\n    ],\n)\ndef test_sideeffect_warning(sideeffect, warning_text, _extend_initialization):\n    with pytest.warns(HypothesisSideeffectWarning, match=warning_text):\n        sideeffect()\n\n\ndef test_sideeffect_delayed_warning(monkeypatch, _extend_initialization):\n    what = \"synthetic side-effect\"\n    # _extend_initialization ensures we start at known clean slate (no delayed warnings).\n    # Then: stop initialization, check a side-effect operation, and restart it.\n    monkeypatch.setattr(_hypothesis_globals, IN_INITIALIZATION_ATTR, 0)\n    fs.check_sideeffect_during_initialization(what)\n    fs.check_sideeffect_during_initialization(\"ignored since not first\")\n    # The warning should identify itself as happening after import but before plugin load\n    with pytest.warns(HypothesisSideeffectWarning, match=what + \".*between import\"):\n        monkeypatch.setattr(_hypothesis_globals, IN_INITIALIZATION_ATTR, 1)\n        fs.notice_initialization_restarted()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_simple_characters.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport unicodedata\n\nimport pytest\n\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.strategies import characters\n\nfrom tests.common.debug import (\n    assert_no_examples,\n    check_can_generate_examples,\n    find_any,\n    minimal,\n)\nfrom tests.common.utils import fails_with\n\n\n@fails_with(InvalidArgument)\ndef test_nonexistent_category_argument():\n    check_can_generate_examples(characters(exclude_categories=[\"foo\"]))\n\n\ndef test_bad_codepoint_arguments():\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(characters(min_codepoint=42, max_codepoint=24))\n\n\ndef test_exclude_all_available_range():\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(\n            characters(\n                min_codepoint=ord(\"0\"), max_codepoint=ord(\"0\"), exclude_characters=\"0\"\n            )\n        )\n\n\ndef test_when_nothing_could_be_produced():\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(\n            characters(\n                categories=[\"Cc\"], min_codepoint=ord(\"0\"), max_codepoint=ord(\"9\")\n            )\n        )\n\n\ndef test_include_exclude_with_multiple_chars_is_invalid():\n    with pytest.raises(InvalidArgument, match=\"required to be a single character\"):\n        check_can_generate_examples(\n            characters(codec=\"ascii\", exclude_characters=[\"a\", \"morethanonechar\"])\n        )\n\n    with pytest.raises(InvalidArgument, match=\"required to be a single character\"):\n        check_can_generate_examples(\n            characters(codec=\"ascii\", include_characters=[\"a\", \"morethanonechar\"])\n        )\n\n\ndef test_characters_of_specific_groups():\n    st = characters(categories=(\"Lu\", \"Nd\"))\n\n    find_any(st, lambda c: unicodedata.category(c) == \"Lu\")\n    find_any(st, lambda c: unicodedata.category(c) == \"Nd\")\n\n    assert_no_examples(st, lambda c: unicodedata.category(c) not in (\"Lu\", \"Nd\"))\n\n\ndef test_characters_of_major_categories():\n    st = characters(categories=(\"L\", \"N\"))\n    find_any(st, lambda c: unicodedata.category(c).startswith(\"L\"))\n    find_any(st, lambda c: unicodedata.category(c).startswith(\"N\"))\n    assert_no_examples(st, lambda c: unicodedata.category(c)[0] not in (\"L\", \"N\"))\n\n\ndef test_exclude_characters_of_specific_groups():\n    st = characters(exclude_categories=(\"Lu\", \"Nd\"))\n\n    find_any(st, lambda c: unicodedata.category(c) != \"Lu\")\n    find_any(st, lambda c: unicodedata.category(c) != \"Nd\")\n\n    assert_no_examples(st, lambda c: unicodedata.category(c) in (\"Lu\", \"Nd\"))\n\n\ndef test_exclude_characters_of_major_categories():\n    st = characters(exclude_categories=(\"L\", \"N\"))\n    find_any(st, lambda c: not unicodedata.category(c).startswith(\"L\"))\n    find_any(st, lambda c: not unicodedata.category(c).startswith(\"N\"))\n    assert_no_examples(st, lambda c: unicodedata.category(c)[0] in (\"L\", \"N\"))\n\n\ndef test_find_one():\n    char = minimal(characters(min_codepoint=48, max_codepoint=48))\n    assert char == \"0\"\n\n\ndef test_find_something_rare():\n    st = characters(categories=[\"Zs\"], min_codepoint=12288)\n\n    find_any(st, lambda c: unicodedata.category(c) == \"Zs\")\n\n    assert_no_examples(st, lambda c: unicodedata.category(c) != \"Zs\")\n\n\ndef test_whitelisted_characters_alone():\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(characters(include_characters=\"te02тест49st\"))\n\n\ndef test_whitelisted_characters_overlap_blacklisted_characters():\n    good_chars = \"te02тест49st\"\n    bad_chars = \"ts94тсет\"\n    with pytest.raises(InvalidArgument) as exc:\n        check_can_generate_examples(\n            characters(\n                min_codepoint=ord(\"0\"),\n                max_codepoint=ord(\"9\"),\n                include_characters=good_chars,\n                exclude_characters=bad_chars,\n            )\n        )\n    assert repr(good_chars) in str(exc)\n    assert repr(bad_chars) in str(exc)\n\n\ndef test_whitelisted_characters_override():\n    good_characters = \"teтестst\"\n    st = characters(\n        min_codepoint=ord(\"0\"),\n        max_codepoint=ord(\"9\"),\n        include_characters=good_characters,\n    )\n\n    find_any(st, lambda c: c in good_characters)\n    find_any(st, lambda c: c in \"0123456789\")\n\n    assert_no_examples(st, lambda c: c not in good_characters + \"0123456789\")\n\n\ndef test_blacklisted_characters():\n    bad_chars = \"te02тест49st\"\n    st = characters(\n        min_codepoint=ord(\"0\"), max_codepoint=ord(\"9\"), exclude_characters=bad_chars\n    )\n\n    assert \"1\" == minimal(st)\n\n    assert_no_examples(st, lambda c: c in bad_chars)\n\n\ndef test_whitelist_characters_disjoint_blacklist_characters():\n    good_chars = \"123abc\"\n    bad_chars = \"456def\"\n    st = characters(\n        min_codepoint=ord(\"0\"),\n        max_codepoint=ord(\"9\"),\n        exclude_characters=bad_chars,\n        include_characters=good_chars,\n    )\n\n    assert_no_examples(st, lambda c: c in bad_chars)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_simple_collections.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections import OrderedDict\nfrom random import Random\n\nimport pytest\n\nfrom hypothesis import given, settings\nfrom hypothesis.strategies import (\n    booleans,\n    dictionaries,\n    fixed_dictionaries,\n    frozensets,\n    integers,\n    lists,\n    none,\n    nothing,\n    sets,\n    text,\n    tuples,\n)\n\nfrom tests.common.debug import assert_simple_property, find_any, minimal\nfrom tests.common.utils import flaky\n\n\n@pytest.mark.parametrize(\n    (\"col\", \"strat\"),\n    [\n        ((), tuples()),\n        ([], lists(none(), max_size=0)),\n        (set(), sets(none(), max_size=0)),\n        (frozenset(), frozensets(none(), max_size=0)),\n        ({}, fixed_dictionaries({})),\n        ({}, fixed_dictionaries({}, optional={})),\n        (OrderedDict(), fixed_dictionaries(OrderedDict(), optional=OrderedDict())),\n        ({}, fixed_dictionaries({}, optional={1: booleans()})),\n        ({0: False}, fixed_dictionaries({0: booleans()}, optional={1: booleans()})),\n        ({}, fixed_dictionaries({}, optional={(): booleans(), 0: booleans()})),\n        ([], lists(nothing())),\n        ([], lists(nothing(), unique=True)),\n    ],\n)\ndef test_find_empty_collection_gives_empty(col, strat):\n    assert minimal(strat) == col\n\n\n@pytest.mark.parametrize(\n    (\"coltype\", \"strat\"), [(list, lists), (set, sets), (frozenset, frozensets)]\n)\ndef test_find_non_empty_collection_gives_single_zero(coltype, strat):\n    assert minimal(strat(integers()), bool) == coltype((0,))\n\n\n@pytest.mark.parametrize(\n    (\"coltype\", \"strat\"), [(list, lists), (set, sets), (frozenset, frozensets)]\n)\ndef test_minimizes_to_empty(coltype, strat):\n    assert minimal(strat(integers())) == coltype()\n\n\ndef test_minimizes_list_of_lists():\n    xs = minimal(lists(lists(booleans())), lambda x: any(x) and not all(x))\n    xs.sort()\n    assert xs == [[], [False]]\n\n\n@given(sets(integers(0, 100), min_size=2, max_size=10))\n@settings(max_examples=100)\ndef test_sets_are_size_bounded(xs):\n    assert 2 <= len(xs) <= 10\n\n\ndef test_ordered_dictionaries_preserve_keys():\n    r = Random()\n    keys = list(range(100))\n    r.shuffle(keys)\n    assert_simple_property(\n        fixed_dictionaries(OrderedDict([(k, booleans()) for k in keys])),\n        lambda x: list(x.keys()) == keys,\n    )\n\n\n@given(fixed_dictionaries({}, optional={0: booleans(), 1: nothing(), 2: booleans()}))\ndef test_fixed_dictionaries_with_optional_and_empty_keys(d):\n    assert 1 not in d\n\n\n@pytest.mark.parametrize(\"n\", range(10))\ndef test_lists_of_fixed_length(n):\n    assert minimal(lists(integers(), min_size=n, max_size=n)) == [0] * n\n\n\n@pytest.mark.parametrize(\"n\", range(10))\ndef test_sets_of_fixed_length(n):\n    x = minimal(sets(integers(), min_size=n, max_size=n))\n    assert len(x) == n\n\n    if n == 0:\n        assert x == set()\n    else:\n        assert x == set(range(min(x), min(x) + n))\n\n\n@pytest.mark.parametrize(\"n\", range(10))\ndef test_dictionaries_of_fixed_length(n):\n    x = set(minimal(dictionaries(integers(), booleans(), min_size=n, max_size=n)))\n\n    if not n:\n        assert x == set()\n    else:\n        assert x == set(range(min(x), min(x) + n))\n\n\n@pytest.mark.parametrize(\"n\", range(10))\ndef test_lists_of_lower_bounded_length(n):\n    l = minimal(lists(integers(), min_size=n), lambda x: sum(x) >= 2 * n)\n    assert l == [] if n == 0 else [0] * (n - 1) + [n * 2]\n\n\n@flaky(min_passes=1, max_runs=3)\ndef test_can_find_unique_lists_of_non_set_order():\n    # This test checks that our strategy for unique lists doesn't accidentally\n    # depend on the iteration order of sets.\n    #\n    # Unfortunately, that means that *this* test has to rely on set iteration\n    # order. That makes it tricky to debug on CPython, because set iteration\n    # order changes every time the process is launched.\n    #\n    # To get around this, define the PYTHONHASHSEED environment variable to\n    # a consistent value. This could be 0, or it could be the PYTHONHASHSEED\n    # value listed in a failure log from CI.\n\n    ls = minimal(\n        lists(text(), min_size=2, unique=True),\n        lambda x: list(set(reversed(x))) != x,  # noqa: C414  # yes, reverse inside set\n    )\n    assert len(set(ls)) == len(ls)\n    assert len(ls) == 2\n\n\ndef test_can_draw_empty_list_from_unsatisfiable_strategy():\n    assert find_any(lists(integers().filter(lambda s: False))) == []\n\n\ndef test_can_draw_empty_set_from_unsatisfiable_strategy():\n    assert find_any(sets(integers().filter(lambda s: False))) == set()\n\n\n@given(lists(sets(none()), min_size=10))\ndef test_small_sized_sets(x):\n    pass\n\n\ndef test_minimize_dicts_with_incompatible_keys():\n    strat = fixed_dictionaries({1: booleans(), \"hi\": lists(booleans())})\n    assert minimal(strat) == {1: False, \"hi\": []}\n\n\n@given(\n    lists(\n        tuples(integers(), integers()),\n        min_size=2,\n        unique_by=(lambda x: x[0], lambda x: x[1]),\n    )\n)\ndef test_lists_unique_by_tuple_funcs(ls):\n    firstitems, seconditems = zip(*ls, strict=True)\n    assert len(set(firstitems)) == len(firstitems)\n    assert len(set(seconditems)) == len(seconditems)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_simple_strings.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given\nfrom hypothesis.strategies import binary, characters, text, tuples\n\nfrom tests.common.debug import minimal\n\n\ndef test_can_minimize_up_to_zero():\n    s = minimal(text(), lambda x: any(t <= \"0\" for t in x))\n    assert s == \"0\"\n\n\ndef test_minimizes_towards_ascii_zero():\n    s = minimal(text(), lambda x: any(t < \"0\" for t in x))\n    assert s == chr(ord(\"0\") - 1)\n\n\ndef test_can_handle_large_codepoints():\n    s = minimal(text(), lambda x: x >= \"☃\")\n    assert s == \"☃\"\n\n\ndef test_can_find_mixed_ascii_and_non_ascii_strings():\n    s = minimal(\n        text(), lambda x: (any(t >= \"☃\" for t in x) and any(ord(t) <= 127 for t in x))\n    )\n    assert len(s) == 2\n    assert sorted(s) == [\"0\", \"☃\"]\n\n\ndef test_will_find_ascii_examples_given_the_chance():\n    s = minimal(\n        tuples(text(max_size=1), text(max_size=1)), lambda x: x[0] and (x[0] < x[1])\n    )\n    assert ord(s[1]) == ord(s[0]) + 1\n    assert \"0\" in s\n\n\ndef test_minimisation_consistent_with_characters():\n    s = minimal(text(\"FEDCBA\", min_size=3))\n    assert s == \"AAA\"\n\n\ndef test_finds_single_element_strings():\n    assert minimal(text(), bool) == \"0\"\n\n\n@given(binary(max_size=5))\ndef test_binary_respects_max_size(x):\n    assert len(x) <= 5\n\n\ndef test_does_not_simplify_into_surrogates():\n    f = minimal(text(), lambda x: x >= \"\\udfff\")\n    assert f == \"\\ue000\"\n\n    size = 5\n\n    f = minimal(text(min_size=size), lambda x: sum(t >= \"\\udfff\" for t in x) >= size)\n    assert f == \"\\ue000\" * size\n\n\n@given(text(alphabet=[\"a\", \"b\"]))\ndef test_respects_alphabet_if_list(xs):\n    assert set(xs).issubset(set(\"ab\"))\n\n\n@given(text(alphabet=\"cdef\"))\ndef test_respects_alphabet_if_string(xs):\n    assert set(xs).issubset(set(\"cdef\"))\n\n\n@given(text())\ndef test_can_encode_as_utf8(s):\n    s.encode()\n\n\n@given(text(characters(exclude_characters=\"\\n\")))\ndef test_can_blacklist_newlines(s):\n    assert \"\\n\" not in s\n\n\n@given(text(characters(exclude_categories=(\"Cc\", \"Cs\"))))\ndef test_can_exclude_newlines_by_category(s):\n    assert \"\\n\" not in s\n\n\n@given(text(characters(max_codepoint=127)))\ndef test_can_restrict_to_ascii_only(s):\n    s.encode(\"ascii\")\n\n\ndef test_fixed_size_bytes_just_draw_bytes():\n    from hypothesis.internal.conjecture.data import ConjectureData\n\n    x = ConjectureData.for_choices([b\"foo\"])\n    assert x.draw(binary(min_size=3, max_size=3)) == b\"foo\"\n\n\n@given(text(max_size=10**6))\ndef test_can_set_max_size_large(s):\n    pass\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_slices.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import HealthCheck, given, settings, strategies as st\n\nfrom tests.common.debug import assert_all_examples, find_any, minimal\n\nuse_several_sizes = pytest.mark.parametrize(\"size\", [1, 2, 5, 10, 100, 1000])\n\n\n@use_several_sizes\ndef test_stop_stays_within_bounds(size):\n    assert_all_examples(\n        st.slices(size),\n        lambda x: x.stop is None or (x.stop >= -size and x.stop <= size),\n    )\n\n\n@use_several_sizes\ndef test_start_stay_within_bounds(size):\n    assert_all_examples(\n        st.slices(size).filter(lambda x: x.start is not None),\n        lambda x: range(size)[x.start] or True,  # no IndexError raised\n    )\n\n\n@use_several_sizes\ndef test_step_stays_within_bounds(size):\n    # indices -> (start, stop, step)\n    # Stop is exclusive so we use -1 as the floor.\n    # This uses the indices that slice produces to make this test more readable\n    # due to how splice processes None being a little complex\n    assert_all_examples(\n        st.slices(size),\n        lambda x: (\n            x.indices(size)[0] + x.indices(size)[2] <= size\n            and x.indices(size)[0] + x.indices(size)[2] >= -size\n        )\n        or x.start % size == x.stop % size,\n    )\n\n\n@use_several_sizes\ndef test_step_will_not_be_zero(size):\n    assert_all_examples(st.slices(size), lambda x: x.step != 0)\n\n\n@use_several_sizes\ndef test_slices_will_shrink(size):\n    sliced = minimal(st.slices(size))\n    assert sliced.start == 0 or sliced.start is None\n    assert sliced.stop == 0 or sliced.stop is None\n    assert sliced.step is None\n\n\n@given(st.integers(1, 1000))\n@settings(deadline=None, suppress_health_check=list(HealthCheck))\ndef test_step_will_be_negative(size):\n    find_any(st.slices(size), lambda x: (x.step or 1) < 0)\n\n\n@given(st.integers(1, 1000))\n@settings(deadline=None)\ndef test_step_will_be_positive(size):\n    find_any(st.slices(size), lambda x: (x.step or 1) > 0)\n\n\n@pytest.mark.parametrize(\"size\", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\ndef test_stop_will_equal_size(size):\n    find_any(st.slices(size), lambda x: x.stop == size, settings(max_examples=10**6))\n\n\n@pytest.mark.parametrize(\"size\", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\ndef test_start_will_equal_size(size):\n    find_any(\n        st.slices(size), lambda x: x.start == size - 1, settings(max_examples=10**6)\n    )\n\n\n@given(st.integers(1, 1000))\n@settings(deadline=None, max_examples=20)\ndef test_start_will_equal_0(size):\n    find_any(st.slices(size), lambda x: x.start == 0)\n\n\n@given(st.integers(1, 1000))\n@settings(deadline=None)\ndef test_start_will_equal_stop(size):\n    find_any(st.slices(size), lambda x: x.start == x.stop)\n\n\ndef test_size_is_equal_0():\n    assert_all_examples(\n        st.slices(0), lambda x: x.step != 0 and x.start is None and x.stop is None\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_slippage.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import Phase, assume, given, settings, strategies as st, target\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.errors import FlakyFailure\nfrom hypothesis.internal.compat import ExceptionGroup\nfrom hypothesis.internal.conjecture.engine import MIN_TEST_CALLS\n\nfrom tests.common.utils import (\n    Why,\n    assert_output_contains_failure,\n    capture_out,\n    non_covering_examples,\n    xfail_on_crosshair,\n)\n\n\ndef capture_reports(test):\n    with capture_out() as o, pytest.raises(ExceptionGroup) as err:\n        test()\n\n    return o.getvalue() + \"\\n\\n\".join(\n        f\"{e!r}\\n\" + \"\\n\".join(getattr(e, \"__notes__\", []))\n        for e in (err.value, *err.value.exceptions)\n    )\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)\ndef test_raises_multiple_failures_with_varying_type():\n    target = None\n\n    @settings(database=None, max_examples=100, report_multiple_bugs=True)\n    @given(st.integers())\n    def test(i):\n        nonlocal target\n        if abs(i) < 1000:\n            return\n        if target is None:\n            # Ensure that we have some space to shrink into, so we can't\n            # trigger an minimal example and mask the other exception type.\n            assume(1003 < abs(i))\n            target = i\n        exc_class = TypeError if target == i else ValueError\n        raise exc_class\n\n    output = capture_reports(test)\n    assert \"TypeError\" in output\n    assert \"ValueError\" in output\n\n\n@pytest.mark.skipif(\n    settings().backend != \"hypothesis\", reason=\"no multiple failures on backends (yet?)\"\n)\ndef test_shows_target_scores_with_multiple_failures():\n    @settings(derandomize=True, max_examples=10_000)\n    @given(st.integers())\n    def test(i):\n        target(i)\n        assert i > 0\n        assert i < 0\n\n    assert \"Highest target score:\" in capture_reports(test)\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)\ndef test_raises_multiple_failures_when_position_varies():\n    target = None\n\n    @settings(max_examples=100, report_multiple_bugs=True)\n    @given(st.integers())\n    def test(i):\n        nonlocal target\n        if abs(i) < 1000:\n            return\n        if target is None:\n            target = i\n        if target == i:\n            raise ValueError(\"loc 1\")\n        else:\n            raise ValueError(\"loc 2\")\n\n    output = capture_reports(test)\n    assert \"loc 1\" in output\n    assert \"loc 2\" in output\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)\ndef test_replays_both_failing_values():\n    target = None\n\n    @settings(\n        database=InMemoryExampleDatabase(), max_examples=500, report_multiple_bugs=True\n    )\n    @given(st.integers())\n    def test(i):\n        nonlocal target\n        if abs(i) < 1000:\n            return\n        if target is None:\n            target = i\n        exc_class = TypeError if target == i else ValueError\n        raise exc_class\n\n    with pytest.raises(ExceptionGroup):\n        test()\n\n    with pytest.raises(ExceptionGroup):\n        test()\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)\n@pytest.mark.parametrize(\"fix\", [TypeError, ValueError])\ndef test_replays_slipped_examples_once_initial_bug_is_fixed(fix):\n    target = []\n    bug_fixed = False\n\n    @settings(\n        database=InMemoryExampleDatabase(), max_examples=500, report_multiple_bugs=True\n    )\n    @given(st.integers())\n    def test(i):\n        if abs(i) < 1000:\n            return\n        if not target:\n            target.append(i)\n        if i == target[0]:\n            if bug_fixed and fix == TypeError:\n                return\n            raise TypeError\n        if len(target) == 1:\n            target.append(i)\n        if bug_fixed and fix == ValueError:\n            return\n        if i == target[1]:\n            raise ValueError\n\n    with pytest.raises(ExceptionGroup):\n        test()\n\n    bug_fixed = True\n\n    with pytest.raises(ValueError if fix == TypeError else TypeError):\n        test()\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)\ndef test_garbage_collects_the_secondary_key():\n    target = []\n    bug_fixed = False\n\n    db = InMemoryExampleDatabase()\n\n    @settings(database=db, max_examples=500, report_multiple_bugs=True)\n    @given(st.integers())\n    def test(i):\n        if bug_fixed:\n            return\n        if abs(i) < 1000:\n            return\n        if not target:\n            target.append(i)\n        if i == target[0]:\n            raise TypeError\n        if len(target) == 1:\n            target.append(i)\n        if i == target[1]:\n            raise ValueError\n\n    with pytest.raises(ExceptionGroup):\n        test()\n\n    bug_fixed = True\n\n    def count():\n        return len(non_covering_examples(db))\n\n    prev = count()\n    while prev > 0:\n        test()\n        current = count()\n        assert current < prev\n        prev = current\n\n\ndef test_shrinks_both_failures():\n    first_has_failed = False\n    duds = set()\n    second_target = None\n\n    @settings(database=None, max_examples=1000, report_multiple_bugs=True)\n    @given(st.integers(min_value=0))\n    def test(i):\n        nonlocal first_has_failed, duds, second_target\n\n        if i >= 10000:\n            first_has_failed = True\n            raise AssertionError\n\n        assert i < 10000\n        if first_has_failed:\n            if second_target is None:\n                for j in range(10000):\n                    if j not in duds:\n                        second_target = j\n                        break\n            # to avoid flaky errors, don't error on an input that we previously\n            # passed.\n            if i not in duds:\n                assert i < second_target\n        else:\n            duds.add(i)\n\n    output = capture_reports(test)\n    assert_output_contains_failure(output, test, i=10000)\n    assert_output_contains_failure(output, test, i=second_target)\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)\ndef test_handles_flaky_tests_where_only_one_is_flaky():\n    flaky_fixed = False\n\n    target = []\n    flaky_failed_once = False\n\n    @settings(\n        database=InMemoryExampleDatabase(), max_examples=1000, report_multiple_bugs=True\n    )\n    @given(st.integers())\n    def test(i):\n        nonlocal flaky_failed_once\n        if abs(i) < 1000:\n            return\n        if not target:\n            target.append(i)\n        if i == target[0]:\n            raise TypeError\n        if flaky_failed_once and not flaky_fixed:\n            return\n        if len(target) == 1:\n            target.append(i)\n        if i == target[1]:\n            flaky_failed_once = True\n            raise ValueError\n\n    with pytest.raises(ExceptionGroup) as err:\n        test()\n    assert any(isinstance(e, FlakyFailure) for e in err.value.exceptions)\n\n    flaky_fixed = True\n\n    with pytest.raises(ExceptionGroup) as err:\n        test()\n    assert not any(isinstance(e, FlakyFailure) for e in err.value.exceptions)\n\n\n@pytest.mark.skipif(\n    settings().backend != \"hypothesis\", reason=\"no multiple failures on backends (yet?)\"\n)\n@pytest.mark.parametrize(\"allow_multi\", [True, False])\ndef test_can_disable_multiple_error_reporting(allow_multi):\n    seen = set()\n\n    @settings(database=None, derandomize=True, report_multiple_bugs=allow_multi)\n    @given(st.integers(min_value=0))\n    def test(i):\n        # We will pass on the minimal i=0, then fail with a large i, and eventually\n        # slip to i=1 and a different error.  We check both seen and raised errors.\n        if i == 1:\n            seen.add(TypeError)\n            raise TypeError\n        elif i >= 2:\n            seen.add(ValueError)\n            raise ValueError\n\n    with pytest.raises(ExceptionGroup if allow_multi else TypeError):\n        test()\n    assert seen == {TypeError, ValueError}\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)\ndef test_finds_multiple_failures_in_generation():\n    special = None\n    seen = set()\n\n    @settings(\n        phases=[Phase.generate, Phase.shrink],\n        max_examples=100,\n        report_multiple_bugs=True,\n    )\n    @given(st.integers(min_value=0))\n    def test(x):\n        \"\"\"Constructs a test so the 10th largeish example we've seen is a\n        special failure, and anything new we see after that point that\n        is larger than it is a different failure. This demonstrates that we\n        can keep generating larger examples and still find new bugs after that\n        point.\"\"\"\n        nonlocal special\n        if not special:\n            # don't mark duplicate inputs as special and thus erroring, to avoid\n            # flakiness where we passed the input the first time but failed it the\n            # second.\n            if len(seen) >= 10 and x <= 1000 and x not in seen:\n                special = x\n            else:\n                seen.add(x)\n\n        if special:\n            assert x in seen or x <= special\n        assert x != special\n\n    with pytest.raises(ExceptionGroup):\n        test()\n\n\ndef test_stops_immediately_if_not_report_multiple_bugs():\n    seen = set()\n\n    @settings(phases=[Phase.generate], report_multiple_bugs=False)\n    @given(st.integers())\n    def test(x):\n        seen.add(x)\n        raise AssertionError\n\n    with pytest.raises(AssertionError):\n        test()\n    assert len(seen) == 1\n\n\n@pytest.mark.skipif(\n    settings().backend != \"hypothesis\", reason=\"unclear backend semantics\"\n)\ndef test_stops_immediately_on_replay():\n    seen = set()\n\n    @settings(database=InMemoryExampleDatabase(), phases=tuple(Phase)[:-1])\n    @given(st.integers())\n    def test(x):\n        seen.add(x)\n        assert x\n\n    # On the first run, we look for up to ten examples:\n    with pytest.raises(AssertionError):\n        test()\n    assert 1 < len(seen) <= MIN_TEST_CALLS\n\n    # With failing examples in the database, we stop at one.\n    seen.clear()\n    with pytest.raises(AssertionError):\n        test()\n    assert len(seen) == 1\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_stateful.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\nfrom collections import defaultdict\nfrom typing import ClassVar\n\nimport pytest\nfrom _pytest.outcomes import Failed, Skipped\nfrom pytest import raises\n\nfrom hypothesis import (\n    HealthCheck,\n    Phase,\n    __version__,\n    reproduce_failure,\n    seed,\n    settings as Settings,\n    strategies as st,\n)\nfrom hypothesis.control import current_build_context\nfrom hypothesis.core import encode_failure\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.errors import (\n    DidNotReproduce,\n    Flaky,\n    FlakyStrategyDefinition,\n    InvalidArgument,\n    InvalidDefinition,\n)\nfrom hypothesis.stateful import (\n    Bundle,\n    RuleBasedStateMachine,\n    consumes,\n    get_state_machine_test,\n    initialize,\n    invariant,\n    multiple,\n    precondition,\n    rule,\n    run_state_machine_as_test,\n)\nfrom hypothesis.strategies import binary, data, integers, just, lists\n\nfrom tests.common.utils import (\n    Why,\n    capture_out,\n    skipif_threading,\n    validate_deprecation,\n    xfail_on_crosshair,\n)\nfrom tests.nocover.test_stateful import DepthMachine\n\nNO_BLOB_SETTINGS = Settings(print_blob=False, phases=tuple(Phase)[:-1])\n\n\nclass MultipleRulesSameFuncMachine(RuleBasedStateMachine):\n    def myfunc(self, data):\n        print(data)\n\n    rule1 = rule(data=just(\"rule1data\"))(myfunc)\n    rule2 = rule(data=just(\"rule2data\"))(myfunc)\n\n\nclass PreconditionMachine(RuleBasedStateMachine):\n    num = 0\n\n    @rule()\n    def add_one(self):\n        self.num += 1\n\n    @rule()\n    def set_to_zero(self):\n        self.num = 0\n\n    @rule(num=integers())\n    @precondition(lambda self: self.num != 0)\n    def div_by_precondition_after(self, num):\n        self.num = num / self.num\n\n    @precondition(lambda self: self.num != 0)\n    @rule(num=integers())\n    def div_by_precondition_before(self, num):\n        self.num = num / self.num\n\n\nTestPrecondition = PreconditionMachine.TestCase\nTestPrecondition.settings = Settings(TestPrecondition.settings, max_examples=10)\n\n\ndef test_picks_up_settings_at_first_use_of_testcase():\n    assert TestPrecondition.settings.max_examples == 10\n\n\ndef test_multiple_rules_same_func():\n    test_class = MultipleRulesSameFuncMachine.TestCase\n    with capture_out() as o:\n        test_class().runTest()\n    output = o.getvalue()\n    assert \"rule1data\" in output\n    assert \"rule2data\" in output\n\n\ndef test_can_get_test_case_off_machine_instance():\n    assert DepthMachine().TestCase is DepthMachine().TestCase\n    assert DepthMachine().TestCase is not None\n\n\nclass FlakyDrawLessMachine(RuleBasedStateMachine):\n    @rule(d=data())\n    def action(self, d):\n        if current_build_context().is_final:\n            d.draw(binary(min_size=1, max_size=1))\n        else:\n            buffer = binary(min_size=1024, max_size=1024)\n            assert 0 not in buffer\n\n\ndef test_flaky_draw_less_raises_flaky():\n    with raises(Flaky):\n        FlakyDrawLessMachine.TestCase().runTest()\n\n\ndef test_result_is_added_to_target():\n    class TargetStateMachine(RuleBasedStateMachine):\n        nodes = Bundle(\"nodes\")\n\n        @rule(target=nodes, source=lists(nodes))\n        def bunch(self, source):\n            assert len(source) == 0\n            return source\n\n    test_class = TargetStateMachine.TestCase\n    try:\n        test_class().runTest()\n        raise RuntimeError(\"Expected an assertion error\")\n    except AssertionError as err:\n        notes = err.__notes__\n    regularized_notes = [re.sub(r\"[0-9]+\", \"i\", note) for note in notes]\n    assert \"state.bunch(source=[nodes_i])\" in regularized_notes\n\n\nclass FlakyStateMachine(RuleBasedStateMachine):\n    @rule()\n    def action(self):\n        assert current_build_context().is_final\n\n\ndef test_flaky_raises_flaky():\n    with raises(Flaky):\n        FlakyStateMachine.TestCase().runTest()\n\n\nclass FlakyPreconditionMachine(RuleBasedStateMachine):\n    @precondition(lambda self: not current_build_context().is_final)\n    @rule()\n    def action(self):\n        raise AssertionError\n\n\ndef test_flaky_precondition_error_message():\n    with raises(FlakyStrategyDefinition) as exc_info:\n        FlakyPreconditionMachine.TestCase().runTest()\n    assert any(\"flaky precondition\" in note for note in exc_info.value.__notes__)\n\n\nclass FlakyDrawInRuleMachine(RuleBasedStateMachine):\n    # Flakiness inside rule execution (via data().draw()) happens AFTER rule selection,\n    # so the \"flaky precondition\" note should NOT be added.\n    @rule(d=data())\n    def action(self, d):\n        if current_build_context().is_final:\n            d.draw(st.integers(0, 0))\n        d.draw(st.integers())\n        raise AssertionError\n\n\ndef test_flaky_draw_in_rule_no_precondition_note():\n    # When flakiness occurs during rule execution (not rule selection),\n    # the error message should NOT mention flaky preconditions.\n    with raises(FlakyStrategyDefinition) as exc_info:\n        FlakyDrawInRuleMachine.TestCase().runTest()\n    notes = getattr(exc_info.value, \"__notes__\", [])\n    assert not any(\"flaky precondition\" in note for note in notes)\n\n\ndef test_get_state_machine_test_is_importable():\n    # Regression test: get_state_machine_test is used by HypoFuzz\n    assert callable(get_state_machine_test)\n\n\nclass FlakyRatchettingMachine(RuleBasedStateMachine):\n    ratchet = 0\n\n    @rule(d=data())\n    def action(self, d):\n        FlakyRatchettingMachine.ratchet += 1\n        n = FlakyRatchettingMachine.ratchet\n        d.draw(lists(integers(), min_size=n, max_size=n))\n        raise AssertionError\n\n\n@Settings(\n    stateful_step_count=10,\n    max_examples=30,\n    suppress_health_check=[HealthCheck.filter_too_much],\n)  # speed this up\nclass MachineWithConsumingRule(RuleBasedStateMachine):\n    b1 = Bundle(\"b1\")\n    b2 = Bundle(\"b2\")\n\n    def __init__(self):\n        self.created_counter = 0\n        self.consumed_counter = 0\n        super().__init__()\n\n    @invariant()\n    def bundle_length(self):\n        assert len(self.bundle(\"b1\")) == self.created_counter - self.consumed_counter\n\n    @rule(target=b1)\n    def populate_b1(self):\n        self.created_counter += 1\n        return self.created_counter\n\n    @rule(target=b2, consumed=consumes(b1))\n    def depopulate_b1(self, consumed):\n        self.consumed_counter += 1\n        return consumed\n\n    @rule(consumed=lists(consumes(b1), max_size=3))\n    def depopulate_b1_multiple(self, consumed):\n        self.consumed_counter += len(consumed)\n\n    @rule(value1=b1, value2=b2)\n    def check(self, value1, value2):\n        assert value1 != value2\n\n\nTestMachineWithConsumingRule = MachineWithConsumingRule.TestCase\n\n\ndef test_multiple():\n    none = multiple()\n    some = multiple(1, 2.01, \"3\", b\"4\", 5)\n    assert len(none.values) == 0\n    assert len(some.values) == 5\n    assert set(some.values) == {1, 2.01, \"3\", b\"4\", 5}\n\n\nclass MachineUsingMultiple(RuleBasedStateMachine):\n    b = Bundle(\"b\")\n\n    def __init__(self):\n        self.expected_bundle_length = 0\n        super().__init__()\n\n    @invariant()\n    def bundle_length(self):\n        assert len(self.bundle(\"b\")) == self.expected_bundle_length\n\n    @rule(target=b, items=lists(elements=integers(), max_size=10))\n    def populate_bundle(self, items):\n        self.expected_bundle_length += len(items)\n        return multiple(*items)\n\n    @rule(target=b)\n    def do_not_populate(self):\n        return multiple()\n\n\nTestMachineUsingMultiple = MachineUsingMultiple.TestCase\n\n\ndef test_multiple_variables_printed():\n    class ProducesMultiple(RuleBasedStateMachine):\n        b = Bundle(\"b\")\n\n        @initialize(target=b)\n        def populate_bundle(self):\n            return multiple(1, 2)\n\n        @rule()\n        def fail_fast(self):\n            raise AssertionError\n\n    with raises(AssertionError) as err:\n        run_state_machine_as_test(ProducesMultiple)\n\n    # This is tightly coupled to the output format of the step printing.\n    # The first line is \"Falsifying Example:...\" the second is creating\n    # the state machine, the third is calling the \"initialize\" method.\n    assignment_line = err.value.__notes__[2]\n    # 'populate_bundle()' returns 2 values, so should be\n    # expanded to 2 variables.\n    assert assignment_line == \"b_0, b_1 = state.populate_bundle()\"\n\n    # Make sure MultipleResult is iterable so the printed code is valid.\n    # See https://github.com/HypothesisWorks/hypothesis/issues/2311\n    state = ProducesMultiple()\n    _b_0, _b_1 = state.populate_bundle()\n    with raises(AssertionError):\n        state.fail_fast()\n\n\ndef test_multiple_variables_printed_single_element():\n    # https://github.com/HypothesisWorks/hypothesis/issues/3236\n    class ProducesMultiple(RuleBasedStateMachine):\n        b = Bundle(\"b\")\n\n        @initialize(target=b)\n        def populate_bundle(self):\n            return multiple(1)\n\n        @rule(b=b)\n        def fail_fast(self, b):\n            assert b != 1\n\n    with raises(AssertionError) as err:\n        run_state_machine_as_test(ProducesMultiple)\n\n    assignment_line = err.value.__notes__[2]\n    assert assignment_line == \"(b_0,) = state.populate_bundle()\"\n\n    state = ProducesMultiple()\n    (v1,) = state.populate_bundle()\n    state.fail_fast((v1,))  # passes if tuple not unpacked\n    with raises(AssertionError):\n        state.fail_fast(v1)\n\n\ndef test_no_variables_printed():\n    class ProducesNoVariables(RuleBasedStateMachine):\n        b = Bundle(\"b\")\n\n        @initialize(target=b)\n        def populate_bundle(self):\n            return multiple()\n\n        @rule()\n        def fail_fast(self):\n            raise AssertionError\n\n    with raises(AssertionError) as err:\n        run_state_machine_as_test(ProducesNoVariables)\n\n    # This is tightly coupled to the output format of the step printing.\n    # The first line is \"Falsifying Example:...\" the second is creating\n    # the state machine, the third is calling the \"initialize\" method.\n    assignment_line = err.value.__notes__[2]\n    # 'populate_bundle()' returns 0 values, so there should be no\n    # variable assignment.\n    assert assignment_line == \"state.populate_bundle()\"\n\n\ndef test_consumes_typecheck():\n    with pytest.raises(TypeError):\n        consumes(integers())\n\n\ndef test_ratchetting_raises_flaky():\n    with raises(Flaky):\n        FlakyRatchettingMachine.TestCase().runTest()\n\n\ndef test_empty_machine_is_invalid():\n    class EmptyMachine(RuleBasedStateMachine):\n        pass\n\n    with raises(InvalidDefinition):\n        EmptyMachine.TestCase().runTest()\n\n\ndef test_machine_with_no_terminals_is_invalid():\n    class NonTerminalMachine(RuleBasedStateMachine):\n        @rule(value=Bundle(\"hi\"))\n        def bye(self, hi):\n            pass\n\n    with raises(InvalidDefinition):\n        NonTerminalMachine.TestCase().runTest()\n\n\ndef test_minimizes_errors_in_teardown():\n    # temporary debugging to try to narrow down a potential thread-safety issue\n    import threading\n\n    from hypothesis import Verbosity\n\n    counter = 0\n\n    @Settings(database=None, verbosity=Verbosity.debug)\n    class Foo(RuleBasedStateMachine):\n        @initialize()\n        def init(self):\n            nonlocal counter\n            counter = 0\n            print(f\"[{threading.get_ident()}] init\", counter)\n\n        @rule()\n        def increment(self):\n            nonlocal counter\n            counter += 1\n            print(f\"[{threading.get_ident()}] increment\", counter)\n\n        def teardown(self):\n            nonlocal counter\n            print(f\"[{threading.get_ident()}] teardown\", counter)\n            assert not counter\n\n    with raises(AssertionError):\n        run_state_machine_as_test(Foo)\n    assert counter == 1\n\n\nclass RequiresInit(RuleBasedStateMachine):\n    def __init__(self, threshold):\n        super().__init__()\n        self.threshold = threshold\n\n    @rule(value=integers())\n    def action(self, value):\n        if value > self.threshold:\n            raise ValueError(f\"{value} is too high\")\n\n\ndef test_can_use_factory_for_tests():\n    with raises(ValueError):\n        run_state_machine_as_test(\n            lambda: RequiresInit(42), settings=Settings(max_examples=100)\n        )\n\n\nclass FailsEventually(RuleBasedStateMachine):\n    def __init__(self):\n        super().__init__()\n        self.counter = 0\n\n    @rule()\n    def increment(self):\n        self.counter += 1\n        assert self.counter < 10\n\n\nFailsEventually.TestCase.settings = Settings(stateful_step_count=5)\n\n\n@skipif_threading\ndef test_can_explicitly_pass_settings():\n    run_state_machine_as_test(FailsEventually)\n    try:\n        FailsEventually.TestCase.settings = Settings(\n            FailsEventually.TestCase.settings, stateful_step_count=15\n        )\n        run_state_machine_as_test(\n            FailsEventually, settings=Settings(stateful_step_count=2)\n        )\n    finally:\n        FailsEventually.TestCase.settings = Settings(\n            FailsEventually.TestCase.settings, stateful_step_count=5\n        )\n\n\ndef test_settings_argument_is_validated():\n    with pytest.raises(InvalidArgument):\n        run_state_machine_as_test(FailsEventually, settings=object())\n\n\ndef test_runner_that_checks_factory_produced_a_machine():\n    with pytest.raises(InvalidArgument):\n        run_state_machine_as_test(object)\n\n\n@skipif_threading\ndef test_settings_attribute_is_validated():\n    real_settings = FailsEventually.TestCase.settings\n    try:\n        FailsEventually.TestCase.settings = object()\n        with pytest.raises(InvalidArgument):\n            run_state_machine_as_test(FailsEventually)\n    finally:\n        FailsEventually.TestCase.settings = real_settings\n\n\ndef test_saves_failing_example_in_database():\n    db = InMemoryExampleDatabase()\n    ss = Settings(\n        database=db, max_examples=1000, suppress_health_check=list(HealthCheck)\n    )\n    with raises(AssertionError):\n        run_state_machine_as_test(DepthMachine, settings=ss)\n    assert any(list(db.data.values()))\n\n\ndef test_can_run_with_no_db():\n    with raises(AssertionError):\n        run_state_machine_as_test(\n            DepthMachine, settings=Settings(database=None, max_examples=10_000)\n        )\n\n\ndef test_stateful_double_rule_is_forbidden(recwarn):\n    with pytest.raises(InvalidDefinition):\n\n        class DoubleRuleMachine(RuleBasedStateMachine):\n            @rule(num=just(1))\n            @rule(num=just(2))\n            def whatevs(self, num):\n                pass\n\n\ndef test_can_explicitly_call_functions_when_precondition_not_satisfied():\n    class BadPrecondition(RuleBasedStateMachine):\n        def __init__(self):\n            super().__init__()\n\n        @precondition(lambda self: False)\n        @rule()\n        def test_blah(self):\n            raise ValueError\n\n        @rule()\n        def test_foo(self):\n            self.test_blah()\n\n    with pytest.raises(ValueError):\n        run_state_machine_as_test(BadPrecondition)\n\n\ndef test_invariant():\n    \"\"\"If an invariant raise an exception, the exception is propagated.\"\"\"\n\n    class Invariant(RuleBasedStateMachine):\n        def __init__(self):\n            super().__init__()\n\n        @invariant()\n        def test_blah(self):\n            raise ValueError\n\n        @rule()\n        def do_stuff(self):\n            pass\n\n    with pytest.raises(ValueError):\n        run_state_machine_as_test(Invariant)\n\n\ndef test_no_double_invariant():\n    \"\"\"The invariant decorator can't be applied multiple times to a single\n    function.\"\"\"\n    with raises(InvalidDefinition):\n\n        class Invariant(RuleBasedStateMachine):\n            def __init__(self):\n                super().__init__()\n\n            @invariant()\n            @invariant()\n            def test_blah(self):\n                pass\n\n            @rule()\n            def do_stuff(self):\n                pass\n\n\ndef test_invariant_precondition():\n    \"\"\"If an invariant precodition isn't met, the invariant isn't run.\n\n    The precondition decorator can be applied in any order.\n    \"\"\"\n\n    class Invariant(RuleBasedStateMachine):\n        def __init__(self):\n            super().__init__()\n\n        @invariant()\n        @precondition(lambda _: False)\n        def an_invariant(self):\n            raise ValueError\n\n        @precondition(lambda _: False)\n        @invariant()\n        def another_invariant(self):\n            raise ValueError\n\n        @rule()\n        def do_stuff(self):\n            pass\n\n    run_state_machine_as_test(Invariant)\n\n\n@pytest.mark.parametrize(\n    \"decorators\",\n    [\n        (invariant(), rule()),\n        (rule(), invariant()),\n        (invariant(), initialize()),\n        (initialize(), invariant()),\n        (invariant(), precondition(lambda self: True), rule()),\n        (rule(), precondition(lambda self: True), invariant()),\n        (precondition(lambda self: True), invariant(), rule()),\n        (precondition(lambda self: True), rule(), invariant()),\n    ],\n    ids=lambda x: \"-\".join(f.__qualname__.split(\".\")[0] for f in x),\n)\ndef test_invariant_and_rule_are_incompatible(decorators):\n    \"\"\"It's an error to apply @invariant and @rule to the same method.\"\"\"\n\n    def method(self):\n        pass\n\n    for d in decorators[:-1]:\n        method = d(method)\n    with pytest.raises(InvalidDefinition):\n        decorators[-1](method)\n\n\ndef test_invalid_rule_argument():\n    \"\"\"Rule kwargs that are not a Strategy are expected to raise an InvalidArgument error.\"\"\"\n    with pytest.raises(InvalidArgument):\n\n        class InvalidRuleMachine(RuleBasedStateMachine):\n            @rule(strategy=object())\n            def do_stuff(self):\n                pass\n\n\ndef test_invalid_initialize_argument():\n    \"\"\"Initialize kwargs that are not a Strategy are expected to raise an InvalidArgument error.\"\"\"\n    with pytest.raises(InvalidArgument):\n\n        class InvalidInitialize(RuleBasedStateMachine):\n            @initialize(strategy=object())\n            def initialize(self):\n                pass\n\n\ndef test_multiple_invariants():\n    \"\"\"If multiple invariants are present, they all get run.\"\"\"\n\n    class Invariant(RuleBasedStateMachine):\n        def __init__(self):\n            super().__init__()\n            self.first_invariant_ran = False\n\n        @invariant()\n        def invariant_1(self):\n            self.first_invariant_ran = True\n\n        @precondition(lambda self: self.first_invariant_ran)\n        @invariant()\n        def invariant_2(self):\n            raise ValueError\n\n        @rule()\n        def do_stuff(self):\n            pass\n\n    with pytest.raises(ValueError):\n        run_state_machine_as_test(Invariant)\n\n\ndef test_explicit_invariant_call_with_precondition():\n    \"\"\"Invariants can be called explicitly even if their precondition is not\n    satisfied.\"\"\"\n\n    class BadPrecondition(RuleBasedStateMachine):\n        def __init__(self):\n            super().__init__()\n\n        @precondition(lambda self: False)\n        @invariant()\n        def test_blah(self):\n            raise ValueError\n\n        @rule()\n        def test_foo(self):\n            self.test_blah()\n\n    with pytest.raises(ValueError):\n        run_state_machine_as_test(BadPrecondition)\n\n\ndef test_invariant_checks_initial_state_if_no_initialize_rules():\n    \"\"\"Invariants are checked before any rules run.\"\"\"\n\n    class BadPrecondition(RuleBasedStateMachine):\n        def __init__(self):\n            super().__init__()\n            self.num = 0\n\n        @invariant()\n        def test_blah(self):\n            if self.num == 0:\n                raise ValueError\n\n        @rule()\n        def test_foo(self):\n            self.num += 1\n\n    with pytest.raises(ValueError):\n        run_state_machine_as_test(BadPrecondition)\n\n\ndef test_invariant_failling_present_in_falsifying_example():\n    @Settings(print_blob=False)\n    class BadInvariant(RuleBasedStateMachine):\n        @initialize()\n        def initialize_1(self):\n            pass\n\n        @invariant()\n        def invariant_1(self):\n            raise ValueError\n\n        @rule()\n        def rule_1(self):\n            pass\n\n    with pytest.raises(ValueError) as err:\n        run_state_machine_as_test(BadInvariant)\n\n    result = \"\\n\".join(err.value.__notes__)\n    assert (\n        result\n        == \"\"\"\nFalsifying example:\nstate = BadInvariant()\nstate.initialize_1()\nstate.invariant_1()\nstate.teardown()\n\"\"\".strip()\n    )\n\n\ndef test_invariant_present_in_falsifying_example():\n    @Settings(print_blob=False, phases=tuple(Phase)[:-1])\n    class BadRuleWithGoodInvariants(RuleBasedStateMachine):\n        def __init__(self):\n            super().__init__()\n            self.num = 0\n\n        @initialize()\n        def initialize_1(self):\n            pass\n\n        @invariant(check_during_init=True)\n        def invariant_1(self):\n            pass\n\n        @invariant(check_during_init=False)\n        def invariant_2(self):\n            pass\n\n        @precondition(lambda self: self.num > 0)\n        @invariant()\n        def invariant_3(self):\n            pass\n\n        @rule()\n        def rule_1(self):\n            self.num += 1\n            if self.num == 2:\n                raise ValueError\n\n    with pytest.raises(ValueError) as err:\n        run_state_machine_as_test(BadRuleWithGoodInvariants)\n\n    expected = \"\"\"\nFalsifying example:\nstate = BadRuleWithGoodInvariants()\nstate.invariant_1()\nstate.initialize_1()\nstate.invariant_1()\nstate.invariant_2()\nstate.rule_1()\nstate.invariant_1()\nstate.invariant_2()\nstate.invariant_3()\nstate.rule_1()\nstate.teardown()\n\"\"\".strip()\n\n    result = \"\\n\".join(err.value.__notes__).strip()\n    assert expected == result\n\n\ndef test_always_runs_at_least_one_step():\n    class CountSteps(RuleBasedStateMachine):\n        def __init__(self):\n            super().__init__()\n            self.count = 0\n\n        @rule()\n        def do_something(self):\n            self.count += 1\n\n        def teardown(self):\n            assert self.count > 0\n\n    run_state_machine_as_test(CountSteps)\n\n\ndef test_removes_needless_steps():\n    \"\"\"Regression test from an example based on\n    tests/nocover/test_database_agreement.py, but without the expensive bits.\n    Comparing two database implementations in which deletion is broken, so as\n    soon as a key/value pair is successfully deleted the test will now fail if\n    you ever check that key.\n\n    The main interesting feature of this is that it has a lot of\n    opportunities to generate keys and values before it actually fails,\n    but will still fail with very high probability.\n    \"\"\"\n\n    @Settings(derandomize=True, max_examples=1000, deadline=None)\n    class IncorrectDeletion(RuleBasedStateMachine):\n        def __init__(self):\n            super().__init__()\n            self.__saved = defaultdict(set)\n            self.__deleted = defaultdict(set)\n\n        keys = Bundle(\"keys\")\n        values = Bundle(\"values\")\n\n        @rule(target=keys, k=binary())\n        def k(self, k):\n            return k\n\n        @rule(target=values, v=binary())\n        def v(self, v):\n            return v\n\n        @rule(k=keys, v=values)\n        def save(self, k, v):\n            self.__saved[k].add(v)\n\n        @rule(k=keys, v=values)\n        def delete(self, k, v):\n            if v in self.__saved[k]:\n                self.__deleted[k].add(v)\n\n        @rule(k=keys)\n        def values_agree(self, k):\n            assert not self.__deleted[k]\n\n    with pytest.raises(AssertionError) as err:\n        run_state_machine_as_test(IncorrectDeletion)\n\n    result = \"\\n\".join(err.value.__notes__)\n    assert result.count(\" = state.k(\") == 1\n    assert result.count(\" = state.v(\") == 1\n\n\ndef test_prints_equal_values_with_correct_variable_name():\n    @Settings(max_examples=100, suppress_health_check=list(HealthCheck))\n    class MovesBetweenBundles(RuleBasedStateMachine):\n        b1 = Bundle(\"b1\")\n        b2 = Bundle(\"b2\")\n\n        @rule(target=b1)\n        def create(self):\n            return []\n\n        @rule(target=b2, source=b1)\n        def transfer(self, source):\n            return source\n\n        @rule(source=b2)\n        def fail(self, source):\n            raise AssertionError\n\n    with pytest.raises(AssertionError) as err:\n        run_state_machine_as_test(MovesBetweenBundles)\n\n    result = \"\\n\".join(err.value.__notes__)\n    for m in [\"create\", \"transfer\", \"fail\"]:\n        assert result.count(\"state.\" + m) == 1\n    assert \"b1_0 = state.create()\" in result\n    assert \"b2_0 = state.transfer(source=b1_0)\" in result\n    assert \"state.fail(source=b2_0)\" in result\n\n\ndef test_initialize_rule():\n    @Settings(max_examples=1000)\n    class WithInitializeRules(RuleBasedStateMachine):\n        initialized: ClassVar = []\n\n        @initialize()\n        def initialize_a(self):\n            self.initialized.append(\"a\")\n\n        @initialize()\n        def initialize_b(self):\n            self.initialized.append(\"b\")\n\n        @initialize()\n        def initialize_c(self):\n            self.initialized.append(\"c\")\n\n        @rule()\n        def fail_fast(self):\n            raise AssertionError\n\n    with pytest.raises(AssertionError) as err:\n        run_state_machine_as_test(WithInitializeRules)\n\n    assert set(WithInitializeRules.initialized[-3:]) == {\"a\", \"b\", \"c\"}\n    result = err.value.__notes__[1:]\n    assert result[0] == \"state = WithInitializeRules()\"\n    # Initialize rules call order is shuffled\n    assert {result[1], result[2], result[3]} == {\n        \"state.initialize_a()\",\n        \"state.initialize_b()\",\n        \"state.initialize_c()\",\n    }\n    assert result[4] == \"state.fail_fast()\"\n    assert result[5] == \"state.teardown()\"\n\n\ndef test_initialize_rule_populate_bundle():\n    class WithInitializeBundleRules(RuleBasedStateMachine):\n        a = Bundle(\"a\")\n\n        @initialize(target=a, dep=just(\"dep\"))\n        def initialize_a(self, dep):\n            return f\"a a_0 with ({dep})\"\n\n        @rule(param=a)\n        def fail_fast(self, param):\n            raise AssertionError\n\n    WithInitializeBundleRules.TestCase.settings = NO_BLOB_SETTINGS\n    with pytest.raises(AssertionError) as err:\n        run_state_machine_as_test(WithInitializeBundleRules)\n\n    result = \"\\n\".join(err.value.__notes__)\n    assert (\n        result\n        == \"\"\"\nFalsifying example:\nstate = WithInitializeBundleRules()\na_0 = state.initialize_a(dep='dep')\nstate.fail_fast(param=a_0)\nstate.teardown()\n\"\"\".strip()\n    )\n\n\ndef test_initialize_rule_dont_mix_with_precondition():\n    with pytest.raises(\n        InvalidDefinition,\n        match=(\n            \"BadStateMachine\\\\.initialize has been decorated with both @initialize \"\n            \"and @precondition\"\n        ),\n    ):\n\n        class BadStateMachine(RuleBasedStateMachine):\n            @precondition(lambda self: True)\n            @initialize()\n            def initialize(self):\n                pass\n\n    # Also test decorator application in reverse order\n\n    with pytest.raises(\n        InvalidDefinition,\n        match=(\n            \"BadStateMachineReverseOrder\\\\.initialize has been decorated with both \"\n            \"@initialize and @precondition\"\n        ),\n    ):\n\n        class BadStateMachineReverseOrder(RuleBasedStateMachine):\n            @initialize()\n            @precondition(lambda self: True)\n            def initialize(self):\n                pass\n\n\ndef test_initialize_rule_dont_mix_with_regular_rule():\n    with pytest.raises(\n        InvalidDefinition,\n        match=\"BadStateMachine\\\\.initialize has been decorated with both @rule and @initialize\",\n    ):\n\n        class BadStateMachine(RuleBasedStateMachine):\n            @rule()\n            @initialize()\n            def initialize(self):\n                pass\n\n    with pytest.raises(\n        InvalidDefinition,\n        match=(\n            \"BadStateMachineReverseOrder\\\\.initialize has been decorated with both \"\n            \"@rule and @initialize\"\n        ),\n    ):\n\n        class BadStateMachineReverseOrder(RuleBasedStateMachine):\n            @initialize()\n            @rule()\n            def initialize(self):\n                pass\n\n\ndef test_initialize_rule_cannot_be_double_applied():\n    with pytest.raises(\n        InvalidDefinition,\n        match=\"BadStateMachine\\\\.initialize has been decorated with @initialize twice\",\n    ):\n\n        class BadStateMachine(RuleBasedStateMachine):\n            @initialize()\n            @initialize()\n            def initialize(self):\n                pass\n\n\ndef test_initialize_rule_in_state_machine_with_inheritance():\n    class ParentStateMachine(RuleBasedStateMachine):\n        initialized: ClassVar = []\n\n        @initialize()\n        def initialize_a(self):\n            self.initialized.append(\"a\")\n\n    class ChildStateMachine(ParentStateMachine):\n        @initialize()\n        def initialize_b(self):\n            self.initialized.append(\"b\")\n\n        @rule()\n        def fail_fast(self):\n            raise AssertionError\n\n    with pytest.raises(AssertionError) as err:\n        run_state_machine_as_test(ChildStateMachine)\n\n    assert set(ChildStateMachine.initialized[-2:]) == {\"a\", \"b\"}\n    result = err.value.__notes__[1:]\n    assert result[0] == \"state = ChildStateMachine()\"\n    # Initialize rules call order is shuffled\n    assert {result[1], result[2]} == {\"state.initialize_a()\", \"state.initialize_b()\"}\n    assert result[3] == \"state.fail_fast()\"\n    assert result[4] == \"state.teardown()\"\n\n\ndef test_can_manually_call_initialize_rule():\n    class StateMachine(RuleBasedStateMachine):\n        initialize_called_counter = 0\n\n        @initialize()\n        def initialize(self):\n            self.initialize_called_counter += 1\n\n        @rule()\n        def fail_eventually(self):\n            self.initialize()\n            assert self.initialize_called_counter <= 2\n\n    StateMachine.TestCase.settings = NO_BLOB_SETTINGS\n    with pytest.raises(AssertionError) as err:\n        run_state_machine_as_test(StateMachine)\n\n    result = \"\\n\".join(err.value.__notes__)\n    assert (\n        result\n        == \"\"\"\nFalsifying example:\nstate = StateMachine()\nstate.initialize()\nstate.fail_eventually()\nstate.fail_eventually()\nstate.teardown()\n\"\"\".strip()\n    )\n\n\ndef test_steps_printed_despite_pytest_fail():\n    # Test for https://github.com/HypothesisWorks/hypothesis/issues/1372\n    @Settings(print_blob=False)\n    class RaisesProblem(RuleBasedStateMachine):\n        @rule()\n        def oops(self):\n            pytest.fail(\"note that this raises a BaseException\")\n\n    with pytest.raises(Failed) as err:\n        run_state_machine_as_test(RaisesProblem)\n    assert (\n        \"\\n\".join(err.value.__notes__).strip()\n        == \"\"\"\nFalsifying example:\nstate = RaisesProblem()\nstate.oops()\nstate.teardown()\"\"\".strip()\n    )\n\n\ndef test_steps_not_printed_with_pytest_skip(capsys):\n    class RaisesProblem(RuleBasedStateMachine):\n        @rule()\n        def skip_whole_test(self):\n            pytest.skip()\n\n    with pytest.raises(Skipped):\n        run_state_machine_as_test(RaisesProblem)\n    out, _ = capsys.readouterr()\n    assert \"state\" not in out\n\n\ndef test_rule_deprecation_targets_and_target():\n    k, v = Bundle(\"k\"), Bundle(\"v\")\n    with pytest.raises(InvalidArgument):\n        rule(targets=(k,), target=v)\n\n\ndef test_rule_deprecation_bundle_by_name():\n    Bundle(\"k\")\n    with pytest.raises(InvalidArgument):\n        rule(target=\"k\")\n\n\ndef test_rule_non_bundle_target():\n    with pytest.raises(InvalidArgument):\n        rule(target=integers())\n\n\ndef test_rule_non_bundle_target_oneof():\n    k, v = Bundle(\"k\"), Bundle(\"v\")\n    pattern = r\".+ `one_of(a, b)` or `a | b` .+\"\n    with pytest.raises(InvalidArgument, match=pattern):\n        rule(target=k | v)\n\n\ndef test_uses_seed(capsys):\n    @seed(0)\n    class TrivialMachine(RuleBasedStateMachine):\n        @rule()\n        def oops(self):\n            raise AssertionError\n\n    with pytest.raises(AssertionError):\n        run_state_machine_as_test(TrivialMachine)\n    out, _ = capsys.readouterr()\n    assert \"@seed\" not in out\n\n\ndef test_reproduce_failure_works():\n    @reproduce_failure(__version__, encode_failure([False, 0, True]))\n    class TrivialMachine(RuleBasedStateMachine):\n        @rule()\n        def oops(self):\n            raise AssertionError\n\n    with pytest.raises(AssertionError):\n        run_state_machine_as_test(TrivialMachine, settings=Settings(print_blob=True))\n\n\ndef test_reproduce_failure_fails_if_no_error():\n    @reproduce_failure(__version__, encode_failure([False, 0, True]))\n    class TrivialMachine(RuleBasedStateMachine):\n        @rule()\n        def ok(self):\n            pass\n\n    with pytest.raises(DidNotReproduce):\n        run_state_machine_as_test(TrivialMachine, settings=Settings(print_blob=True))\n\n\ndef test_cannot_have_zero_steps():\n    with pytest.raises(InvalidArgument):\n        Settings(stateful_step_count=0)\n\n\ndef test_arguments_do_not_use_names_of_return_values():\n    # See https://github.com/HypothesisWorks/hypothesis/issues/2341\n    class TrickyPrintingMachine(RuleBasedStateMachine):\n        data = Bundle(\"data\")\n\n        @initialize(target=data, value=integers())\n        def init_data(self, value):\n            return value\n\n        @rule(d=data)\n        def mostly_fails(self, d):\n            assert d == 42\n\n    with pytest.raises(AssertionError) as err:\n        run_state_machine_as_test(TrickyPrintingMachine)\n    assert \"data_0 = state.init_data(value=0)\" in err.value.__notes__\n    assert \"data_0 = state.init_data(value=data_0)\" not in err.value.__notes__\n\n\nclass TrickyInitMachine(RuleBasedStateMachine):\n    @initialize()\n    def init_a(self):\n        self.a = 0\n\n    @rule()\n    def inc(self):\n        self.a += 1\n\n    @invariant()\n    def check_a_positive(self):\n        # This will fail if run before the init_a method, but without\n        # @invariant(check_during_init=True) it will only run afterwards.\n        assert self.a >= 0\n\n\ndef test_invariants_are_checked_after_init_steps():\n    run_state_machine_as_test(TrickyInitMachine)\n\n\ndef test_invariants_can_be_checked_during_init_steps():\n    class UndefinedMachine(TrickyInitMachine):\n        @invariant(check_during_init=True)\n        def check_a_defined(self):\n            # This will fail because `a` is undefined before the init rule.\n            self.a\n\n    with pytest.raises(AttributeError):\n        run_state_machine_as_test(UndefinedMachine)\n\n\ndef test_check_during_init_must_be_boolean():\n    invariant(check_during_init=False)\n    invariant(check_during_init=True)\n    with pytest.raises(InvalidArgument):\n        invariant(check_during_init=\"not a bool\")\n\n\ndef test_deprecated_target_consumes_bundle():\n    # It would be nicer to raise this error at runtime, but the internals make\n    # this sadly impractical.  Most InvalidDefinition errors happen at, well,\n    # definition-time already anyway, so it's not *worse* than the status quo.\n    with validate_deprecation():\n        rule(target=consumes(Bundle(\"b\")))\n\n\n@Settings(stateful_step_count=5)\nclass MinStepsMachine(RuleBasedStateMachine):\n    @initialize()\n    def init_a(self):\n        self.a = 0\n\n    @rule()\n    def inc(self):\n        self.a += 1\n\n    @invariant()\n    def not_too_many_steps(self):\n        assert self.a < 10\n\n    def teardown(self):\n        assert self.a >= 2\n\n\n# Replay overruns after we trigger a crosshair.util.IgnoreAttempt exception for n=3\n@xfail_on_crosshair(Why.other)\ndef test_min_steps_argument():\n    # You must pass a non-negative integer...\n    for n_steps in (-1, \"nan\", 5.0):\n        with pytest.raises(InvalidArgument):\n            run_state_machine_as_test(MinStepsMachine, _min_steps=n_steps)\n\n    # and if you do, we'll take at least that many steps\n    run_state_machine_as_test(MinStepsMachine, _min_steps=3)\n\n    # (oh, and it's OK if you ask for more than we're actually going to take)\n    run_state_machine_as_test(MinStepsMachine, _min_steps=20)\n\n\nclass ErrorsOnClassAttributeSettings(RuleBasedStateMachine):\n    settings = Settings(derandomize=True)\n\n    @rule()\n    def step(self):\n        pass\n\n\ndef test_fails_on_settings_class_attribute():\n    with pytest.raises(\n        InvalidDefinition,\n        match=r\"Assigning .+ as a class attribute does nothing\",\n    ):\n        run_state_machine_as_test(ErrorsOnClassAttributeSettings)\n\n\ndef test_single_target_multiple():\n    class Machine(RuleBasedStateMachine):\n        a = Bundle(\"a\")\n\n        @initialize(target=a)\n        def initialize(self):\n            return multiple(\"ret1\", \"ret2\", \"ret3\")\n\n        @rule(param=a)\n        def fail_fast(self, param):\n            raise AssertionError\n\n    Machine.TestCase.settings = NO_BLOB_SETTINGS\n    with pytest.raises(AssertionError) as err:\n        run_state_machine_as_test(Machine)\n\n    result = \"\\n\".join(err.value.__notes__)\n    assert (\n        result\n        == \"\"\"\nFalsifying example:\nstate = Machine()\na_0, a_1, a_2 = state.initialize()\nstate.fail_fast(param=a_2)\nstate.teardown()\n\"\"\".strip()\n    )\n\n\n@pytest.mark.parametrize(\n    \"bundle_names,initial,repr_\",\n    [\n        (\"a\", \"ret1\", \"a_0 = state.init()\"),\n        (\"aba\", \"ret1\", \"a_0 = b_0 = a_1 = state.init()\"),\n        (\"a\", multiple(), \"state.init()\"),\n        (\"aba\", multiple(), \"state.init()\"),\n        (\"a\", multiple(\"ret1\"), \"(a_0,) = state.init()\"),\n        (\"aba\", multiple(\"ret1\"), \"(a_0,) = (b_0,) = (a_1,) = state.init()\"),\n        (\"a\", multiple(\"ret1\", \"ret2\"), \"a_0, a_1 = state.init()\"),\n        (\n            \"aba\",\n            multiple(\"ret1\", \"ret2\"),\n            \"\\n\".join(  # noqa: FLY002  # no, f-string is not more readable\n                [\n                    \"a_0, a_1 = state.init()\",\n                    \"b_0, b_1 = a_0, a_1\",\n                    \"a_2, a_3 = a_0, a_1\",\n                ]\n            ),\n        ),\n    ],\n)\ndef test_targets_repr(bundle_names, initial, repr_):\n    bundles = {name: Bundle(name) for name in bundle_names}\n\n    class Machine(RuleBasedStateMachine):\n        @initialize(targets=[bundles[name] for name in bundle_names])\n        def init(self):\n            return initial\n\n        @rule()\n        def fail_fast(self):\n            raise AssertionError\n\n    Machine.TestCase.settings = NO_BLOB_SETTINGS\n    with pytest.raises(AssertionError) as err:\n        run_state_machine_as_test(Machine)\n\n    result = \"\\n\".join(err.value.__notes__)\n    assert (\n        result\n        == f\"\"\"\nFalsifying example:\nstate = Machine()\n{repr_}\nstate.fail_fast()\nstate.teardown()\n\"\"\".strip()\n    )\n\n\ndef test_multiple_targets():\n    class Machine(RuleBasedStateMachine):\n        a = Bundle(\"a\")\n        b = Bundle(\"b\")\n\n        @initialize(targets=(a, b))\n        def initialize(self):\n            return multiple(\"ret1\", \"ret2\", \"ret3\")\n\n        @rule(\n            a1=consumes(a),\n            a2=consumes(a),\n            a3=consumes(a),\n            b1=consumes(b),\n            b2=consumes(b),\n            b3=consumes(b),\n        )\n        def fail_fast(self, a1, a2, a3, b1, b2, b3):\n            raise AssertionError\n\n    Machine.TestCase.settings = NO_BLOB_SETTINGS\n    with pytest.raises(AssertionError) as err:\n        run_state_machine_as_test(Machine)\n\n    result = \"\\n\".join(err.value.__notes__)\n    assert (\n        result\n        == \"\"\"\nFalsifying example:\nstate = Machine()\na_0, a_1, a_2 = state.initialize()\nb_0, b_1, b_2 = a_0, a_1, a_2\nstate.fail_fast(a1=a_2, a2=a_1, a3=a_0, b1=b_2, b2=b_1, b3=b_0)\nstate.teardown()\n\"\"\".strip()\n    )\n\n\ndef test_multiple_common_targets():\n    class Machine(RuleBasedStateMachine):\n        a = Bundle(\"a\")\n        b = Bundle(\"b\")\n\n        @initialize(targets=(a, b, a))\n        def initialize(self):\n            return multiple(\"ret1\", \"ret2\", \"ret3\")\n\n        @rule(\n            a1=consumes(a),\n            a2=consumes(a),\n            a3=consumes(a),\n            a4=consumes(a),\n            a5=consumes(a),\n            a6=consumes(a),\n            b1=consumes(b),\n            b2=consumes(b),\n            b3=consumes(b),\n        )\n        def fail_fast(self, a1, a2, a3, a4, a5, a6, b1, b2, b3):\n            raise AssertionError\n\n    Machine.TestCase.settings = NO_BLOB_SETTINGS\n    with pytest.raises(AssertionError) as err:\n        run_state_machine_as_test(Machine)\n\n    result = \"\\n\".join(err.value.__notes__)\n    assert (\n        result\n        == \"\"\"\nFalsifying example:\nstate = Machine()\na_0, a_1, a_2 = state.initialize()\nb_0, b_1, b_2 = a_0, a_1, a_2\na_3, a_4, a_5 = a_0, a_1, a_2\nstate.fail_fast(a1=a_5, a2=a_4, a3=a_3, a4=a_2, a5=a_1, a6=a_0, b1=b_2, b2=b_1, b3=b_0)\nstate.teardown()\n\"\"\".strip()\n    )\n\n\nclass LotsOfEntropyPerStepMachine(RuleBasedStateMachine):\n    # Regression tests for https://github.com/HypothesisWorks/hypothesis/issues/3618\n    @rule(data=binary(min_size=512, max_size=512))\n    def rule1(self, data):\n        assert data\n\n\n@pytest.mark.skipif(\n    Settings.get_current_profile_name() == \"crosshair\",\n    reason=\"takes hours; too much symbolic data\",\n)\ndef test_lots_of_entropy():\n    run_state_machine_as_test(LotsOfEntropyPerStepMachine)\n\n\ndef test_flatmap():\n    class Machine(RuleBasedStateMachine):\n        buns = Bundle(\"buns\")\n\n        @initialize(target=buns)\n        def create_bun(self):\n            return 0\n\n        @rule(target=buns, bun=buns.flatmap(lambda x: just(x + 1)))\n        def use_flatmap(self, bun):\n            assert isinstance(bun, int)\n            return bun\n\n        @rule(bun=buns)\n        def use_directly(self, bun):\n            assert isinstance(bun, int)\n\n    Machine.TestCase.settings = Settings(stateful_step_count=5, max_examples=10)\n    run_state_machine_as_test(Machine)\n\n\ndef test_use_bundle_within_other_strategies():\n    class Class:\n        def __init__(self, value):\n            self.value = value\n\n    class Machine(RuleBasedStateMachine):\n        my_bundle = Bundle(\"my_bundle\")\n\n        @initialize(target=my_bundle)\n        def set_initial(self, /) -> str:\n            return \"sample text\"\n\n        @rule(instance=st.builds(Class, my_bundle))\n        def check(self, instance):\n            assert isinstance(instance, Class)\n            assert isinstance(instance.value, str)\n\n    Machine.TestCase.settings = Settings(stateful_step_count=5, max_examples=10)\n    run_state_machine_as_test(Machine)\n\n\ndef test_precondition_cannot_be_used_without_rule():\n    class BadStateMachine(RuleBasedStateMachine):\n        @precondition(lambda: True)\n        def has_precondition_but_no_rule(self):\n            pass\n\n        @rule(n=st.integers())\n        def trivial(self, n):\n            pass\n\n    with pytest.raises(\n        InvalidDefinition,\n        match=(\n            \"BadStateMachine\\\\.has_precondition_but_no_rule has been decorated \"\n            \"with @precondition, but not @rule\"\n        ),\n    ):\n        BadStateMachine.TestCase().runTest()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_statistical_events.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\nimport time\nimport traceback\n\nimport pytest\n\nfrom hypothesis import (\n    HealthCheck,\n    assume,\n    event,\n    example,\n    given,\n    reject,\n    settings,\n    stateful,\n    strategies as st,\n    target,\n)\nfrom hypothesis.control import current_build_context\nfrom hypothesis.statistics import collector, describe_statistics\n\nfrom tests.common.utils import Why, xfail_on_crosshair\n\n\ndef call_for_statistics(test_function):\n    result = []\n    with collector.with_value(result.append):\n        try:\n            test_function()\n        except Exception:\n            traceback.print_exc()\n    assert len(result) == 1, result\n    return result[0]\n\n\ndef unique_events(stats):\n    return set(sum((t[\"events\"] for t in stats[\"generate-phase\"][\"test-cases\"]), []))\n\n\ndef test_notes_hard_to_satisfy():\n    @given(st.integers())\n    @settings(suppress_health_check=list(HealthCheck))\n    def test(i):\n        assume(i == 13)\n\n    stats = call_for_statistics(test)\n    assert \"satisfied assumptions\" in stats[\"stopped-because\"]\n\n\ndef test_can_callback_with_a_string():\n    @given(st.integers())\n    def test(i):\n        event(\"hi\")\n\n    stats = call_for_statistics(test)\n    assert any(\"hi\" in s for s in unique_events(stats))\n\n\ncounter = 0\nseen = []\n\n\nclass Foo:\n    def __eq__(self, other):\n        return True\n\n    def __ne__(self, other):\n        return False\n\n    def __hash__(self):\n        return 0\n\n    def __str__(self):\n        seen.append(self)\n        global counter\n        counter += 1\n        return f\"COUNTER {counter}\"\n\n\ndef test_formats_are_evaluated_only_once():\n    global counter\n    counter = 0\n\n    @given(st.integers())\n    def test(i):\n        if current_build_context().data.provider.avoid_realization:\n            pytest.skip(\"event() cache is disabled under avoid_realization = True\")\n        event(Foo())\n\n    stats = call_for_statistics(test)\n    assert \"COUNTER 1\" in unique_events(stats)\n    assert \"COUNTER 2\" not in unique_events(stats)\n\n\ndef test_does_not_report_on_examples():\n    @example(\"hi\")\n    @given(st.integers())\n    def test(i):\n        if isinstance(i, str):\n            event(\"boo\")\n\n    stats = call_for_statistics(test)\n    assert not unique_events(stats)\n\n\ndef test_exact_timing():\n    @settings(suppress_health_check=[HealthCheck.too_slow], deadline=None)\n    @given(st.integers())\n    def test(i):\n        time.sleep(0.5)\n\n    stats = describe_statistics(call_for_statistics(test))\n    assert \"~ 500ms\" in stats\n\n\ndef test_apparently_instantaneous_tests():\n    time.freeze()\n\n    @given(st.integers())\n    def test(i):\n        pass\n\n    stats = describe_statistics(call_for_statistics(test))\n    assert \"< 1ms\" in stats\n\n\n@xfail_on_crosshair(Why.other)  # crosshair re-executes for flakiness itself\ndef test_flaky_exit():\n    first = True\n\n    @settings(derandomize=True)\n    @given(st.integers())\n    def test(i):\n        nonlocal first\n        if i > 1001:\n            if first:\n                first = False\n                raise AssertionError\n\n    stats = call_for_statistics(test)\n    assert stats[\"stopped-because\"] == \"test was flaky\"\n\n\n@pytest.mark.parametrize(\"draw_delay\", [False, True])\n@pytest.mark.parametrize(\"test_delay\", [False, True])\ndef test_draw_timing(draw_delay, test_delay):\n    time.freeze()\n\n    @st.composite\n    def s(draw):\n        if draw_delay:\n            time.sleep(0.05)\n        draw(st.integers())\n\n    @given(s())\n    def test(_):\n        if test_delay:\n            time.sleep(0.05)\n\n    stats = describe_statistics(call_for_statistics(test))\n    if not draw_delay:\n        assert \"< 1ms\" in stats\n    else:\n        match = re.search(r\"of which ~ (?P<gentime>\\d+)\", stats)\n        assert 49 <= int(match.group(\"gentime\")) <= 51\n\n\ndef test_has_lambdas_in_output():\n    @settings(max_examples=100, database=None)\n    @given(st.integers().filter(lambda x: x % 2 == 0))\n    def test(i):\n        pass\n\n    stats = call_for_statistics(test)\n    assert any(\"lambda x: x % 2 == 0\" in e for e in unique_events(stats))\n\n\ndef test_stops_after_x_shrinks(monkeypatch):\n    # the max_shrinks argument is deprecated, but we still stop after some\n    # number - which we can reduce to zero to check that this works.\n    from hypothesis.internal.conjecture import engine\n\n    monkeypatch.setattr(engine, \"MAX_SHRINKS\", 0)\n\n    @given(st.integers(min_value=0))\n    def test(n):\n        assert n < 10\n\n    stats = call_for_statistics(test)\n    assert \"shrunk example\" in stats[\"stopped-because\"]\n\n\ndef test_stateful_states_are_deduped():\n    class DemoStateMachine(stateful.RuleBasedStateMachine):\n        Stuff = stateful.Bundle(\"stuff\")\n\n        @stateful.rule(target=Stuff, name=st.text())\n        def create_stuff(self, name):\n            return name\n\n        @stateful.rule(item=Stuff)\n        def do(self, item):\n            return\n\n    stats = call_for_statistics(DemoStateMachine.TestCase().runTest)\n    stats = unique_events(stats)\n    stats = [s for s in stats if not s.startswith(\"invalid because: (internal)\")]\n    assert len(stats) <= 2\n\n\ndef test_stateful_with_one_of_bundles_states_are_deduped():\n    class DemoStateMachine(stateful.RuleBasedStateMachine):\n        Things = stateful.Bundle(\"things\")\n        Stuff = stateful.Bundle(\"stuff\")\n        StuffAndThings = Things | Stuff\n\n        @stateful.rule(target=Things, name=st.text())\n        def create_thing(self, name):\n            return name\n\n        @stateful.rule(target=Stuff, name=st.text())\n        def create_stuff(self, name):\n            return name\n\n        @stateful.rule(item=StuffAndThings)\n        def do(self, item):\n            return\n\n    stats = call_for_statistics(DemoStateMachine.TestCase().runTest)\n    stats = unique_events(stats)\n    stats = [s for s in stats if not s.startswith(\"invalid because: (internal)\")]\n    assert len(stats) <= 4\n\n\ndef test_statistics_for_threshold_problem():\n    @settings(max_examples=100, database=None)\n    @given(st.floats(min_value=0, allow_infinity=False))\n    def threshold(error):\n        target(error, label=\"error\")\n        assert error <= 10\n        target(0.0, label=\"never in failing example\")\n\n    stats = call_for_statistics(threshold)\n    assert \"  - Highest target scores:\" in describe_statistics(stats)\n    assert \"never in failing example\" in describe_statistics(stats)\n    # Check that we report far-from-threshold failing examples\n    assert stats[\"targets\"][\"error\"] > 10\n\n\ndef test_statistics_with_events_and_target():\n    @given(st.integers(0, 10_000))\n    def test(value):\n        event(value)\n        target(float(value), label=\"a target\")\n\n    stats = describe_statistics(call_for_statistics(test))\n    assert \"- Events:\" in stats\n    assert \"- Highest target score: \" in stats\n\n\n@given(st.booleans())\ndef test_event_with_non_weakrefable_keys(b):\n    event((b,))\n\n\ndef test_assume_adds_event_with_function_origin():\n    @given(st.integers())\n    def very_distinguishable_name(n):\n        assume(n > 100)\n\n    stats = call_for_statistics(very_distinguishable_name)\n\n    for tc in stats[\"generate-phase\"][\"test-cases\"]:\n        for e in tc[\"events\"]:\n            assert \"failed to satisfy assume() in very_distinguishable_name\" in e\n\n\ndef test_reject_adds_event_with_function_origin():\n    @given(st.integers())\n    def very_distinguishable_name(n):\n        if n > 100:\n            reject()\n\n    stats = call_for_statistics(very_distinguishable_name)\n\n    for tc in stats[\"generate-phase\"][\"test-cases\"]:\n        for e in tc[\"events\"]:\n            assert \"reject() in very_distinguishable_name\" in e\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_subnormal_floats.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom sys import float_info\n\nimport pytest\n\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.floats import next_down, next_up\nfrom hypothesis.strategies import floats\nfrom hypothesis.strategies._internal.numbers import next_down_normal, next_up_normal\n\nfrom tests.common.debug import assert_no_examples, check_can_generate_examples, find_any\nfrom tests.common.utils import PYTHON_FTZ\n\npytestmark = [pytest.mark.skipif(PYTHON_FTZ, reason=\"broken by unsafe compiler flags\")]\n\n\ndef kw(marks=(), **kwargs):\n    id_ = \", \".join(f\"{k}={v!r}\" for k, v in kwargs.items())\n    return pytest.param(kwargs, id=id_, marks=marks)\n\n\n@pytest.mark.parametrize(\n    \"kwargs\",\n    [\n        kw(min_value=1),\n        kw(max_value=-1),\n        kw(min_value=float_info.min),\n        kw(min_value=next_down(float_info.min), exclude_min=True),\n        kw(max_value=-float_info.min),\n        kw(min_value=next_up(-float_info.min), exclude_max=True),\n    ],\n)\ndef test_subnormal_validation(kwargs):\n    strat = floats(**kwargs, allow_subnormal=True)\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(strat)\n\n\n@pytest.mark.parametrize(\n    \"kwargs\",\n    [\n        # min value\n        kw(allow_subnormal=False, min_value=1),\n        kw(allow_subnormal=False, min_value=float_info.min),\n        kw(allow_subnormal=True, min_value=-1),\n        kw(allow_subnormal=True, min_value=next_down(float_info.min)),\n        # max value\n        kw(allow_subnormal=False, max_value=-1),\n        kw(allow_subnormal=False, max_value=-float_info.min),\n        kw(allow_subnormal=True, max_value=1),\n        kw(allow_subnormal=True, max_value=next_up(-float_info.min)),\n        # min/max values\n        kw(allow_subnormal=True, min_value=-1, max_value=1),\n        kw(\n            allow_subnormal=True,\n            min_value=next_down(float_info.min),\n            max_value=float_info.min,\n        ),\n        kw(\n            allow_subnormal=True,\n            min_value=-float_info.min,\n            max_value=next_up(-float_info.min),\n        ),\n        kw(allow_subnormal=False, min_value=-1, max_value=-float_info.min),\n        kw(allow_subnormal=False, min_value=float_info.min, max_value=1),\n    ],\n)\ndef test_allow_subnormal_defaults_correctly(kwargs):\n    # copy to support our threading CI tests\n    kwargs = kwargs.copy()\n    allow_subnormal = kwargs.pop(\"allow_subnormal\")\n    strat = floats(**kwargs).filter(lambda x: x != 0)\n    if allow_subnormal:\n        find_any(strat, lambda x: -float_info.min < x < float_info.min)\n    else:\n        assert_no_examples(strat, lambda x: -float_info.min < x < float_info.min)\n\n\n@pytest.mark.parametrize(\n    \"func, val, expected\",\n    [\n        (next_up_normal, -float_info.min, -0.0),\n        (next_up_normal, +0.0, float_info.min),\n        (next_down_normal, float_info.min, +0.0),\n        (next_down_normal, -0.0, -float_info.min),\n    ],\n)\ndef test_next_float_normal(func, val, expected):\n    assert func(value=val, width=64, allow_subnormal=False) == expected\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_targeting.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom operator import itemgetter\n\nimport pytest\n\nfrom hypothesis import example, given, strategies as st, target\nfrom hypothesis.control import current_build_context\nfrom hypothesis.errors import InvalidArgument\n\n\n@example(0.0, \"this covers the branch where context.data is None\")\n@given(\n    observation=st.integers() | st.floats(allow_nan=False, allow_infinity=False),\n    label=st.text(),\n)\ndef test_allowed_inputs_to_target(observation, label):\n    target(observation, label=label)\n\n\n@given(\n    observation=st.integers(min_value=1)\n    | st.floats(min_value=1, allow_nan=False, allow_infinity=False),\n    label=st.sampled_from([\"a\", \"few\", \"labels\"]),\n)\ndef test_allowed_inputs_to_target_fewer_labels(observation, label):\n    target(observation, label=label)\n\n\n@given(st.floats(min_value=1, max_value=10))\ndef test_target_without_label(observation):\n    target(observation)\n\n\n@given(\n    st.lists(\n        st.tuples(st.floats(allow_nan=False, allow_infinity=False), st.text()),\n        min_size=1,\n        unique_by=itemgetter(1),\n    )\n)\ndef test_multiple_target_calls(args):\n    for observation, label in args:\n        target(observation, label=label)\n\n\n@given(\n    st.lists(st.floats(allow_nan=False, allow_infinity=False), min_size=11, max_size=20)\n)\ndef test_respects_max_pool_size(observations):\n    \"\"\"Using many examples of several labels like this stresses the\n    pool-size logic and internal assertions in TargetSelector.\n    \"\"\"\n    for i, obs in enumerate(observations):\n        target(obs, label=str(i))\n\n\ndef everything_except(type_):\n    # Note: we would usually stick to faster traditional or parametrized\n    # tests to check that invalid inputs are rejected, but for `target()`\n    # we need to use `@given` (to validate arguments instead of context)\n    # so we might as well apply this neat recipe.\n    return (\n        st.from_type(type)\n        .flatmap(st.from_type)\n        .filter(lambda x: not isinstance(x, type_))\n    )\n\n\n@example(float(\"nan\"), \"\")\n@example(float(\"inf\"), \"\")\n@example(float(\"-inf\"), \"\")\n@example(\"1\", \"Non-float observations are invalid\")\n@example(0.0, [\"a list of strings is not a valid label\"])\n@given(observation=everything_except((float, int)), label=everything_except(str))\ndef test_disallowed_inputs_to_target(observation, label):\n    with pytest.raises(InvalidArgument):\n        target(observation, label=label)\n\n\ndef test_cannot_target_outside_test():\n    with pytest.raises(InvalidArgument):\n        target(1.0, label=\"example label\")\n\n\n@given(st.none())\ndef test_cannot_target_same_label_twice(_):\n    if current_build_context().data.provider.avoid_realization:\n        pytest.skip(\"target() is a noop to avoid realizing arguments\")\n    target(0.0, label=\"label\")\n    with pytest.raises(InvalidArgument):\n        target(1.0, label=\"label\")\n\n\n@given(st.none())\ndef test_cannot_target_default_label_twice(_):\n    target(0.0)\n    with pytest.raises(InvalidArgument):\n        target(1.0)\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_testdecorators.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport functools\nimport threading\nfrom collections import namedtuple\n\nimport pytest\n\nfrom hypothesis import (\n    HealthCheck,\n    Verbosity,\n    assume,\n    given,\n    note,\n    reporting,\n    settings,\n    strategies as st,\n)\nfrom hypothesis.errors import Unsatisfiable\nfrom hypothesis.internal.conjecture.engine import INVALID_THRESHOLD_BASE\nfrom hypothesis.strategies import (\n    binary,\n    booleans,\n    builds,\n    data,\n    floats,\n    frozensets,\n    integers,\n    just,\n    lists,\n    one_of,\n    sampled_from,\n    sets,\n    text,\n)\n\nfrom tests.common.utils import (\n    Why,\n    assert_falsifying_output,\n    capture_out,\n    fails,\n    fails_with,\n    no_shrink,\n    skipif_emscripten,\n    xfail_on_crosshair,\n)\nfrom tests.conjecture.common import buffer_size_limit\n\n\n@given(integers(), integers())\ndef test_int_addition_is_commutative(x, y):\n    assert x + y == y + x\n\n\n@fails\n@given(text(min_size=1), text(min_size=1))\ndef test_str_addition_is_commutative(x, y):\n    assert x + y == y + x\n\n\n@fails\n@given(binary(min_size=1), binary(min_size=1))\ndef test_bytes_addition_is_commutative(x, y):\n    # We enforce min_size=1 here to avoid a rare flakiness, where the\n    # test passes if x and/or y are b\"\" for every generated example.\n    # (the internal implementation makes this less rare for bytes)\n    assert x + y == y + x\n\n\n@given(integers(), integers(), integers())\ndef test_int_addition_is_associative(x, y, z):\n    assert x + (y + z) == (x + y) + z\n\n\n@fails\n@given(floats(), floats(), floats())\n@settings(max_examples=2000)\ndef test_float_addition_is_associative(x, y, z):\n    assert x + (y + z) == (x + y) + z\n\n\n@given(lists(integers()))\ndef test_reversing_preserves_integer_addition(xs):\n    assert sum(xs) == sum(reversed(xs))\n\n\ndef test_still_minimizes_on_non_assertion_failures():\n    @settings(max_examples=50)\n    @given(integers())\n    def is_not_too_large(x):\n        if x >= 10:\n            raise ValueError(f\"No, {x} is just too large. Sorry\")\n\n    with pytest.raises(ValueError, match=\" 10 \"):\n        is_not_too_large()\n\n\n@given(integers())\ndef test_integer_division_shrinks_positive_integers(n):\n    assume(n > 0)\n    assert n / 2 < n\n\n\nclass TestCases:\n    @given(integers())\n    def test_abs_non_negative(self, x):\n        assert abs(x) >= 0\n        assert isinstance(self, TestCases)\n\n    @given(x=integers())\n    def test_abs_non_negative_varargs(self, x, *args):\n        assert abs(x) >= 0\n        assert isinstance(self, TestCases)\n\n    @given(x=integers())\n    def test_abs_non_negative_varargs_kwargs(self, *args, **kw):\n        assert abs(kw[\"x\"]) >= 0\n        assert isinstance(self, TestCases)\n\n    @given(x=integers())\n    def test_abs_non_negative_varargs_kwargs_only(*args, **kw):\n        assert abs(kw[\"x\"]) >= 0\n        assert isinstance(args[0], TestCases)\n\n    @fails\n    @given(integers())\n    def test_int_is_always_negative(self, x):\n        assert x < 0\n\n    @fails\n    @given(floats(), floats())\n    def test_float_addition_cancels(self, x, y):\n        assert x + (y - x) == y\n\n\n@fails\n@given(x=integers(min_value=0, max_value=3), name=text())\ndef test_can_be_given_keyword_args(x, name):\n    assume(x > 0)\n    assert len(name) < x\n\n\n@fails\n@given(one_of(floats(), booleans()), one_of(floats(), booleans()))\ndef test_one_of_produces_different_values(x, y):\n    assert type(x) == type(y)\n\n\n@given(just(42))\ndef test_is_the_answer(x):\n    assert x == 42\n\n\n@given(integers(1, 10))\ndef test_integers_are_in_range(x):\n    assert 1 <= x <= 10\n\n\n@given(integers(min_value=100))\ndef test_integers_from_are_from(x):\n    assert x >= 100\n\n\ndef test_does_not_catch_interrupt_during_falsify():\n    called = False\n\n    @given(integers())\n    def flaky_base_exception(x):\n        nonlocal called\n        if not called:\n            called = True\n            raise KeyboardInterrupt\n\n    with pytest.raises(KeyboardInterrupt):\n        flaky_base_exception()\n\n\n@given(lists(integers(), unique=True), integers())\ndef test_removing_an_element_from_a_unique_list(xs, y):\n    assume(len(set(xs)) == len(xs))\n\n    try:\n        xs.remove(y)\n    except ValueError:\n        pass\n\n    assert y not in xs\n\n\n@fails\n@given(lists(integers(), min_size=2), data())\ndef test_removing_an_element_from_a_non_unique_list(xs, data):\n    y = data.draw(sampled_from(xs))\n    xs.remove(y)\n    assert y not in xs\n\n\n@given(sets(sampled_from(list(range(10)))))\ndef test_can_test_sets_sampled_from(xs):\n    assert all(isinstance(x, int) for x in xs)\n    assert all(0 <= x < 10 for x in xs)\n\n\nmix = one_of(sampled_from([1, 2, 3]), text())\n\n\n@fails\n@given(mix, mix)\ndef test_can_mix_sampling_with_generating(x, y):\n    assert type(x) == type(y)\n\n\n@fails\n@given(frozensets(integers()))\ndef test_can_find_large_sum_frozenset(xs):\n    assert sum(xs) < 100\n\n\ndef test_prints_on_failure_by_default():\n    @given(integers(), integers())\n    @settings(max_examples=1000)\n    def test_ints_are_sorted(balthazar, evans):\n        assume(evans >= 0)\n        assert balthazar <= evans\n\n    assert_falsifying_output(test_ints_are_sorted, balthazar=1, evans=0)\n\n\ndef test_does_not_print_on_success():\n    @settings(verbosity=Verbosity.normal)\n    @given(integers())\n    def test_is_an_int(x):\n        return\n\n    with capture_out() as out:\n        test_is_an_int()\n    out = out.getvalue()\n    lines = [l.strip() for l in out.split(\"\\n\")]\n    assert all(not l for l in lines), lines\n\n\n@given(sampled_from([1]))\ndef test_can_sample_from_single_element(x):\n    assert x == 1\n\n\n@fails\n@given(lists(integers()))\ndef test_list_is_sorted(xs):\n    assert sorted(xs) == xs\n\n\n@fails\n@given(floats(1.0, 2.0))\ndef test_is_an_endpoint(x):\n    assert x in {1.0, 2.0}\n\n\ndef test_breaks_bounds():\n    @fails\n    @given(x=integers())\n    @settings(derandomize=True, max_examples=10_000)\n    def test_is_bounded(t, x):\n        assert x < t\n\n    for t in [1, 10, 100, 1000]:\n        test_is_bounded(t)\n\n\n@given(x=booleans())\ndef test_can_test_kwargs_only_methods(**kwargs):\n    assert isinstance(kwargs[\"x\"], bool)\n\n\n@fails_with(UnicodeEncodeError)\n@given(text())\n@settings(max_examples=100)\ndef test_is_ascii(x):\n    x.encode(\"ascii\")\n\n\n@fails\n@given(text())\ndef test_is_not_ascii(x):\n    try:\n        x.encode(\"ascii\")\n        raise AssertionError\n    except UnicodeEncodeError:\n        pass\n\n\n@fails\n@given(text(min_size=2))\n@settings(max_examples=100, derandomize=True)\ndef test_can_find_string_with_duplicates(s):\n    assert len(set(s)) == len(s)\n\n\n@fails\n@given(text(min_size=1))\n@settings(derandomize=True)\ndef test_has_ascii(x):\n    if not x:\n        return\n    ascii_characters = (\n        \"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \\t\\n\"\n    )\n    assert any(c in ascii_characters for c in x)\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)\ndef test_can_derandomize():\n    values = []\n\n    @fails\n    @given(integers())\n    @settings(derandomize=True, database=None)\n    def test_blah(x):\n        values.append(x)\n        assert x > 0\n\n    test_blah()\n    assert values\n    v1 = values\n    values = []\n    test_blah()\n    assert v1 == values\n\n\ndef test_can_run_without_database():\n    @given(integers())\n    @settings(database=None)\n    def test_blah(x):\n        raise AssertionError\n\n    with pytest.raises(AssertionError):\n        test_blah()\n\n\n@skipif_emscripten\ndef test_can_run_with_database_in_thread():\n    results = []\n\n    @given(integers())\n    def test_blah(x):\n        raise ValueError\n\n    def run_test():\n        try:\n            test_blah()\n        except ValueError:\n            results.append(\"success\")\n\n    # Run once in the main thread and once in another thread. Execution is\n    # strictly serial, so no need for locking.\n    run_test()\n    assert results == [\"success\"]\n    thread = threading.Thread(target=run_test)\n    thread.start()\n    thread.join()\n    assert results == [\"success\", \"success\"]\n\n\n@given(integers())\ndef test_can_call_an_argument_f(f):\n    # See issue https://github.com/HypothesisWorks/hypothesis-python/issues/38\n    # for details\n    pass\n\n\nLitter = namedtuple(\"Litter\", (\"kitten1\", \"kitten2\"))\n\n\n@given(builds(Litter, integers(), integers()))\ndef test_named_tuples_are_of_right_type(litter):\n    assert isinstance(litter, Litter)\n\n\n@fails_with(AttributeError)\n@given(integers().map(lambda x: x.nope))\n@settings(suppress_health_check=list(HealthCheck))\ndef test_fails_in_reify(x):\n    pass\n\n\n@given(text(\"a\"))\ndef test_a_text(x):\n    assert set(x).issubset(set(\"a\"))\n\n\n@given(text(\"\"))\ndef test_empty_text(x):\n    assert not x\n\n\n@given(text(\"abcdefg\"))\ndef test_mixed_text(x):\n    assert set(x).issubset(set(\"abcdefg\"))\n\n\n@xfail_on_crosshair(Why.other, strict=False)  # runs ~five failing examples\ndef test_when_set_to_no_simplifies_runs_failing_example_twice():\n    failing = []\n\n    @given(integers())\n    @settings(\n        phases=no_shrink,\n        max_examples=100,\n        verbosity=Verbosity.normal,\n        report_multiple_bugs=False,\n    )\n    def foo(x):\n        if x > 11:\n            note(\"Lo\")\n            failing.append(x)\n            raise AssertionError\n\n    with pytest.raises(AssertionError) as err:\n        foo()\n    assert len(failing) == 2\n    assert len(set(failing)) == 1\n    assert \"Falsifying example\" in \"\\n\".join(err.value.__notes__)\n    assert \"Lo\" in err.value.__notes__\n\n\n@given(integers().filter(lambda x: x % 4 == 0))\ndef test_filtered_values_satisfy_condition(i):\n    assert i % 4 == 0\n\n\ndef nameless_const(x):\n    def f(u, v):\n        return u\n\n    return functools.partial(f, x)\n\n\n@given(sets(booleans()).map(nameless_const(2)))\ndef test_can_map_nameless(x):\n    assert x == 2\n\n\n@given(integers(0, 10).flatmap(nameless_const(just(3))))\ndef test_can_flatmap_nameless(x):\n    assert x == 3\n\n\ndef test_can_be_used_with_none_module():\n    def test_is_cool(i):\n        pass\n\n    test_is_cool.__module__ = None\n    test_is_cool = given(integers())(test_is_cool)\n    test_is_cool()\n\n\ndef test_does_not_print_notes_if_all_succeed():\n    @given(integers())\n    @settings(verbosity=Verbosity.normal)\n    def test(i):\n        note(\"Hi there\")\n\n    with capture_out() as out, reporting.with_reporter(reporting.default):\n        test()\n    assert not out.getvalue()\n\n\ndef test_prints_notes_once_on_failure():\n    @given(lists(integers()))\n    @settings(database=None, verbosity=Verbosity.normal)\n    def test(xs):\n        note(\"Hi there\")\n        if sum(xs) <= 100:\n            raise ValueError\n\n    with pytest.raises(ValueError) as err:\n        test()\n    assert err.value.__notes__.count(\"Hi there\") == 1\n\n\n@given(lists(integers(), max_size=0))\ndef test_empty_lists(xs):\n    assert xs == []\n\n\n@xfail_on_crosshair(Why.other, strict=False)\ndef test_given_usable_inline_on_lambdas():\n    xs = []\n    given(booleans())(lambda x: xs.append(x))()\n    assert len(xs) == 2\n    assert set(xs) == {False, True}\n\n\ndef test_notes_high_filter_rates_in_unsatisfiable_error():\n    @given(st.integers())\n    @settings(suppress_health_check=[HealthCheck.filter_too_much])\n    def f(v):\n        assume(False)\n\n    with pytest.raises(\n        Unsatisfiable,\n        match=(\n            rf\"Unable to satisfy assumptions of f\\. {INVALID_THRESHOLD_BASE+1} of \"\n            rf\"{INVALID_THRESHOLD_BASE+1} examples failed a \\.filter\\(\\) or assume\\(\\)\"\n        ),\n    ):\n        f()\n\n\n# crosshair generates one valid input before verifying the test function,\n# so the Unsatisfiable check never occurs.\n# (not strict due to slowness causing crosshair to bail out on the first input,\n# maybe?)\n@xfail_on_crosshair(Why.other, strict=False)\ndef test_notes_high_overrun_rates_in_unsatisfiable_error():\n    @given(st.binary(min_size=100))\n    @settings(\n        suppress_health_check=[\n            HealthCheck.data_too_large,\n            HealthCheck.too_slow,\n            HealthCheck.large_base_example,\n        ]\n    )\n    def f(v):\n        pass\n\n    match = (\n        rf\"{INVALID_THRESHOLD_BASE+1} of {INVALID_THRESHOLD_BASE+1} examples were too large to\"\n        rf\" finish generating; try reducing the typical size of your inputs\\?\"\n    )\n    with (\n        pytest.raises(Unsatisfiable, match=match),\n        buffer_size_limit(10),\n    ):\n        f()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_threading.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom threading import Barrier, Thread\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis.utils.threading import ThreadLocal\n\nfrom tests.common.utils import skipif_emscripten\n\n\ndef test_threadlocal_setattr_and_getattr():\n    threadlocal = ThreadLocal(a=lambda: 1, b=lambda: 2)\n    assert threadlocal.a == 1\n    assert threadlocal.b == 2\n    # check that we didn't add attributes to the ThreadLocal instance itself\n    # instead of its threading.local() variable\n    assert set(threadlocal.__dict__) == {\n        \"_ThreadLocal__initialized\",\n        \"_ThreadLocal__kwargs\",\n        \"_ThreadLocal__threadlocal\",\n    }\n\n    threadlocal.a = 3\n    assert threadlocal.a == 3\n    assert threadlocal.b == 2\n    assert set(threadlocal.__dict__) == {\n        \"_ThreadLocal__initialized\",\n        \"_ThreadLocal__kwargs\",\n        \"_ThreadLocal__threadlocal\",\n    }\n\n\ndef test_nonexistent_getattr_raises():\n    threadlocal = ThreadLocal(a=lambda: 1)\n    with pytest.raises(AttributeError):\n        threadlocal.c\n\n\ndef test_nonexistent_setattr_raises():\n    threadlocal = ThreadLocal(a=lambda: 1)\n    with pytest.raises(AttributeError):\n        threadlocal.c = 2\n\n\ndef test_raises_if_not_passed_callable():\n    with pytest.raises(TypeError):\n        ThreadLocal(a=1)\n\n\n@skipif_emscripten\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"crosshair is not thread-safe\",\n)\ndef test_run_given_concurrently():\n    # this is just a basic covering test. The more complicated and complete threading\n    # tests are in nocover/test_threading.py.\n\n    n_threads = 2\n    barrier = Barrier(n_threads)\n\n    @given(st.integers())\n    def test(n):\n        barrier.wait()\n\n    threads = [Thread(target=test) for _ in range(n_threads)]\n\n    for thread in threads:\n        thread.start()\n\n    for thread in threads:\n        thread.join(timeout=10)\n\n\n# rely on our pytest-run-parallel job to test this, since this only happens because\n# pytest instantiates a new class instance for each parametrization.\nclass TestNoDifferingExecutorsHealthCheck:\n    @given(st.integers())\n    @pytest.mark.parametrize(\"x\", range(2))\n    def test_a(self, x, i):\n        pass\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_traceback_elision.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport traceback\n\nimport pytest\n\nfrom hypothesis import Verbosity, given, settings, strategies as st\n\n\n@pytest.mark.parametrize(\"verbosity\", [Verbosity.normal, Verbosity.debug])\n@pytest.mark.parametrize(\"env_value\", [\"\", \"1\"])\ndef test_tracebacks_omit_hypothesis_internals(monkeypatch, env_value, verbosity):\n    monkeypatch.setenv(\"HYPOTHESIS_NO_TRACEBACK_TRIM\", env_value)\n\n    @settings(verbosity=verbosity)\n    @given(st.just(False))\n    def simplest_failure(x):\n        raise ValueError\n\n    try:\n        simplest_failure()\n    except ValueError as e:\n        tb = traceback.extract_tb(e.__traceback__)\n        # Unless in debug mode, Hypothesis adds 1 frame - the least possible!\n        # (4 frames: this one, simplest_failure, internal frame, assert False)\n        if verbosity < Verbosity.debug and not env_value:\n            assert len(tb) == 4\n        else:\n            assert len(tb) >= 5\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_type_lookup.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport abc\nimport enum\nimport typing\nfrom collections.abc import Callable, Sequence\nfrom inspect import Parameter as P, Signature\nfrom typing import Generic, List as _List, TypeVar, Union\n\nimport pytest\n\nfrom hypothesis import given, infer, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument, ResolutionFailed\nfrom hypothesis.internal.compat import get_type_hints\nfrom hypothesis.internal.reflection import get_pretty_function_description\nfrom hypothesis.strategies._internal import types\nfrom hypothesis.strategies._internal.lazy import LazyStrategy\nfrom hypothesis.strategies._internal.types import _global_type_lookup\nfrom hypothesis.strategies._internal.utils import _all_strategies\n\nfrom tests.common.debug import (\n    assert_all_examples,\n    assert_simple_property,\n    check_can_generate_examples,\n    find_any,\n)\nfrom tests.common.utils import (\n    Why,\n    fails_with,\n    skipif_threading,\n    temp_registered,\n    xfail_on_crosshair,\n)\n\n# we'll continue testing the typing variants until their removal from the stdlib\n# ruff: noqa: UP006, UP035, UP007\n\ntypes_with_core_strat = {\n    type_\n    for type_, strat in _global_type_lookup.items()\n    if isinstance(strat, LazyStrategy) and strat.function in vars(st).values()\n}\n\n\ndef test_generic_sequence_of_integers_may_be_lists_or_bytes():\n    strat = st.from_type(Sequence[int])\n    find_any(strat, lambda x: isinstance(x, bytes))\n    find_any(strat, lambda x: isinstance(x, list))\n\n\n@pytest.mark.parametrize(\"typ\", sorted(types_with_core_strat, key=str))\ndef test_resolve_core_strategies(typ):\n    @given(st.from_type(typ))\n    def inner(ex):\n        assert isinstance(ex, typ)\n\n    inner()\n\n\ndef test_lookup_knows_about_all_core_strategies():\n    # Build a set of all types output by core strategies\n    blocklist = {\n        \"builds\",\n        \"data\",\n        \"deferred\",\n        \"from_regex\",\n        \"from_type\",\n        \"ip_addresses\",\n        \"iterables\",\n        \"just\",\n        \"nothing\",\n        \"one_of\",\n        \"permutations\",\n        \"random_module\",\n        \"randoms\",\n        \"recursive\",\n        \"runner\",\n        \"sampled_from\",\n        \"shared\",\n        \"timezone_keys\",\n        \"timezones\",\n    }\n    assert set(_all_strategies).issuperset(blocklist), blocklist.difference(\n        _all_strategies\n    )\n    found = set()\n    for thing in (\n        getattr(st, name)\n        for name in sorted(_all_strategies)\n        if name in dir(st) and name not in blocklist\n    ):\n        for n in range(3):\n            try:\n                ex = find_any(thing(*([st.nothing()] * n)))\n                found.add(type(ex))\n                break\n            except Exception:\n                continue\n\n    cannot_lookup = found - set(types._global_type_lookup)\n    assert not cannot_lookup\n\n\ndef test_lookup_keys_are_types():\n    with pytest.raises(InvalidArgument):\n        st.register_type_strategy(\"int\", st.integers())\n    assert \"int\" not in types._global_type_lookup\n\n\n@pytest.mark.parametrize(\n    \"typ, not_a_strategy\",\n    [\n        (int, 42),  # Values must be strategies\n        # Can't register NotImplemented directly, even though strategy functions\n        # can return it.\n        (int, NotImplemented),\n    ],\n)\ndef test_lookup_values_are_strategies(typ, not_a_strategy):\n    with pytest.raises(InvalidArgument):\n        st.register_type_strategy(typ, not_a_strategy)\n    assert not_a_strategy not in types._global_type_lookup.values()\n\n\n@pytest.mark.parametrize(\"typ\", sorted(types_with_core_strat, key=str))\ndef test_lookup_overrides_defaults(typ):\n    sentinel = object()\n    with temp_registered(typ, st.just(sentinel)):\n        assert_simple_property(st.from_type(typ), lambda v: v is sentinel)\n    assert_simple_property(st.from_type(typ), lambda v: v is not sentinel)\n\n\nclass ParentUnknownType:\n    pass\n\n\nclass UnknownType(ParentUnknownType):\n    def __init__(self, arg):\n        pass\n\n\ndef test_custom_type_resolution_fails_without_registering():\n    fails = st.from_type(UnknownType)\n    with pytest.raises(ResolutionFailed):\n        check_can_generate_examples(fails)\n\n\ndef test_custom_type_resolution():\n    sentinel = object()\n    with temp_registered(UnknownType, st.just(sentinel)):\n        assert_simple_property(st.from_type(UnknownType), lambda v: v is sentinel)\n        # Also covered by registration of child class\n        assert_simple_property(st.from_type(ParentUnknownType), lambda v: v is sentinel)\n\n\ndef test_custom_type_resolution_with_function():\n    sentinel = object()\n    with temp_registered(UnknownType, lambda _: st.just(sentinel)):\n        assert_simple_property(st.from_type(UnknownType), lambda v: v is sentinel)\n        assert_simple_property(st.from_type(ParentUnknownType), lambda v: v is sentinel)\n\n\ndef test_custom_type_resolution_with_function_non_strategy():\n    with temp_registered(UnknownType, lambda _: None):\n        with pytest.raises(ResolutionFailed):\n            check_can_generate_examples(st.from_type(UnknownType))\n        with pytest.raises(ResolutionFailed):\n            check_can_generate_examples(st.from_type(ParentUnknownType))\n\n\n@pytest.mark.parametrize(\"strategy_returned\", [True, False])\ndef test_conditional_type_resolution_with_function(strategy_returned):\n    sentinel = object()\n\n    def resolve_strategy(thing):\n        assert thing == UnknownType\n        if strategy_returned:\n            return st.just(sentinel)\n        return NotImplemented\n\n    with temp_registered(UnknownType, resolve_strategy):\n        if strategy_returned:\n            assert_simple_property(st.from_type(UnknownType), lambda v: v is sentinel)\n        else:\n            with pytest.raises(ResolutionFailed):\n                check_can_generate_examples(st.from_type(UnknownType))\n\n\ndef test_errors_if_generic_resolves_empty():\n    with temp_registered(UnknownType, lambda _: st.nothing()):\n        fails_1 = st.from_type(UnknownType)\n        with pytest.raises(ResolutionFailed):\n            check_can_generate_examples(fails_1)\n        fails_2 = st.from_type(ParentUnknownType)\n        with pytest.raises(ResolutionFailed):\n            check_can_generate_examples(fails_2)\n\n\n@skipif_threading\ndef test_cannot_register_empty():\n    # Cannot register and did not register\n    with pytest.raises(InvalidArgument):\n        st.register_type_strategy(UnknownType, st.nothing())\n    fails = st.from_type(UnknownType)\n    with pytest.raises(ResolutionFailed):\n        check_can_generate_examples(fails)\n    assert UnknownType not in types._global_type_lookup\n\n\ndef test_pulic_interface_works():\n    check_can_generate_examples(st.from_type(int))\n    fails = st.from_type(\"not a type or annotated function\")\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(fails)\n\n\n@pytest.mark.parametrize(\"infer_token\", [infer, ...])\ndef test_given_can_infer_from_manual_annotations(infer_token):\n    # Editing annotations before decorating is hilariously awkward, but works!\n    def inner(a):\n        assert isinstance(a, int)\n\n    inner.__annotations__ = {\"a\": int}\n    given(a=infer_token)(inner)()\n\n\nclass EmptyEnum(enum.Enum):\n    pass\n\n\n@fails_with(InvalidArgument)\n@given(st.from_type(EmptyEnum))\ndef test_error_if_enum_is_empty(x):\n    pass\n\n\nclass BrokenClass:\n    __init__ = \"Hello!\"\n\n\ndef test_uninspectable_builds():\n    with pytest.raises(TypeError, match=\"object is not callable\"):\n        check_can_generate_examples(st.builds(BrokenClass))\n\n\ndef test_uninspectable_from_type():\n    with pytest.raises(TypeError, match=\"object is not callable\"):\n        check_can_generate_examples(st.from_type(BrokenClass))\n\n\ndef _check_instances(t):\n    # See https://github.com/samuelcolvin/pydantic/discussions/2508\n    return (\n        t.__module__ != \"typing\"\n        and t.__name__ != \"ByteString\"\n        and not t.__module__.startswith(\"pydantic\")\n        and t.__module__ != \"typing_extensions\"\n    )\n\n\ndef maybe_mark(x):\n    if x.__name__ in \"Match Decimal IPv4Address\":\n        marks = xfail_on_crosshair(Why.other, as_marks=True, strict=False)\n        return pytest.param(x, marks=marks)\n    return x\n\n\n@pytest.mark.parametrize(\n    \"typ\",\n    sorted(\n        (maybe_mark(x) for x in _global_type_lookup if _check_instances(x)),\n        key=str,\n    ),\n)\n@given(data=st.data())\ndef test_can_generate_from_all_registered_types(data, typ):\n    value = data.draw(st.from_type(typ), label=\"value\")\n    assert isinstance(value, typ)\n\n\nT = TypeVar(\"T\")\n\n\nclass MyGeneric(Generic[T]):\n    def __init__(self, arg: T) -> None:\n        self.arg = arg\n\n\nclass Lines(Sequence[str]):\n    \"\"\"Represent a sequence of text lines.\n\n    It turns out that resolving a class which inherits from a parametrised generic\n    type is... tricky.  See https://github.com/HypothesisWorks/hypothesis/issues/2951\n    \"\"\"\n\n\nclass SpecificDict(dict[int, int]):\n    pass\n\n\ndef using_generic(instance: MyGeneric[T]) -> T:\n    return instance.arg\n\n\ndef using_concrete_generic(instance: MyGeneric[int]) -> int:\n    return instance.arg\n\n\ndef test_generic_origin_empty():\n    with pytest.raises(ResolutionFailed):\n        check_can_generate_examples(st.builds(using_generic))\n\n\ndef test_issue_2951_regression():\n    lines_strat = st.builds(Lines, lines=st.lists(st.text()))\n    prev_seq_int_repr = repr(st.from_type(Sequence[int]))\n    with temp_registered(Lines, lines_strat):\n        assert st.from_type(Lines) == lines_strat\n        # Now let's test that the strategy for ``Sequence[int]`` did not\n        # change just because we registered a strategy for ``Lines``:\n        assert repr(st.from_type(Sequence[int])) == prev_seq_int_repr\n\n\ndef test_issue_2951_regression_two_params():\n    map_strat = st.builds(SpecificDict, st.dictionaries(st.integers(), st.integers()))\n    expected = repr(st.from_type(dict[int, int]))\n    with temp_registered(SpecificDict, map_strat):\n        assert st.from_type(SpecificDict) == map_strat\n        assert expected == repr(st.from_type(dict[int, int]))\n\n\n@pytest.mark.parametrize(\n    \"generic\",\n    (\n        Union[str, int],\n        str | int,\n        Sequence[Sequence[int]],\n        MyGeneric[str],\n        Callable[..., str],\n        Callable[[int], str],\n    ),\n    ids=repr,\n)\n@pytest.mark.parametrize(\"strategy\", [st.none(), lambda _: st.none()])\ndef test_generic_origin_with_type_args(generic, strategy):\n    with pytest.raises(InvalidArgument):\n        st.register_type_strategy(generic, strategy)\n    assert generic not in types._global_type_lookup\n\n\n@pytest.mark.parametrize(\n    \"generic\",\n    (\n        Callable,\n        list,\n        Sequence,\n        # you can register types with all generic parameters\n        _List[T],\n        getattr(typing, \"Sequence\", None)[T],  # pyupgrade workaround\n        list[T],\n        Sequence[T],\n        # User-defined generics should also work\n        MyGeneric,\n        MyGeneric[T],\n    ),\n)\ndef test_generic_origin_without_type_args(generic):\n    with temp_registered(generic, st.just(\"example\")):\n        pass\n\n\n@pytest.mark.parametrize(\n    \"strat, type_\",\n    [\n        (st.from_type, MyGeneric[T]),\n        (st.from_type, MyGeneric[int]),\n        (st.from_type, MyGeneric),\n        (st.builds, using_generic),\n        (st.builds, using_concrete_generic),\n    ],\n    ids=get_pretty_function_description,\n)\ndef test_generic_origin_from_type(strat, type_):\n    with temp_registered(MyGeneric, st.builds(MyGeneric)):\n        check_can_generate_examples(strat(type_))\n\n\ndef test_generic_origin_concrete_builds():\n    with temp_registered(MyGeneric, st.builds(MyGeneric, st.integers())):\n        assert_all_examples(\n            st.builds(using_generic), lambda example: isinstance(example, int)\n        )\n\n\nclass AbstractFoo(abc.ABC):\n    def __init__(self, x):  # noqa: B027\n        pass\n\n    @abc.abstractmethod\n    def qux(self):\n        pass\n\n\nclass ConcreteFoo1(AbstractFoo):\n    # Can't resolve this one due to unannotated `x` param\n    def qux(self):\n        pass\n\n\nclass ConcreteFoo2(AbstractFoo):\n    def __init__(self, x: int):\n        pass\n\n    def qux(self):\n        pass\n\n\n@given(st.from_type(AbstractFoo))\ndef test_gen_abstract(foo):\n    # This requires that we correctly checked which of the subclasses\n    # could be resolved, rather than unconditionally using all of them.\n    assert isinstance(foo, ConcreteFoo2)\n\n\nclass AbstractBar(abc.ABC):\n    def __init__(self, x):  # noqa: B027\n        pass\n\n    @abc.abstractmethod\n    def qux(self):\n        pass\n\n\nclass ConcreteBar(AbstractBar):\n    def qux(self):\n        pass\n\n\ndef test_abstract_resolver_fallback():\n    # We create our distinct strategies for abstract and concrete types\n    gen_abstractbar = st.from_type(AbstractBar)\n    gen_concretebar = st.builds(ConcreteBar, x=st.none())\n    assert gen_abstractbar != gen_concretebar\n\n    # And trying to generate an instance of the abstract type fails,\n    # UNLESS the concrete type is currently resolvable\n    with pytest.raises(ResolutionFailed):\n        check_can_generate_examples(gen_abstractbar)\n    with temp_registered(ConcreteBar, gen_concretebar):\n        # which in turn means we resolve to the concrete subtype.\n        assert_simple_property(\n            gen_abstractbar, lambda gen: isinstance(gen, ConcreteBar)\n        )\n    with pytest.raises(ResolutionFailed):\n        check_can_generate_examples(gen_abstractbar)\n\n\ndef _one_arg(x: int):\n    assert isinstance(x, int)\n\n\ndef _multi_arg(x: int, y: str):\n    assert isinstance(x, int)\n    assert isinstance(y, str)\n\n\ndef _kwd_only(*, y: str):\n    assert isinstance(y, str)\n\n\ndef _pos_and_kwd_only(x: int, *, y: str):\n    assert isinstance(x, int)\n    assert isinstance(y, str)\n\n\n@pytest.mark.parametrize(\"func\", [_one_arg, _multi_arg, _kwd_only, _pos_and_kwd_only])\ndef test_infer_all(func):\n    # tests @given(...) against various signatures\n    settings(max_examples=1)(given(...))(func)()\n\n\ndef test_does_not_add_param_empty_to_type_hints():\n    def f(x):\n        pass\n\n    f.__signature__ = Signature([P(\"y\", P.KEYWORD_ONLY)], return_annotation=None)\n    assert get_type_hints(f) == {}\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_type_lookup_forward_ref.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\nWe need these test to make sure ``TypeVar('X', bound='MyType')`` works correctly.\n\nThere was a problem previously that ``bound='MyType'`` was resolved as ``ForwardRef('MyType')``\nwhich is not a real type. And ``hypothesis`` was not able to generate any meaningful values out of it.\n\nRight here we test different possible outcomes for different Python versions:\n- Regular case, when ``'MyType'`` can be imported\n- Alias case, when we use type aliases for ``'MyType'``\n- ``if TYPE_CHECKING:`` case, when ``'MyType'`` only exists during type checking and is not importable at all\n- Dot access case, like ``'module.MyType'``\n- Missing case, when there's no ``'MyType'`` at all\n\"\"\"\n\nfrom typing import TYPE_CHECKING, ForwardRef, TypeVar\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import ResolutionFailed\n\nfrom tests.common import utils\nfrom tests.common.debug import check_can_generate_examples\n\nif TYPE_CHECKING:\n    from tests.common.utils import ExcInfo  # we just need any type\n\n# Correct:\n\n_Correct = TypeVar(\"_Correct\", bound=\"CustomType\")\n\n\ndef correct_fun(thing: _Correct) -> int:\n    return thing.arg\n\n\nclass CustomType:\n    def __init__(self, arg: int) -> None:\n        self.arg = arg\n\n\n@given(st.builds(correct_fun))\ndef test_bound_correct_forward_ref(built):\n    \"\"\"Correct resolution of existing type codebase.\"\"\"\n    assert isinstance(built, int)\n\n\n# Aliases:\n\n_Alias = TypeVar(\"_Alias \", bound=\"OurAlias\")\n\n\ndef alias_fun(thing: _Alias) -> int:\n    return thing.arg\n\n\nOurAlias = CustomType\n\n\n@given(st.builds(alias_fun))\ndef test_bound_alias_forward_ref(built):\n    \"\"\"Correct resolution of type aliases.\"\"\"\n    assert isinstance(built, int)\n\n\n# Dot access:\n\n_CorrectDotAccess = TypeVar(\"_CorrectDotAccess\", bound=\"utils.ExcInfo\")\n_WrongDotAccess = TypeVar(\"_WrongDotAccess\", bound=\"wrong.ExcInfo\")  # noqa\n_MissingDotAccess = TypeVar(\"_MissingDotAccess\", bound=\"utils.MissingType\")\n\n\ndef correct_dot_access_fun(thing: _CorrectDotAccess) -> int:\n    return 1\n\n\ndef wrong_dot_access_fun(thing: _WrongDotAccess) -> int:\n    return 1\n\n\ndef missing_dot_access_fun(thing: _MissingDotAccess) -> int:\n    return 1\n\n\n@given(st.builds(correct_dot_access_fun))\ndef test_bound_correct_dot_access_forward_ref(built):\n    \"\"\"Correct resolution of dot access types.\"\"\"\n    assert isinstance(built, int)\n\n\n@pytest.mark.parametrize(\"function\", [wrong_dot_access_fun, missing_dot_access_fun])\ndef test_bound_missing_dot_access_forward_ref(function):\n    \"\"\"Resolution of missing type in dot access.\"\"\"\n    with pytest.raises(ResolutionFailed):\n        check_can_generate_examples(st.builds(function))\n\n\n# Missing:\n\n_Missing = TypeVar(\"_Missing\", bound=\"MissingType\")  # noqa\n\n\ndef missing_fun(thing: _Missing) -> int:\n    return 1\n\n\ndef test_bound_missing_forward_ref():\n    \"\"\"We should raise proper errors on missing types.\"\"\"\n    with pytest.raises(ResolutionFailed):\n        check_can_generate_examples(st.builds(missing_fun))\n\n\n# Type checking only:\n\n_TypeChecking = TypeVar(\"_TypeChecking\", bound=\"ExcInfo\")\n\n\ndef typechecking_only_fun(thing: _TypeChecking) -> int:\n    return 1\n\n\ndef test_bound_type_cheking_only_forward_ref():\n    \"\"\"We should fallback to registering explicit ``ForwardRef`` when we have to.\"\"\"\n    with utils.temp_registered(ForwardRef(\"ExcInfo\"), st.just(1)):\n        check_can_generate_examples(st.builds(typechecking_only_fun))\n\n\ndef test_bound_type_checking_only_forward_ref_wrong_type():\n    \"\"\"We should check ``ForwardRef`` parameter name correctly.\"\"\"\n    with (\n        utils.temp_registered(ForwardRef(\"WrongType\"), st.just(1)),\n        pytest.raises(ResolutionFailed),\n    ):\n        check_can_generate_examples(st.builds(typechecking_only_fun))\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_typealias_py312.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections.abc import Callable\nfrom typing import get_args, get_origin\n\nimport pytest\n\nfrom hypothesis import strategies as st\nfrom hypothesis.errors import HypothesisException\nfrom hypothesis.strategies._internal.types import evaluate_type_alias_type\n\nfrom tests.common.debug import assert_simple_property, find_any\nfrom tests.common.utils import temp_registered\n\n\ndef test_resolves_simple_typealias():\n    type MyInt = int\n    type AliasedInt = MyInt\n    type MaybeInt = int | None\n\n    assert_simple_property(st.from_type(MyInt), lambda x: isinstance(x, int))\n    assert_simple_property(st.from_type(AliasedInt), lambda x: isinstance(x, int))\n    assert_simple_property(\n        st.from_type(MaybeInt), lambda x: isinstance(x, int) or x is None\n    )\n\n    find_any(st.from_type(MaybeInt), lambda x: isinstance(x, int))\n    find_any(st.from_type(MaybeInt), lambda x: x is None)\n\n\ndef test_resolves_nested():\n    type Point1 = int\n    type Point2 = Point1\n    type Point3 = Point2\n\n    assert_simple_property(st.from_type(Point3), lambda x: isinstance(x, int))\n\n\ndef test_resolves_parametrized():\n    type MyList = list[int]\n    assert_simple_property(\n        st.from_type(MyList), lambda l: all(isinstance(x, int) for x in l)\n    )\n\n\ndef test_mutually_recursive_fails():\n    # example from\n    # https://docs.python.org/3/library/typing.html#typing.TypeAliasType.__value__\n    type A = B\n    type B = A\n\n    # I guess giving a nicer error here would be good, but detecting this in general\n    # is...complicated.\n    with pytest.raises(RecursionError):\n        find_any(st.from_type(A))\n\n\ndef test_mutually_recursive_fails_parametrized():\n    # same with parametrized types\n    type A[T] = B[T]\n    type B[T] = A[T]\n\n    with pytest.raises(RecursionError):\n        find_any(st.from_type(A[int]))\n\n\ndef test_can_register_typealias():\n    type A = int\n    st.register_type_strategy(A, st.just(\"a\"))\n    assert_simple_property(st.from_type(A), lambda x: x == \"a\")\n\n\ndef test_prefers_manually_registered_typealias():\n    # manually registering a `type A = ...` should override automatic detection\n    type A = int\n\n    assert_simple_property(st.from_type(A), lambda x: isinstance(x, int))\n\n    with temp_registered(A, st.booleans()):\n        assert_simple_property(st.from_type(A), lambda x: isinstance(x, bool))\n\n\ndef test_resolves_parameterized_typealias():\n    type A[T] = list[T]\n\n    assert_simple_property(st.from_type(A[int]), lambda x: isinstance(x, list))\n    find_any(st.from_type(A[int]), lambda x: len(x) > 0)\n    assert_simple_property(\n        st.from_type(A[int]), lambda x: all(isinstance(i, int) for i in x)\n    )\n\n\ndef test_resolves_nested_parameterized_typealias():\n    type Inner[T] = list[T]\n    type Outer[T] = Inner[T]\n\n    assert_simple_property(st.from_type(Outer[str]), lambda x: isinstance(x, list))\n    assert_simple_property(\n        st.from_type(Outer[str]), lambda x: all(isinstance(i, str) for i in x)\n    )\n\n\ndef test_resolves_parameterized_typealias_with_literal_types():\n    # Type param used in non-first position with literal types\n    type MyDict[T] = dict[str, T]\n\n    assert_simple_property(st.from_type(MyDict[int]), lambda x: isinstance(x, dict))\n    assert_simple_property(\n        st.from_type(MyDict[int]),\n        lambda x: all(isinstance(k, str) and isinstance(v, int) for k, v in x.items()),\n    )\n\n\ndef test_can_register_parameterized_typealias_with_unused_params():\n    # Users can explicitly register strategies for such types using a resolver function\n    type MyList[T1, T2] = list[T1]\n\n    # Register a function that resolves the type alias\n    def resolve_mylist(thing):\n        if get_origin(thing) is MyList:\n            args = get_args(thing)\n            # Use the first type argument, ignore the second\n            return st.lists(st.from_type(args[0]))\n        return NotImplemented\n\n    st.register_type_strategy(MyList, resolve_mylist)\n\n    assert_simple_property(\n        st.from_type(MyList[int, float]), lambda x: isinstance(x, list)\n    )\n    assert_simple_property(\n        st.from_type(MyList[int, float]), lambda x: all(isinstance(i, int) for i in x)\n    )\n\n\ndef test_typealias_evaluation():\n    type A[T1, T2] = list[T1]\n    assert evaluate_type_alias_type(A[int, float]) == list[int]\n\n    type A[T1, T2] = list[T2]\n    assert evaluate_type_alias_type(A[float, int]) == list[int]\n\n    type A[K, V] = dict[V, K]\n    assert evaluate_type_alias_type(A[str, int]) == dict[int, str]\n\n    type A[T] = list[list[T]]\n    assert evaluate_type_alias_type(A[int]) == list[list[int]]\n\n    type Inner[T] = list[T]\n    type Outer[T] = Inner[T]\n    assert evaluate_type_alias_type(Outer[int]) == list[int]\n\n    type Bare[T] = list\n    assert evaluate_type_alias_type(Bare[int]) == list\n\n    type A[T1, T2] = list[T1]\n    assert evaluate_type_alias_type(A[int]) == list[int]\n\n    # tries to reference free variable\n    type A[T1, T2] = list[T2]\n    with pytest.raises(ValueError):\n        evaluate_type_alias_type(A[int])\n\n    # (currently) unsupported type forms\n    type A[*Ts] = tuple[*Ts]\n    with pytest.raises(HypothesisException, match=\"Hypothesis does not yet support\"):\n        assert evaluate_type_alias_type(A[int, str, float]) == tuple[int, str, float]\n\n    type A[**P] = Callable[P, int]\n    with pytest.raises(HypothesisException, match=\"Hypothesis does not yet support\"):\n        assert evaluate_type_alias_type(A[[str, float]]) == Callable[[str, float], int]\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_unicode_identifiers.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.internal.reflection import get_pretty_function_description, proxies\n\n\ndef test_can_copy_signature_of_unicode_args():\n    def foo(μ):\n        return μ\n\n    @proxies(foo)\n    def bar(μ):\n        return foo(μ)\n\n    assert bar(1) == 1\n\n\ndef test_can_copy_signature_of_unicode_name():\n    def ā():\n        return 1\n\n    @proxies(ā)\n    def bar():\n        return 2\n\n    assert bar() == 2\n\n\nis_approx_π = lambda x: x == 3.1415\n\n\ndef test_can_handle_unicode_identifier_in_same_line_as_lambda_def():\n    assert get_pretty_function_description(is_approx_π) == \"lambda x: x == 3.1415\"\n\n\ndef test_regression_issue_1700():\n    π = 3.1415\n\n    @given(st.floats(min_value=-π, max_value=π).filter(lambda x: abs(x) > 1e-5))\n    def test_nonzero(x):\n        assert x != 0\n\n    test_nonzero()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_unittest.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport io\nimport sys\nimport unittest\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import FailedHealthCheck, HypothesisWarning\n\nfrom tests.common.utils import fails_with, skipif_emscripten\n\n\nclass Thing_with_a_subThing(unittest.TestCase):\n    \"\"\"Example test case using subTest for the actual test below.\"\"\"\n\n    @given(st.tuples(st.booleans(), st.booleans()))\n    def thing(self, lst):\n        for i, b in enumerate(lst):\n            with pytest.warns(HypothesisWarning), self.subTest((i, b)):\n                self.assertTrue(b)\n\n\ndef test_subTest():\n    suite = unittest.TestSuite()\n    suite.addTest(Thing_with_a_subThing(\"thing\"))\n    stream = io.StringIO()\n    out = unittest.TextTestRunner(stream=stream).run(suite)\n    assert len(out.failures) <= out.testsRun, out\n\n\nclass test_given_on_setUp_fails_health_check(unittest.TestCase):\n    @fails_with(FailedHealthCheck)\n    @given(st.integers())\n    def setUp(self, i):\n        pass\n\n    def test(self):\n        \"\"\"Provide something to set up for, so the setUp method is called.\"\"\"\n\n\nSUBTEST_SUITE = \"\"\"\nimport unittest\nfrom hypothesis import given, settings, strategies as st\n\nclass MyTest(unittest.TestCase):\n    @given(s=st.text())\n    @settings(deadline=None)\n    def test_subtest(self, s):\n        with self.subTest(text=s):\n            self.assertIsInstance(s, str)\n\nif __name__ == \"__main__\":\n    unittest.main()\n\"\"\"\n\n\n@skipif_emscripten\n@pytest.mark.parametrize(\"err\", [[], [\"-Werror\"]])\ndef test_subTest_no_self(testdir, err):\n    # https://github.com/HypothesisWorks/hypothesis/issues/2462\n    # for some reason this issue happens only when running unittest from commandline\n    fname = testdir.makepyfile(tests=SUBTEST_SUITE)\n    result = testdir.run(sys.executable, *err, str(fname))\n    expected = pytest.ExitCode.TESTS_FAILED if err else pytest.ExitCode.OK\n    assert result.ret == expected, result.stderr.str()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_uuids.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport uuid\n\nimport pytest\n\nfrom hypothesis import strategies as st\nfrom hypothesis.errors import InvalidArgument\n\nfrom tests.common.debug import assert_no_examples, check_can_generate_examples, find_any\n\n\ndef test_no_nil_uuid_by_default():\n    assert_no_examples(st.uuids(), lambda x: x == uuid.UUID(int=0))\n\n\ndef test_can_generate_nil_uuid():\n    find_any(st.uuids(allow_nil=True), lambda x: x == uuid.UUID(int=0))\n\n\ndef test_can_only_allow_nil_uuid_with_none_version():\n    check_can_generate_examples(st.uuids(version=None, allow_nil=True))\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(st.uuids(version=4, allow_nil=True))\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(st.uuids(version=None, allow_nil=\"not a bool\"))\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_validation.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport functools\nimport warnings\n\nimport pytest\n\nfrom hypothesis import find, given, strategies as st\nfrom hypothesis.errors import HypothesisWarning, InvalidArgument\nfrom hypothesis.internal.validation import check_type\nfrom hypothesis.strategies import (\n    SearchStrategy as ActualSearchStrategy,\n    binary,\n    booleans,\n    data,\n    dictionaries,\n    floats,\n    frozensets,\n    integers,\n    lists,\n    nothing,\n    recursive,\n    sets,\n    text,\n)\nfrom hypothesis.strategies._internal.strategies import check_strategy\n\nfrom tests.common.debug import check_can_generate_examples, find_any\nfrom tests.common.utils import fails_with\n\n\ndef test_errors_when_given_varargs():\n    @given(integers())\n    def has_varargs(*args):\n        pass\n\n    with pytest.raises(InvalidArgument) as e:\n        has_varargs()\n    assert \"varargs\" in e.value.args[0]\n\n\ndef test_varargs_without_positional_arguments_allowed():\n    @given(somearg=integers())\n    def has_varargs(somearg, *args):\n        pass\n\n\ndef test_errors_when_given_varargs_and_kwargs_with_positional_arguments():\n    @given(integers())\n    def has_varargs(*args, **kw):\n        pass\n\n    with pytest.raises(InvalidArgument) as e:\n        has_varargs()\n    assert \"varargs\" in e.value.args[0]\n\n\ndef test_varargs_and_kwargs_without_positional_arguments_allowed():\n    @given(somearg=integers())\n    def has_varargs(*args, **kw):\n        pass\n\n\ndef test_bare_given_errors():\n    @given()\n    def test():\n        pass\n\n    with pytest.raises(InvalidArgument):\n        test()\n\n\ndef test_errors_on_unwanted_kwargs():\n    @given(hello=int, world=int)\n    def greet(world):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        greet()\n\n\ndef test_errors_on_too_many_positional_args():\n    @given(integers(), int, int)\n    def foo(x, y):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        foo()\n\n\ndef test_errors_on_any_varargs():\n    @given(integers())\n    def oops(*args):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        oops()\n\n\ndef test_can_put_arguments_in_the_middle():\n    @given(y=integers())\n    def foo(x, y, z):\n        pass\n\n    foo(1, 2)\n\n\ndef test_float_ranges():\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(floats(float(\"nan\"), 0))\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(floats(1, -1))\n\n\ndef test_float_range_and_allow_nan_cannot_both_be_enabled():\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(floats(min_value=1, allow_nan=True))\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(floats(max_value=1, allow_nan=True))\n\n\ndef test_float_finite_range_and_allow_infinity_cannot_both_be_enabled():\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(floats(0, 1, allow_infinity=True))\n\n\ndef test_does_not_error_if_min_size_is_bigger_than_default_size():\n    find_any(lists(integers(), min_size=50))\n    find_any(sets(integers(), min_size=50))\n    find_any(frozensets(integers(), min_size=50))\n    find_any(lists(integers(), min_size=50, unique=True))\n\n\ndef test_list_unique_and_unique_by_cannot_both_be_enabled():\n    @given(lists(integers(), unique=True, unique_by=lambda x: x))\n    def boom(t):\n        pass\n\n    with pytest.raises(InvalidArgument) as e:\n        boom()\n    assert \"unique \" in e.value.args[0]\n    assert \"unique_by\" in e.value.args[0]\n\n\ndef test_min_before_max():\n    with pytest.raises(InvalidArgument):\n        integers(min_value=1, max_value=0).validate()\n\n\ndef test_filter_validates():\n    with pytest.raises(InvalidArgument):\n        integers(min_value=1, max_value=0).filter(bool).validate()\n\n\ndef test_recursion_validates_base_case():\n    with pytest.raises(InvalidArgument):\n        recursive(integers(min_value=1, max_value=0), lists).validate()\n\n\ndef test_recursion_validates_recursive_step():\n    with pytest.raises(InvalidArgument):\n        recursive(integers(), lambda x: lists(x, min_size=3, max_size=1)).validate()\n\n\n@fails_with(InvalidArgument)\n@given(x=integers())\ndef test_stuff_keyword(x=1):  # noqa: PT028\n    pass\n\n\n@fails_with(InvalidArgument)\n@given(integers())\ndef test_stuff_positional(x=1):  # noqa: PT028\n    pass\n\n\n@fails_with(InvalidArgument)\n@given(integers(), integers())\ndef test_too_many_positional(x):\n    pass\n\n\ndef test_given_warns_on_use_of_non_strategies():\n    @given(bool)\n    def test(x):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        test()\n\n\ndef test_given_warns_when_mixing_positional_with_keyword():\n    @given(booleans(), y=booleans())\n    def test(x, y):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        test()\n\n\ndef test_cannot_find_non_strategies():\n    with pytest.raises(InvalidArgument):\n        find(bool, bool)\n\n\n@pytest.mark.parametrize(\n    \"strategy\",\n    [\n        functools.partial(lists, elements=integers()),\n        functools.partial(dictionaries, keys=integers(), values=integers()),\n        text,\n        binary,\n    ],\n)\n@pytest.mark.parametrize(\"min_size,max_size\", [(0, \"10\"), (\"0\", 10)])\ndef test_valid_sizes(strategy, min_size, max_size):\n    @given(strategy(min_size=min_size, max_size=max_size))\n    def test(x):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        test()\n\n\ndef test_check_type_with_tuple_of_length_two():\n    def type_checker(x):\n        check_type((int, str), x, \"x\")\n\n    type_checker(1)\n    type_checker(\"1\")\n    with pytest.raises(InvalidArgument, match=\"Expected one of int, str but got \"):\n        type_checker(1.0)\n\n\ndef test_validation_happens_on_draw():\n    @given(data())\n    def test(data):\n        data.draw(integers().flatmap(lambda _: lists(nothing(), min_size=1)))\n\n    with pytest.raises(InvalidArgument, match=\"has no values\"):\n        test()\n\n\nclass SearchStrategy:\n    \"\"\"Not the SearchStrategy type you were looking for.\"\"\"\n\n\ndef check_type_(*args):\n    return check_type(*args)\n\n\ndef test_check_type_suggests_check_strategy():\n    check_type_(SearchStrategy, SearchStrategy(), \"this is OK\")\n    with pytest.raises(AssertionError, match=\"use check_strategy instead\"):\n        check_type_(ActualSearchStrategy, None, \"SearchStrategy assertion\")\n\n\ndef check_strategy_(*args):\n    return check_strategy(*args)\n\n\ndef test_check_strategy_might_suggest_sampled_from():\n    with pytest.raises(InvalidArgument) as excinfo:\n        check_strategy_(\"not a strategy\")\n    assert \"sampled_from\" not in str(excinfo.value)\n    with pytest.raises(InvalidArgument, match=\"such as st\\\\.sampled_from\"):\n        check_strategy_([1, 2, 3])\n    with pytest.raises(InvalidArgument, match=\"such as st\\\\.sampled_from\"):\n        check_strategy_((1, 2, 3))\n    check_strategy_(integers(), \"passes for our custom coverage check\")\n\n\n@pytest.mark.parametrize(\"codec\", [\"ascii\", \"utf-8\"])\ndef test_warn_on_strings_matching_common_codecs(codec):\n    with pytest.warns(\n        HypothesisWarning,\n        match=f\"it seems like you are trying to use the codec {codec!r}\",\n    ):\n\n        @given(st.text(codec))\n        def f(s):\n            pass\n\n        f()\n\n    # if we reorder, it doesn't warn anymore\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"error\")\n\n        @given(st.text(codec[1:] + codec[:1]))\n        def f(s):\n            pass\n\n        f()\n"
  },
  {
    "path": "hypothesis-python/tests/cover/test_verbosity.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom contextlib import contextmanager\n\nfrom hypothesis import example, find, given\nfrom hypothesis._settings import Verbosity, settings\nfrom hypothesis.reporting import default as default_reporter, with_reporter\nfrom hypothesis.strategies import booleans, integers, lists\n\nfrom tests.common.debug import minimal\nfrom tests.common.utils import Why, capture_out, fails, xfail_on_crosshair\n\n\n@contextmanager\ndef capture_verbosity():\n    with capture_out() as o, with_reporter(default_reporter):\n        yield o\n\n\ndef test_prints_intermediate_in_success():\n    with capture_verbosity() as o:\n\n        @settings(verbosity=Verbosity.verbose)\n        @given(booleans())\n        def test_works(x):\n            pass\n\n        test_works()\n    assert \"Trying example\" in o.getvalue()\n\n\ndef test_does_not_log_in_quiet_mode():\n    with capture_verbosity() as o:\n\n        @fails\n        @settings(verbosity=Verbosity.quiet, print_blob=False)\n        @given(integers())\n        def test_foo(x):\n            raise AssertionError\n\n        test_foo()\n    assert not o.getvalue()\n\n\ndef test_includes_progress_in_verbose_mode():\n    with capture_verbosity() as o:\n        minimal(\n            lists(integers(), min_size=1),\n            lambda x: sum(x) >= 100,\n            settings(verbosity=Verbosity.verbose),\n        )\n    out = o.getvalue()\n    assert out\n    assert \"Trying example: \" in out\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)\ndef test_prints_initial_attempts_on_find():\n    with capture_verbosity() as o:\n\n        def foo():\n            seen = []\n\n            def not_first(x):\n                if not seen:\n                    seen.append(x)\n                    return False\n                return x not in seen\n\n            find(\n                integers(),\n                not_first,\n                settings=settings(verbosity=Verbosity.verbose, max_examples=1000),\n            )\n\n        foo()\n\n    assert \"Trying example\" in o.getvalue()\n\n\ndef test_includes_intermediate_results_in_verbose_mode():\n    with capture_verbosity() as o:\n\n        @fails\n        @settings(\n            verbosity=Verbosity.verbose,\n            database=None,\n            derandomize=True,\n            max_examples=100,\n        )\n        @given(lists(integers(), min_size=1))\n        def test_foo(x):\n            assert sum(x) < 10000\n\n        test_foo()\n    lines = o.getvalue().splitlines()\n    assert len([l for l in lines if \"example\" in l]) > 2\n    assert [l for l in lines if \"AssertionError\" in l]\n\n\n@example(0)\n@settings(verbosity=Verbosity.quiet)\n@given(integers())\ndef test_no_indexerror_in_quiet_mode(x):\n    # Regression tests for https://github.com/HypothesisWorks/hypothesis/issues/2696\n    # where quiet mode -> no fragments to report -> IndexError accessing first report\n    pass\n\n\n@fails\n@example(0)\n@settings(verbosity=Verbosity.quiet, report_multiple_bugs=True)\n@given(integers())\ndef test_no_indexerror_in_quiet_mode_report_multiple(x):\n    assert x\n\n\n@fails\n@example(0)\n@settings(verbosity=Verbosity.quiet, report_multiple_bugs=False)\n@given(integers())\ndef test_no_indexerror_in_quiet_mode_report_one(x):\n    assert x\n"
  },
  {
    "path": "hypothesis-python/tests/crosshair/test_conformance.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom crosshair.core import IgnoreAttempt, NotDeterministic, UnexploredPath\nfrom hypothesis_crosshair_provider.crosshair_provider import CrossHairPrimitiveProvider\n\nfrom hypothesis import Verbosity, settings, strategies as st\nfrom hypothesis.internal.conjecture.provider_conformance import run_conformance_test\n\n\ndef test_provider_conformance_crosshair():\n    # Hypothesis can in theory pass values of any type to `realize`,\n    # but the default strategy in the conformance test here acts too much like a\n    # fuzzer for crosshair internals here and finds very strange errors.\n    _realize_objects = (\n        st.integers() | st.floats() | st.booleans() | st.binary() | st.text()\n    )\n    run_conformance_test(\n        CrossHairPrimitiveProvider,\n        context_manager_exceptions=(IgnoreAttempt, UnexploredPath, NotDeterministic),\n        settings=settings(\n            max_examples=5,\n            stateful_step_count=10,\n            # It's nice to set Verbosity.verbose unconditionally here so we get\n            # more information during rare errors without having to retry.\n            #\n            # Careful, though: it's possible interactions with crosshair differ\n            # under verbosity (eg realizing the symbolic debug messages), so\n            # some errors may only surface with or without verbosity.\n            verbosity=Verbosity.verbose,\n        ),\n        _realize_objects=_realize_objects,\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/crosshair/test_crosshair.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport crosshair\nimport pytest\nfrom hypothesis_crosshair_provider.crosshair_provider import CrossHairPrimitiveProvider\n\nfrom hypothesis import Phase, Verbosity, event, given, settings, strategies as st\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.internal.conjecture.providers import COLLECTION_DEFAULT_MAX_SIZE\nfrom hypothesis.internal.intervalsets import IntervalSet\nfrom hypothesis.internal.observability import with_observability_callback\nfrom hypothesis.vendor.pretty import pretty\n\nfrom tests.common.utils import capture_observations\nfrom tests.conjecture.common import float_constr, integer_constr, string_constr\n\n\n@pytest.mark.parametrize(\"verbosity\", list(Verbosity))\ndef test_crosshair_works_for_all_verbosities(verbosity):\n    # check that we aren't realizing symbolics early in debug prints and killing\n    # test effectiveness.\n    @given(st.integers())\n    @settings(backend=\"crosshair\", verbosity=verbosity, database=None)\n    def f(n):\n        assert n != 123456\n\n    with pytest.raises(AssertionError):\n        f()\n\n\n@pytest.mark.parametrize(\"verbosity\", list(Verbosity))\ndef test_crosshair_works_for_all_verbosities_data(verbosity):\n    # data draws have their own print path\n    if verbosity == Verbosity.quiet:\n        pytest.skip(\"Flaky test, pending fix\")\n\n    @given(st.data())\n    @settings(backend=\"crosshair\", verbosity=verbosity, database=None)\n    def f(data):\n        n = data.draw(st.integers())\n        assert n != 123456\n\n    with pytest.raises(AssertionError):\n        f()\n\n\ndef test_hypothesis_realizes_on_fatal_error():\n    # BaseException or internal hypothesis failures have a different database save\n    # path. Make sure we realize symbolic values on that path. This test is a bit\n    # of a no-op because we're really relying on our realization validation to\n    # pass here.\n    db = InMemoryExampleDatabase()\n\n    @given(st.integers())\n    @settings(database=db, backend=\"crosshair\")\n    def f(n):\n        raise BaseException(\"marker\")\n\n    with pytest.raises(BaseException, match=\"marker\"):\n        f()\n\n\ndef count_choices_for(choice_type, constraints):\n    # returns the number of choices that crosshair makes for this draw, before\n    # hypothesis ever has a chance to interact with it.\n    provider = CrossHairPrimitiveProvider()\n    with provider.per_test_case_context_manager():\n        assert len(crosshair.statespace.context_statespace().choices_made) == 0\n        getattr(provider, f\"draw_{choice_type}\")(**constraints)\n        return len(crosshair.statespace.context_statespace().choices_made)\n\n\n@pytest.mark.parametrize(\n    \"strategy, expected_choices\",\n    [\n        (st.integers(), lambda: count_choices_for(\"integer\", integer_constr())),\n        (st.floats(), lambda: count_choices_for(\"float\", float_constr())),\n        (\n            st.binary(),\n            lambda: count_choices_for(\n                \"bytes\", {\"min_size\": 0, \"max_size\": COLLECTION_DEFAULT_MAX_SIZE}\n            ),\n        ),\n        (st.booleans(), lambda: count_choices_for(\"boolean\", {})),\n        (\n            st.text(),\n            lambda: count_choices_for(\n                \"string\", string_constr(IntervalSet.from_string(\"a\"))\n            ),\n        ),\n    ],\n    ids=pretty,\n)\ndef test_no_path_constraints_are_added_to_symbolic_values(strategy, expected_choices):\n    # check that we don't interact with returned symbolics from the crosshair\n    # provider in a way that would add decisions to crosshair's state space (ie\n    # add path constraints).\n\n    expected_choices = expected_choices()\n    # skip the first call, which is ChoiceTemplate(type=\"simplest\") with the\n    # hypothesis backend.\n    called = False\n\n    # limit to one example to prevent crosshair from raising e.g.\n    # BackendCannotProceed(scope=\"verified\") and switching to the hypothesis\n    # provider\n    @given(strategy)\n    @settings(\n        backend=\"crosshair\", database=None, phases={Phase.generate}, max_examples=2\n    )\n    def f(value):\n        nonlocal called\n        if not called:\n            called = True\n            return\n        # if this test ever fails, we will replay it without crosshair, in which\n        # case the statespace is None.\n        statespace = crosshair.statespace.optional_context_statespace()\n        assert statespace is not None, \"this test failed under crosshair\"\n        assert len(statespace.choices_made) == expected_choices\n\n    f()\n\n\n@pytest.mark.parametrize(\n    \"strategy, extra_observability\",\n    [\n        # we add an additional path constraint to ints in to_jsonable.\n        (st.integers(), 1),\n        (st.text(), 0),\n        (st.booleans(), 0),\n        (st.floats(), 0),\n        (st.binary(), 0),\n    ],\n)\ndef test_observability_and_verbosity_dont_add_choices(strategy, extra_observability):\n    choices = {}\n    # skip the first call, which is ChoiceTemplate(type=\"simplest\") with the\n    # hypothesis backend.\n    called = False\n\n    @given(strategy)\n    @settings(backend=\"crosshair\", database=None, max_examples=2)\n    def f_normal(value):\n        nonlocal called\n        if called:\n            choices[\"normal\"] = len(\n                crosshair.statespace.context_statespace().choices_made\n            )\n        called = True\n\n    f_normal()\n    called = False\n\n    @given(strategy)\n    @settings(\n        backend=\"crosshair\", database=None, max_examples=2, verbosity=Verbosity.debug\n    )\n    def f_verbosity(value):\n        nonlocal called\n        if called:\n            choices[\"verbosity\"] = len(\n                crosshair.statespace.context_statespace().choices_made\n            )\n        called = True\n\n    f_verbosity()\n    called = False\n\n    @given(strategy)\n    @settings(backend=\"crosshair\", database=None, max_examples=2)\n    def f_observability(value):\n        nonlocal called\n        if called:\n            choices[\"observability\"] = len(\n                crosshair.statespace.context_statespace().choices_made\n            )\n        called = True\n\n    with capture_observations():\n        f_observability()\n\n    assert (\n        choices[\"normal\"]\n        == (choices[\"observability\"] - extra_observability)\n        == choices[\"verbosity\"]\n    )\n\n\ndef test_realizes_event():\n    saw_myevent = False\n\n    def callback(observation):\n        if observation.type != \"test_case\":\n            return\n\n        nonlocal saw_myevent\n        # crosshair might raise BackendCannotProceed(verified) during generation,\n        # which never reaches event().\n        if \"myevent\" in observation.features:\n            assert isinstance(observation.features[\"myevent\"], int)\n            saw_myevent = True\n\n    @given(st.integers())\n    @settings(backend=\"crosshair\", max_examples=5)\n    def test(n):\n        event(\"myevent\", n)\n\n    with with_observability_callback(callback):\n        test()\n\n    assert saw_myevent\n\n\n@given(st.integers())\n@settings(backend=\"crosshair\")\ndef test_event_with_realization(value):\n    event(value)\n    float(value)\n"
  },
  {
    "path": "hypothesis-python/tests/datetime/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/datetime/test_dateutil_timezones.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport datetime as dt\nimport sys\nimport warnings\n\nimport pytest\n\nfrom hypothesis import assume, given\nfrom hypothesis.errors import FailedHealthCheck, InvalidArgument\nfrom hypothesis.strategies import data, datetimes, just, sampled_from, times\nfrom hypothesis.strategies._internal.datetime import datetime_does_not_exist\n\nfrom tests.common.debug import assert_all_examples, find_any, minimal\nfrom tests.common.utils import Why, fails_with, xfail_on_crosshair\n\nwith warnings.catch_warnings():\n    if sys.version_info[:2] >= (3, 12):\n        # Prior to https://github.com/dateutil/dateutil/pull/1285/\n        warnings.simplefilter(\"ignore\", DeprecationWarning)\n    from dateutil import tz, zoneinfo\n\nfrom hypothesis.extra.dateutil import timezones\n\n\ndef test_utc_is_minimal():\n    assert tz.UTC is minimal(timezones())\n\n\ndef test_can_generate_non_naive_time():\n    assert minimal(times(timezones=timezones()), lambda d: d.tzinfo).tzinfo == tz.UTC\n\n\ndef test_can_generate_non_naive_datetime():\n    assert (\n        minimal(datetimes(timezones=timezones()), lambda d: d.tzinfo).tzinfo == tz.UTC\n    )\n\n\n@given(datetimes(timezones=timezones()))\ndef test_timezone_aware_datetimes_are_timezone_aware(dt):\n    assert dt.tzinfo is not None\n\n\n@given(sampled_from([\"min_value\", \"max_value\"]), datetimes(timezones=timezones()))\ndef test_datetime_bounds_must_be_naive(name, val):\n    with pytest.raises(InvalidArgument):\n        datetimes(**{name: val}).validate()\n\n\ndef test_timezones_arg_to_datetimes_must_be_search_strategy():\n    all_timezones = zoneinfo.get_zonefile_instance().zones\n    with pytest.raises(InvalidArgument):\n        datetimes(timezones=all_timezones).validate()\n\n\n@given(times(timezones=timezones()))\ndef test_timezone_aware_times_are_timezone_aware(dt):\n    assert dt.tzinfo is not None\n\n\ndef test_can_generate_non_utc():\n    times(timezones=timezones()).filter(\n        lambda d: assume(d.tzinfo) and d.tzinfo.zone != \"UTC\"\n    ).validate()\n\n\n@given(sampled_from([\"min_value\", \"max_value\"]), times(timezones=timezones()))\ndef test_time_bounds_must_be_naive(name, val):\n    with pytest.raises(InvalidArgument):\n        times(**{name: val}).validate()\n\n\ndef test_should_have_correct_ordering():\n    def offset(timezone):\n        return abs(timezone.utcoffset(dt.datetime(2000, 1, 1)))\n\n    next_interesting_tz = minimal(timezones(), lambda tz: offset(tz) > dt.timedelta(0))\n    assert offset(next_interesting_tz) == dt.timedelta(seconds=3600)\n\n\n@given(data(), datetimes(), datetimes())\ndef test_datetimes_stay_within_naive_bounds(data, lo, hi):\n    if lo > hi:\n        lo, hi = hi, lo\n    out = data.draw(datetimes(lo, hi, timezones=timezones()))\n    assert lo <= out.replace(tzinfo=None) <= hi\n\n\nDAY_WITH_IMAGINARY_HOUR_KWARGS = {\n    # The day of a spring-forward transition; 2am is imaginary\n    \"min_value\": dt.datetime(2020, 10, 4),\n    \"max_value\": dt.datetime(2020, 10, 5),\n    \"timezones\": just(tz.gettz(\"Australia/Sydney\")),\n}\n\n\n@xfail_on_crosshair(Why.other, strict=False)  # fromutc argument must be a datetime\n@given(datetimes(timezones=timezones()) | datetimes(**DAY_WITH_IMAGINARY_HOUR_KWARGS))\ndef test_dateutil_exists_our_not_exists_are_inverse(value):\n    assert datetime_does_not_exist(value) == (not tz.datetime_exists(value))\n\n\ndef test_datetimes_can_exclude_imaginary():\n    find_any(\n        datetimes(**DAY_WITH_IMAGINARY_HOUR_KWARGS, allow_imaginary=True),\n        lambda x: not tz.datetime_exists(x),\n    )\n    assert_all_examples(\n        datetimes(**DAY_WITH_IMAGINARY_HOUR_KWARGS, allow_imaginary=False),\n        tz.datetime_exists,\n    )\n\n\n@xfail_on_crosshair(Why.other)\n@fails_with(FailedHealthCheck)\n@given(\n    datetimes(\n        max_value=dt.datetime(1, 1, 1, 9),\n        timezones=just(tz.gettz(\"Australia/Sydney\")),\n        allow_imaginary=False,\n    )\n)\ndef test_non_imaginary_datetimes_at_boundary(val):\n    # This is expected to fail because Australia/Sydney is UTC+10,\n    # and the filter logic overflows when checking for round-trips.\n    raise AssertionError\n"
  },
  {
    "path": "hypothesis-python/tests/datetime/test_pytz_timezones.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport datetime as dt\nimport sys\nimport warnings\n\nimport pytest\n\nfrom hypothesis import assume, given, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument, StopTest\nfrom hypothesis.strategies import data, datetimes, just, sampled_from, times\nfrom hypothesis.strategies._internal.datetime import datetime_does_not_exist\n\nfrom tests.common.debug import assert_all_examples, find_any, minimal\nfrom tests.common.utils import Why, xfail_on_crosshair\n\nwith warnings.catch_warnings():\n    if sys.version_info[:2] >= (3, 12):\n        # See https://github.com/stub42/pytz/issues/105 and\n        # https://github.com/dateutil/dateutil/pull/1285/\n        warnings.simplefilter(\"ignore\", DeprecationWarning)\n    import pytz\n    from dateutil.tz import datetime_exists\n\nfrom hypothesis.extra.pytz import timezones\n\n\ndef test_utc_is_minimal():\n    assert pytz.UTC is minimal(timezones())\n\n\ndef test_can_generate_non_naive_time():\n    assert minimal(times(timezones=timezones()), lambda d: d.tzinfo).tzinfo == pytz.UTC\n\n\ndef test_can_generate_non_naive_datetime():\n    assert (\n        minimal(datetimes(timezones=timezones()), lambda d: d.tzinfo).tzinfo == pytz.UTC\n    )\n\n\n@given(datetimes(timezones=timezones()))\ndef test_timezone_aware_datetimes_are_timezone_aware(dt):\n    assert dt.tzinfo is not None\n\n\n@given(sampled_from([\"min_value\", \"max_value\"]), datetimes(timezones=timezones()))\ndef test_datetime_bounds_must_be_naive(name, val):\n    with pytest.raises(InvalidArgument):\n        datetimes(**{name: val}).validate()\n\n\ndef test_underflow_in_simplify():\n    # we shouldn't trigger a pytz bug when we're simplifying\n    minimal(\n        datetimes(\n            max_value=dt.datetime.min + dt.timedelta(days=3), timezones=timezones()\n        ),\n        lambda x: x.tzinfo != pytz.UTC,\n    )\n\n\ndef test_overflow_in_simplify():\n    # we shouldn't trigger a pytz bug when we're simplifying\n    minimal(\n        datetimes(\n            min_value=dt.datetime.max - dt.timedelta(days=3), timezones=timezones()\n        ),\n        lambda x: x.tzinfo != pytz.UTC,\n    )\n\n\ndef test_timezones_arg_to_datetimes_must_be_search_strategy():\n    with pytest.raises(InvalidArgument):\n        datetimes(timezones=pytz.all_timezones).validate()\n\n    tz = [pytz.timezone(t) for t in pytz.all_timezones]\n    with pytest.raises(InvalidArgument):\n        datetimes(timezones=tz).validate()\n\n\n@given(times(timezones=timezones()))\ndef test_timezone_aware_times_are_timezone_aware(dt):\n    assert dt.tzinfo is not None\n\n\ndef test_can_generate_non_utc():\n    times(timezones=timezones()).filter(\n        lambda d: assume(d.tzinfo) and d.tzinfo.zone != \"UTC\"\n    ).validate()\n\n\n@given(sampled_from([\"min_value\", \"max_value\"]), times(timezones=timezones()))\ndef test_time_bounds_must_be_naive(name, val):\n    with pytest.raises(InvalidArgument):\n        times(**{name: val}).validate()\n\n\n@pytest.mark.parametrize(\n    \"bound\",\n    [\n        {\"min_value\": dt.datetime.max - dt.timedelta(days=3)},\n        {\"max_value\": dt.datetime.min + dt.timedelta(days=3)},\n    ],\n)\ndef test_can_trigger_error_in_draw_near_boundary(bound):\n    found = False\n\n    # this would be better written with find_any, but I couldn't get rewriting\n    # with st.composite and assuming the event condition to work.\n    # https://github.com/HypothesisWorks/hypothesis/pull/4229#discussion_r1907993831\n    @given(st.data())\n    @settings(max_examples=1000)\n    def f(data):\n        try:\n            data.draw(datetimes(**bound, timezones=timezones()))\n        except StopTest:\n            pass\n        if \"Failed to draw a datetime\" in data.conjecture_data.events.get(\n            \"invalid because\", \"\"\n        ):\n            nonlocal found\n            found = True\n\n    f()\n    assert found\n\n\n@given(data(), datetimes(), datetimes())\ndef test_datetimes_stay_within_naive_bounds(data, lo, hi):\n    if lo > hi:\n        lo, hi = hi, lo\n    out = data.draw(datetimes(lo, hi, timezones=timezones()))\n    assert lo <= out.replace(tzinfo=None) <= hi\n\n\n@pytest.mark.parametrize(\n    \"kw\",\n    [\n        # Ireland uses  *negative* offset DST, which means that our sloppy interpretation\n        # of \"is_dst=not fold\" bypasses the filter for imaginary times.  This is basically\n        # unfixable without redesigning pytz per PEP-495, and it's much more likely to be\n        # replaced by dateutil or PEP-615 zoneinfo in the standard library instead.\n        {\n            \"min_value\": dt.datetime(2019, 3, 31),\n            \"max_value\": dt.datetime(2019, 4, 1),\n            \"timezones\": just(pytz.timezone(\"Europe/Dublin\")),\n        },\n        # The day of a spring-forward transition in Australia; 2am is imaginary\n        # (the common case so an optimistic `is_dst=bool(fold)` also fails the test)\n        {\n            \"min_value\": dt.datetime(2020, 10, 4),\n            \"max_value\": dt.datetime(2020, 10, 5),\n            \"timezones\": just(pytz.timezone(\"Australia/Sydney\")),\n        },\n    ],\n)\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)\ndef test_datetimes_can_exclude_imaginary(kw):\n    # Sanity check: fail unless those days contain an imaginary hour to filter out\n    find_any(datetimes(**kw, allow_imaginary=True), lambda x: not datetime_exists(x))\n\n    # Assert that with allow_imaginary=False we only generate existing datetimes.\n    assert_all_examples(datetimes(**kw, allow_imaginary=False), datetime_exists)\n\n\ndef test_really_weird_tzinfo_case():\n    x = dt.datetime(2019, 3, 31, 2, 30, tzinfo=pytz.timezone(\"Europe/Dublin\"))\n    assert x.tzinfo is not x.astimezone(dt.timezone.utc).astimezone(x.tzinfo)\n    # And that weird case exercises the rare branch in our helper:\n    assert datetime_does_not_exist(x)\n"
  },
  {
    "path": "hypothesis-python/tests/datetime/test_zoneinfo_timezones.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport platform\nimport zoneinfo\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import InvalidArgument\n\nfrom tests.common.debug import assert_no_examples, find_any, minimal\n\n\ndef test_utc_is_minimal():\n    assert minimal(st.timezones()) is zoneinfo.ZoneInfo(\"UTC\")\n\n\ndef test_can_generate_non_utc():\n    find_any(\n        st.datetimes(timezones=st.timezones()).filter(lambda d: d.tzinfo.key != \"UTC\")\n    )\n\n\n@given(st.data(), st.datetimes(), st.datetimes())\ndef test_datetimes_stay_within_naive_bounds(data, lo, hi):\n    if lo > hi:\n        lo, hi = hi, lo\n    out = data.draw(st.datetimes(lo, hi, timezones=st.timezones()))\n    assert lo <= out.replace(tzinfo=None) <= hi\n\n\n@pytest.mark.parametrize(\"kwargs\", [{\"no_cache\": 1}])\ndef test_timezones_argument_validation(kwargs):\n    with pytest.raises(InvalidArgument):\n        st.timezones(**kwargs).validate()\n\n\n@pytest.mark.parametrize(\n    \"kwargs\",\n    [\n        # {\"allow_alias\": 1},\n        # {\"allow_deprecated\": 1},\n        {\"allow_prefix\": 1},\n    ],\n)\ndef test_timezone_keys_argument_validation(kwargs):\n    with pytest.raises(InvalidArgument):\n        st.timezone_keys(**kwargs).validate()\n\n\n@pytest.mark.xfail(strict=False, reason=\"newly failing on GitHub Actions\")\n@pytest.mark.skipif(platform.system() != \"Linux\", reason=\"platform-specific\")\ndef test_can_generate_prefixes_if_allowed_and_available():\n    \"\"\"\n    This is actually kinda fiddly: we may generate timezone keys with the\n    \"posix/\" or \"right/\" prefix if-and-only-if they are present on the filesystem.\n\n    This immediately rules out Windows (which uses the tzdata package instead),\n    along with OSX (which doesn't seem to have prefixed keys).  We believe that\n    they are present on at least most Linux distros, but have not done exhaustive\n    testing.\n\n    It's fine to just patch this test out if it fails - passing in the\n    Hypothesis CI demonstrates that the feature works on *some* systems.\n    \"\"\"\n    find_any(st.timezone_keys(), lambda s: s.startswith(\"posix/\"))\n    find_any(st.timezone_keys(), lambda s: s.startswith(\"right/\"))\n\n\ndef test_can_disallow_prefixes():\n    assert_no_examples(\n        st.timezone_keys(allow_prefix=False),\n        lambda s: s.startswith((\"posix/\", \"right/\")),\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/django/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/django/manage.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport sys\nimport warnings\n\nfrom hypothesis import HealthCheck, settings\n\nfrom tests.common.setup import run\n\nif __name__ == \"__main__\":\n    run()\n\n    settings.register_profile(\n        \"default\", settings(suppress_health_check=[HealthCheck.too_slow])\n    )\n\n    settings.load_profile(os.getenv(\"HYPOTHESIS_PROFILE\", \"default\"))\n\n    os.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"tests.django.toys.settings\")\n\n    # This triggers a deprecation warning on some older versions of Django\n    # because of its use of the imp module.\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", category=DeprecationWarning)\n        from django.core.management import execute_from_command_line\n\n    try:\n        from django.utils.deprecation import RemovedInDjango50Warning\n    except ImportError:\n        RemovedInDjango50Warning = ()\n\n    try:\n        from django.utils.deprecation import RemovedInDjango60Warning\n    except ImportError:\n        RemovedInDjango60Warning = ()\n\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", category=RemovedInDjango50Warning)\n        warnings.simplefilter(\"ignore\", category=RemovedInDjango60Warning)\n        execute_from_command_line(sys.argv)\n"
  },
  {
    "path": "hypothesis-python/tests/django/toys/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/django/toys/settings/no_urls.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nurlpatterns = []\n"
  },
  {
    "path": "hypothesis-python/tests/django/toys/settings/settings.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"Django settings for toys project.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/1.7/topics/settings/\n\nFor the full list of settings and their values, see\nhttps://docs.djangoproject.com/en/1.7/ref/settings/\n\"\"\"\n\nimport os\n\nimport django\n\n# Build paths inside the project like this: os.path.join(BASE_DIR, ...)\nBASE_DIR = os.path.dirname(os.path.dirname(__file__))\n\n\n# Quick-start development settings - unsuitable for production\n# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/\n\n# SECURITY WARNING: keep the secret key used in production secret!\nSECRET_KEY = \"o0zlv@74u4e3s+o0^h$+tlalh&$r(7hbx01g4^h5-3gizj%hub\"\n\n# SECURITY WARNING: don't run with debug turned on in production!\nDEBUG = True\n\nTEMPLATE_DEBUG = True\n\nALLOWED_HOSTS = []\n\n\n# Application definition\n\nINSTALLED_APPS = (\n    \"django.contrib.admin\",\n    \"django.contrib.auth\",\n    \"django.contrib.contenttypes\",\n    \"django.contrib.sessions\",\n    \"django.contrib.messages\",\n    \"django.contrib.staticfiles\",\n    \"tests.django.toystore\",\n)\n\nMIDDLEWARE_CLASSES = (\n    \"django.contrib.sessions.middleware.SessionMiddleware\",\n    \"django.middleware.common.CommonMiddleware\",\n    \"django.middleware.csrf.CsrfViewMiddleware\",\n    \"django.contrib.auth.middleware.AuthenticationMiddleware\",\n    \"django.contrib.auth.middleware.SessionAuthenticationMiddleware\",\n    \"django.contrib.messages.middleware.MessageMiddleware\",\n    \"django.middleware.clickjacking.XFrameOptionsMiddleware\",\n)\n\nROOT_URLCONF = \"tests.django.toys.settings.urls\"\n\nWSGI_APPLICATION = \"tests.django.toys.wsgi.application\"\n\nDEFAULT_AUTO_FIELD = \"django.db.models.AutoField\"\n\n\n# Database\n# https://docs.djangoproject.com/en/1.7/ref/settings/#databases\n\nDATABASES = {\n    \"default\": {\n        \"ENGINE\": \"django.db.backends.sqlite3\",\n        \"NAME\": os.path.join(BASE_DIR, \"db.sqlite3\"),\n    }\n}\n\n# Internationalization\n# https://docs.djangoproject.com/en/1.7/topics/i18n/\n\nLANGUAGE_CODE = \"en-us\"\n\nTIME_ZONE = \"UTC\"\n\nUSE_I18N = True\n\nif django.VERSION < (5, 0, 0):\n    USE_L10N = True\n\nUSE_TZ = os.environ.get(\"HYPOTHESIS_DJANGO_USETZ\", \"TRUE\") == \"TRUE\"\n\n\n# Static files (CSS, JavaScript, Images)\n# https://docs.djangoproject.com/en/1.7/howto/static-files/\n\nSTATIC_URL = \"/static/\"\n\n\n# Added these bits to avoid warnings on Django 2.2\n\nTEMPLATES = [\n    {\n        \"BACKEND\": \"django.template.backends.django.DjangoTemplates\",\n        \"OPTIONS\": {\n            \"context_processors\": [\n                \"django.template.context_processors.debug\",\n                \"django.template.context_processors.request\",\n                \"django.contrib.auth.context_processors.auth\",\n                \"django.contrib.messages.context_processors.messages\",\n            ]\n        },\n    }\n]\n\nMIDDLEWARE = [\n    \"django.middleware.security.SecurityMiddleware\",\n    \"django.contrib.sessions.middleware.SessionMiddleware\",\n    \"django.middleware.common.CommonMiddleware\",\n    \"django.middleware.csrf.CsrfViewMiddleware\",\n    \"django.contrib.auth.middleware.AuthenticationMiddleware\",\n    \"django.contrib.messages.middleware.MessageMiddleware\",\n    \"django.middleware.clickjacking.XFrameOptionsMiddleware\",\n]\n\n# Transitional setting until 6.0. See\n# https://docs.djangoproject.com/en/5.0/ref/forms/fields/#django.forms.URLField.assume_scheme\nFORMS_URLFIELD_ASSUME_HTTPS = True\n"
  },
  {
    "path": "hypothesis-python/tests/django/toys/settings/settings_no_contrib.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom .settings import *  # noqa: F403\n\n# We test django in two contexts: with some default django.contrib apps installed\n# (which is settings.py), and with no django.contrib apps installed (which is this\n# file). We set DJANGO_SETTINGS_MODULE in tox to select which settings file we\n# use during testing.\n\nINSTALLED_APPS = [\"tests.django.toystore\"]\nROOT_URLCONF = \"tests.django.toys.settings.no_urls\"\n"
  },
  {
    "path": "hypothesis-python/tests/django/toys/settings/urls.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom django.contrib import admin\nfrom django.urls import include, re_path\n\npatterns, namespace, name = admin.site.urls\n\nurlpatterns = [\n    # Examples:\n    # url(r'^$', 'toys.views.home', name='home'),\n    # url(r'^blog/', include('blog.urls')),\n    re_path(r\"^admin/\", include((patterns, name), namespace=namespace))\n]\n"
  },
  {
    "path": "hypothesis-python/tests/django/toys/wsgi.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"WSGI config for toys project.\n\nIt exposes the WSGI callable as a module-level variable named ``application``.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/\n\"\"\"\n\nimport os\n\nfrom django.core.wsgi import get_wsgi_application\n\nos.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"toys.settings\")\n\napplication = get_wsgi_application()\n"
  },
  {
    "path": "hypothesis-python/tests/django/toystore/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/django/toystore/admin.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/django/toystore/forms.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom django import forms\nfrom django.conf import settings\nfrom django.core.validators import (\n    MaxLengthValidator,\n    MaxValueValidator,\n    MinLengthValidator,\n    MinValueValidator,\n)\nfrom django.forms import widgets\n\nfrom tests.django.toystore.models import (\n    Company,\n    CouldBeCharming,\n    Customer,\n    FileFields,\n    ManyNumerics,\n    ManyTimes,\n    OddFields,\n    Store,\n)\n\nif \"django.contrib.auth\" in settings.INSTALLED_APPS:\n    from django.contrib.auth.forms import ReadOnlyPasswordHashField, UsernameField\n\n\nclass ReprModelForm(forms.ModelForm):\n    def __repr__(self):\n        \"\"\"I recommend putting this in your form to show the failed cases.\"\"\"\n        return f\"{self.data!r}\\n{self.errors!r}\"\n\n\nclass ReprForm(forms.Form):\n    def __repr__(self):\n        return f\"{self.data!r}\\n{self.errors!r}\"\n\n\nclass CouldBeCharmingForm(ReprModelForm):\n    class Meta:\n        model = CouldBeCharming\n        fields = \"__all__\"\n\n\nclass FileFieldsForm(ReprModelForm):\n    class Meta:\n        model = FileFields\n        fields = \"__all__\"\n\n\nclass CustomerForm(ReprModelForm):\n    class Meta:\n        model = Customer\n        fields = \"__all__\"\n\n\nclass ManyNumericsForm(ReprModelForm):\n    class Meta:\n        model = ManyNumerics\n        fields = \"__all__\"\n\n\nclass ManyTimesForm(ReprModelForm):\n    class Meta:\n        model = ManyTimes\n        fields = \"__all__\"\n\n\nclass OddFieldsForm(ReprModelForm):\n    class Meta:\n        model = OddFields\n        fields = \"__all__\"\n\n\nclass DynamicForm(ReprForm):\n    def __init__(self, field_count=5, **kwargs):\n        super().__init__(**kwargs)\n        for i in range(field_count):\n            field_name = f\"field-{i}\"\n            self.fields[field_name] = forms.CharField(required=False)\n\n\nclass BasicFieldForm(ReprForm):\n    _boolean_required = forms.BooleanField()\n    _boolean = forms.BooleanField(required=False)\n    # This took me too long to figure out... The BooleanField will actually\n    # raise a ValidationError when it receives a value of False. Why they\n    # didn't call it a TrueOnlyField escapes me, but *if* you actually want\n    # to accept both True and False in your BooleanField, make sure you set\n    # `required=False`. This behavior has been hotly contested in the bug\n    # tracker (e.g. https://code.djangoproject.com/ticket/23547), but it\n    # seems that since the tests and documentation are already written\n    # this behavior is Truth.\n    # see the note in the documentation\n    # https://docs.djangoproject.com/en/dev/ref/forms/fields/#booleanfield\n\n    _char_required = forms.CharField(required=True)\n    _char = forms.CharField(required=False)\n    _decimal = forms.DecimalField(max_digits=8, decimal_places=3)\n    _float = forms.FloatField()\n    _integer = forms.IntegerField()\n    _null_boolean = forms.NullBooleanField()\n\n\nclass TemporalFieldForm(ReprForm):\n    _date = forms.DateField()\n    _date_time = forms.DateTimeField()\n    _duration = forms.DurationField()\n    _time = forms.TimeField()\n    _split_date_time = forms.SplitDateTimeField()\n\n\nclass WithValidatorsForm(ReprForm):\n    num_validators = (MinValueValidator(1), MaxValueValidator(5))\n    _int_one_to_five = forms.IntegerField(validators=num_validators)\n    _decimal_one_to_five = forms.FloatField(validators=num_validators)\n    _float_one_to_five = forms.FloatField(validators=num_validators)\n    len_validators = (MinLengthValidator(5), MaxLengthValidator(10))\n    _string_five_to_ten = forms.CharField(validators=len_validators)\n\n\nclass EmailFieldForm(ReprForm):\n    _email = forms.EmailField()\n\n\nclass SlugFieldForm(ReprForm):\n    _slug = forms.SlugField()\n\n\nclass URLFieldForm(ReprForm):\n    _url = forms.URLField()\n\n\nclass RegexFieldForm(ReprForm):\n    _regex = forms.RegexField(regex=\"[A-Z]{3}\\\\.[a-z]{4}\")\n\n\nclass UUIDFieldForm(ReprForm):\n    _uuid = forms.UUIDField()\n\n\nclass ChoiceFieldForm(ReprForm):\n    _choice = forms.ChoiceField(\n        choices=((\"cola\", \"Cola\"), (\"tea\", \"Tea\"), (\"water\", \"Water\"))\n    )\n    _multiple = forms.MultipleChoiceField(\n        choices=((\"cola\", \"Cola\"), (\"tea\", \"Tea\"), (\"water\", \"Water\"))\n    )\n    _typed = forms.TypedChoiceField(\n        choices=((\"1\", \"one\"), (\"2\", \"two\"), (\"3\", \"three\"), (\"4\", \"four\")),\n        coerce=int,\n        empty_value=0,\n    )\n    _typed_multiple = forms.TypedMultipleChoiceField(\n        choices=((\"1\", \"one\"), (\"2\", \"two\"), (\"3\", \"three\"), (\"4\", \"four\")),\n        coerce=int,\n        empty_value=0,\n    )\n\n\nclass InternetProtocolForm(ReprForm):\n    _ip_both = forms.GenericIPAddressField()\n    _ip_v4 = forms.GenericIPAddressField(protocol=\"IPv4\")\n    _ip_v6 = forms.GenericIPAddressField(protocol=\"IPv6\")\n\n\nclass BroadBooleanInput(widgets.CheckboxInput):\n    \"\"\"Basically pulled directly from the Django CheckboxInput. I added\n    some stuff to ``values``\n    \"\"\"\n\n    def value_from_datadict(self, data, files, name):\n        if name not in data:\n            return False\n        value = data.get(name)\n        # Translate true and false strings to boolean values.\n        values = {\"true\": True, \"false\": False, \"0\": False, \"1\": True}\n        if isinstance(value, str):\n            value = values.get(value.lower(), value)\n        return bool(value)\n\n\nclass MultiCheckboxWidget(widgets.MultiWidget):\n    def __init__(self, subfield_count=12, **kwargs):\n        _widgets = [BroadBooleanInput()] * subfield_count\n        super().__init__(_widgets, **kwargs)\n\n    def decompress(self, value):\n        values = []\n        for _value in value.split(\"::\"):\n            if _value in (\"0\", \"\", \"False\", 0, None, False):\n                values.append(False)\n            else:\n                values.append(True)\n        return values\n\n\nclass BroadBooleanField(forms.BooleanField):\n    pass\n\n\nclass MultiBooleanField(forms.MultiValueField):\n    def __init__(self, subfield_count=12, **kwargs):\n        subfields = [BroadBooleanField()] * subfield_count\n        widget = MultiCheckboxWidget(subfield_count=subfield_count)\n        super().__init__(fields=subfields, widget=widget)\n\n    def compress(self, values):\n        return \"::\".join(str(x) for x in values)\n\n\nclass ManyMultiValueForm(ReprForm):\n    def __init__(self, subfield_count=12, **kwargs):\n        super().__init__(**kwargs)\n        self.fields[\"mv_field\"] = MultiBooleanField(subfield_count=subfield_count)\n\n\nclass ShortStringForm(ReprForm):\n    _not_too_long = forms.CharField(max_length=20, required=False)\n\n\nif \"django.contrib.auth\" in settings.INSTALLED_APPS:\n\n    class UsernameForm(ReprForm):\n        username = UsernameField()\n\n    class ReadOnlyPasswordHashFieldForm(ReprForm):\n        password = ReadOnlyPasswordHashField()\n\nelse:\n    UsernameForm = None\n    ReadOnlyPasswordHashFieldForm = None\n\n\nclass StoreForm(ReprModelForm):\n    company = forms.ModelChoiceField(queryset=Company.objects.order_by(\"name\"))\n\n    class Meta:\n        model = Store\n        fields = \"__all__\"\n\n\nclass MultipleCompaniesForm(ReprForm):\n    companies = forms.ModelMultipleChoiceField(\n        queryset=Company.objects.order_by(\"name\")\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/django/toystore/models.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport django\nfrom django.core.exceptions import ValidationError\nfrom django.core.validators import MinValueValidator\nfrom django.db import models\n\n\nclass Company(models.Model):\n    name = models.CharField(max_length=100, unique=True)\n\n\nclass Store(models.Model):\n    name = models.CharField(max_length=100, unique=True)\n    company = models.ForeignKey(Company, null=False, on_delete=models.CASCADE)\n\n\nclass Car(models.Model):\n    # See https://github.com/HypothesisWorks/hypothesis/issues/2369\n    model = models.CharField(max_length=100, unique=True)\n\n\nclass CharmField(models.Field):\n    def db_type(self, connection):\n        return \"char(1)\"\n\n\nclass CustomishField(models.Field):\n    def db_type(self, connection):\n        return \"char(1)\"\n\n\nclass Customish(models.Model):\n    customish = CustomishField()\n\n\nclass Customer(models.Model):\n    name = models.CharField(max_length=100, unique=True)\n    email = models.EmailField(max_length=100, unique=True)\n    gender = models.CharField(max_length=50, null=True)  # noqa  # avoid nullable strs\n    age = models.IntegerField()\n    birthday = models.DateTimeField()\n\n\nclass Charming(models.Model):\n    charm = CharmField()\n\n\nclass CouldBeCharming(models.Model):\n    charm = CharmField(null=True)\n\n\nclass SelfLoop(models.Model):\n    me = models.ForeignKey(\"self\", null=True, on_delete=models.SET_NULL)\n\n\nclass LoopA(models.Model):\n    b = models.ForeignKey(\"LoopB\", null=False, on_delete=models.CASCADE)\n\n\nclass LoopB(models.Model):\n    a = models.ForeignKey(\"LoopA\", null=True, on_delete=models.SET_NULL)\n\n\nclass ManyNumerics(models.Model):\n    i1 = models.IntegerField()\n    i2 = models.SmallIntegerField()\n    i3 = models.BigIntegerField()\n\n    p1 = models.PositiveIntegerField()\n    p2 = models.PositiveSmallIntegerField()\n\n    d = models.DecimalField(decimal_places=2, max_digits=5)\n\n\nclass ManyTimes(models.Model):\n    time = models.TimeField()\n    date = models.DateField()\n    duration = models.DurationField()\n\n\nclass OddFields(models.Model):\n    uuid = models.UUIDField()\n    slug = models.SlugField()\n    url = models.URLField()\n    ipv4 = models.GenericIPAddressField(protocol=\"IPv4\")\n    ipv6 = models.GenericIPAddressField(protocol=\"IPv6\")\n\n\nclass CustomishDefault(models.Model):\n    customish = CustomishField(default=\"b\")\n\n\nclass FileFields(models.Model):\n    file1 = models.FileField()\n\n\nclass MandatoryComputed(models.Model):\n    name = models.CharField(max_length=100, unique=True)\n    company = models.ForeignKey(Company, null=False, on_delete=models.CASCADE)\n\n    def __init__(self, **kw):\n        if \"company\" in kw:\n            raise RuntimeError\n        cname = kw[\"name\"] + \"_company\"\n        kw[\"company\"] = Company.objects.create(name=cname)\n        super().__init__(**kw)\n\n\ndef validate_even(value):\n    if value % 2 != 0:\n        raise ValidationError(\"\")\n\n\nclass RestrictedFields(models.Model):\n    text_field_4 = models.TextField(max_length=4, blank=True)\n    char_field_4 = models.CharField(max_length=4, blank=True)\n    choice_field_text = models.TextField(choices=((\"foo\", \"Foo\"), (\"bar\", \"Bar\")))\n    choice_field_int = models.IntegerField(choices=((1, \"First\"), (2, \"Second\")))\n    null_choice_field_int = models.IntegerField(\n        choices=((1, \"First\"), (2, \"Second\")), null=True, blank=True\n    )\n    choice_field_grouped = models.TextField(\n        choices=(\n            (\"Audio\", ((\"vinyl\", \"Vinyl\"), (\"cd\", \"CD\"))),\n            (\"Video\", ((\"vhs\", \"VHS Tape\"), (\"dvd\", \"DVD\"))),\n            (\"unknown\", \"Unknown\"),\n        )\n    )\n    even_number_field = models.IntegerField(validators=[validate_even])\n    non_blank_text_field = models.TextField(blank=False)\n\n\nclass SelfModifyingField(models.IntegerField):\n    def pre_save(self, model_instance, add):\n        value = getattr(model_instance, self.attname)\n        value += 1\n        setattr(model_instance, self.attname, value)\n        return value\n\n\nclass CompanyExtension(models.Model):\n    company = models.OneToOneField(Company, primary_key=True, on_delete=models.CASCADE)\n\n    self_modifying = SelfModifyingField()\n\n\nclass UserSpecifiedAutoId(models.Model):\n    my_id = models.AutoField(primary_key=True)\n\n\nif django.VERSION >= (5, 0, 0):\n    import math\n\n    class Pizza(models.Model):\n        AREA = math.pi * models.F(\"radius\") ** 2\n\n        radius = models.IntegerField(validators=[MinValueValidator(1)])\n        slices = models.PositiveIntegerField(validators=[MinValueValidator(2)])\n        total_area = models.GeneratedField(\n            expression=AREA,\n            output_field=models.FloatField(),\n            db_persist=True,\n        )\n        slice_area = models.GeneratedField(\n            expression=AREA / models.F(\"slices\"),\n            output_field=models.FloatField(),\n            db_persist=False,\n        )\n"
  },
  {
    "path": "hypothesis-python/tests/django/toystore/test_basic_configuration.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom unittest import TestCase as VanillaTestCase\n\nimport pytest\nfrom django.db import IntegrityError\nfrom django.test import TestCase as DjangoTestCase\n\nfrom hypothesis import HealthCheck, Verbosity, given, settings\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra.django import SimpleTestCase, TestCase, TransactionTestCase\nfrom hypothesis.internal.compat import GRAALPY, PYPY\nfrom hypothesis.strategies import integers\n\nfrom tests.django.toystore.models import Company\n\n\nclass SomeStuff:\n    @settings(\n        suppress_health_check=[HealthCheck.too_slow, HealthCheck.differing_executors]\n    )\n    @given(integers())\n    def test_is_blank_slate(self, unused):\n        Company.objects.create(name=\"MickeyCo\")\n\n    def test_normal_test_1(self):\n        Company.objects.create(name=\"MickeyCo\")\n\n    def test_normal_test_2(self):\n        Company.objects.create(name=\"MickeyCo\")\n\n\nclass TestConstraintsWithTransactions(SomeStuff, TestCase):\n    pass\n\n\nif not (PYPY or GRAALPY):\n    # xfail\n    # This is excessively slow in general, but particularly on pypy. We just\n    # disable it altogether there as it's a niche case.\n    class TestConstraintsWithoutTransactions(SomeStuff, TransactionTestCase):\n        pass\n\n\nclass TestWorkflow(VanillaTestCase):\n    def test_does_not_break_later_tests(self):\n        def break_the_db(i):\n            Company.objects.create(name=\"MickeyCo\")\n            Company.objects.create(name=\"MickeyCo\")\n\n        class LocalTest(TestCase):\n            @given(integers().map(break_the_db))\n            @settings(\n                suppress_health_check=list(HealthCheck), verbosity=Verbosity.quiet\n            )\n            def test_does_not_break_other_things(self, unused):\n                pass\n\n            def test_normal_test_1(self):\n                Company.objects.create(name=\"MickeyCo\")\n\n        t = LocalTest(\"test_normal_test_1\")\n        try:\n            t.test_does_not_break_other_things()\n        except IntegrityError:\n            pass\n        t.test_normal_test_1()\n\n    def test_given_needs_hypothesis_test_case(self):\n        class LocalTest(DjangoTestCase):\n            @given(integers())\n            def tst(self, i):\n                raise AssertionError(\"InvalidArgument should be raised in @given\")\n\n        with pytest.raises(InvalidArgument):\n            LocalTest(\"tst\").tst()\n\n\nclass TestSimple(SimpleTestCase):\n    @given(integers())\n    def test_that_doesnt_need_db(self, z: int):\n        company = Company(name=\"Company-\" + str(z))\n        assert company.name.endswith(str(z))\n"
  },
  {
    "path": "hypothesis-python/tests/django/toystore/test_given_forms.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom unittest import skipIf\n\nfrom django import forms\nfrom django.conf import settings\n\nfrom hypothesis import assume, given\nfrom hypothesis.extra.django import (\n    TestCase,\n    from_field,\n    from_form,\n    register_field_strategy,\n)\nfrom hypothesis.strategies import booleans, sampled_from\n\nfrom tests.django.toystore.forms import (\n    BasicFieldForm,\n    BroadBooleanField,\n    ChoiceFieldForm,\n    CustomerForm,\n    DynamicForm,\n    EmailFieldForm,\n    FileFieldsForm,\n    InternetProtocolForm,\n    ManyMultiValueForm,\n    ManyNumericsForm,\n    ManyTimesForm,\n    MultipleCompaniesForm,\n    OddFieldsForm,\n    RegexFieldForm,\n    ShortStringForm,\n    SlugFieldForm,\n    StoreForm,\n    TemporalFieldForm,\n    URLFieldForm,\n    UsernameForm,\n    UUIDFieldForm,\n    WithValidatorsForm,\n)\nfrom tests.django.toystore.models import Company\n\nregister_field_strategy(\n    BroadBooleanField, booleans() | sampled_from([\"1\", \"0\", \"True\", \"False\"])\n)\n\nhas_contrib_auth = \"django.contrib.auth\" in settings.INSTALLED_APPS\n\n\nclass TestGetsBasicForms(TestCase):\n    @given(from_form(CustomerForm))\n    def test_valid_customer(self, customer_form):\n        self.assertTrue(customer_form.is_valid())\n\n    @given(from_form(ManyNumericsForm))\n    def test_valid_numerics(self, numerics_form):\n        self.assertTrue(numerics_form.is_valid())\n\n    @given(from_form(ManyTimesForm))\n    def test_valid_times(self, times_form):\n        self.assertTrue(times_form.is_valid())\n\n    @given(from_form(OddFieldsForm))\n    def test_valid_odd_fields(self, odd_form):\n        self.assertTrue(odd_form.is_valid())\n\n    def test_dynamic_form(self):\n        for field_count in range(2, 7):\n\n            @given(from_form(DynamicForm, form_kwargs={\"field_count\": field_count}))\n            def _test(dynamic_form):\n                self.assertTrue(dynamic_form.is_valid())\n\n            _test()\n\n    @given(from_form(BasicFieldForm))\n    def test_basic_fields_form(self, basic_field_form):\n        self.assertTrue(basic_field_form.is_valid())\n\n    @given(from_form(TemporalFieldForm))\n    def test_temporal_fields_form(self, time_field_form):\n        self.assertTrue(time_field_form.is_valid())\n\n    @given(from_form(EmailFieldForm))\n    def test_email_field_form(self, email_field_form):\n        self.assertTrue(email_field_form.is_valid())\n\n    @given(from_form(SlugFieldForm))\n    def test_slug_field_form(self, slug_field_form):\n        self.assertTrue(slug_field_form.is_valid())\n\n    @given(from_form(URLFieldForm))\n    def test_url_field_form(self, url_field_form):\n        self.assertTrue(url_field_form.is_valid())\n\n    @given(from_form(RegexFieldForm))\n    def test_regex_field_form(self, regex_field_form):\n        self.assertTrue(regex_field_form.is_valid())\n\n    @given(from_form(UUIDFieldForm))\n    def test_uuid_field_form(self, uuid_field_form):\n        self.assertTrue(uuid_field_form.is_valid())\n\n    @given(from_form(ChoiceFieldForm))\n    def test_choice_fields_form(self, choice_field_form):\n        self.assertTrue(choice_field_form.is_valid())\n\n    @given(from_form(InternetProtocolForm))\n    def test_ip_fields_form(self, ip_field_form):\n        self.assertTrue(ip_field_form.is_valid())\n\n    @given(from_form(ManyMultiValueForm, form_kwargs={\"subfield_count\": 2}))\n    def test_many_values_in_multi_value_field(self, many_multi_value_form):\n        self.assertTrue(many_multi_value_form.is_valid())\n\n    @given(from_form(ManyMultiValueForm, form_kwargs={\"subfield_count\": 105}))\n    def test_excessive_values_in_multi_value_field(self, excessive_form):\n        self.assertTrue(excessive_form.is_valid())\n\n    @given(from_form(ShortStringForm))\n    def test_short_string_form(self, short_string_form):\n        self.assertTrue(short_string_form.is_valid())\n\n    @given(from_form(WithValidatorsForm))\n    def test_tight_validators_form(self, x):\n        self.assertTrue(1 <= x.data[\"_int_one_to_five\"] <= 5)\n        self.assertTrue(1 <= x.data[\"_decimal_one_to_five\"] <= 5)\n        self.assertTrue(1 <= x.data[\"_float_one_to_five\"] <= 5)\n        self.assertTrue(5 <= len(x.data[\"_string_five_to_ten\"]) <= 10)\n\n    @given(from_form(FileFieldsForm))\n    def test_file_fields_form(self, x):\n        assert x.is_valid()\n        # form.data is empty, and form.files has one entry: file1\n        self.assertFalse(x.data)\n        self.assertTrue(set(x.files.keys()) == {\"file1\"})\n        self.assertTrue(x.files[\"file1\"])\n\n    @skipIf(not has_contrib_auth, \"contrib.auth not installed\")\n    @given(from_form(UsernameForm))\n    def test_username_form(self, username_form):\n        self.assertTrue(username_form.is_valid())\n\n    @skipIf(not has_contrib_auth, \"contrib.auth not installed\")\n    @given(from_form(UsernameForm))\n    def test_read_only_password_hash_field_form(self, password_form):\n        self.assertTrue(password_form.is_valid())\n\n\nclass TestFormsWithModelChoices(TestCase):\n    @classmethod\n    def setUpTestData(cls):\n        super().setUpTestData()\n\n        # Set up example Company records to use as choices for\n        # Store.company. These must exist before creating a strategy\n        # for the ModelChoiceField.\n        cls.company_names = (\"Bill's Flowers\", \"Jane's Sporting Goods\")\n        for name in cls.company_names:\n            Company.objects.create(name=name)\n\n    @given(\n        choice=from_field(\n            forms.ModelChoiceField(queryset=Company.objects.order_by(\"name\"))\n        )\n    )\n    def test_from_model_choices_field(self, choice):\n        assume(choice != \"\")  # Skip the empty choice.\n        self.assertIsInstance(choice, int)\n        Company.objects.get(id=choice)\n\n    @given(\n        choice=from_field(\n            forms.ModelChoiceField(\n                queryset=Company.objects.order_by(\"name\"), empty_label=None\n            )\n        )\n    )\n    def test_from_model_choices_field_no_empty_choice(self, choice):\n        Company.objects.get(id=choice)\n\n    @given(choice=from_field(forms.ModelChoiceField(queryset=Company.objects.none())))\n    def test_from_model_choices_field_empty(self, choice):\n        self.assertEqual(choice, \"\")\n\n    @given(form=from_form(StoreForm))\n    def test_store_form_valid(self, form):\n        assume(form.data[\"company\"])\n        self.assertTrue(form.is_valid())\n\n    @given(\n        choice=from_field(\n            forms.ModelMultipleChoiceField(queryset=Company.objects.order_by(\"name\"))\n        )\n    )\n    def test_from_model_multiple_choices_field(self, choice):\n        n_choices = len(choice)\n        self.assertEqual(n_choices, len(set(choice)))\n        self.assertEqual(n_choices, Company.objects.filter(pk__in=choice).count())\n\n    @given(form=from_form(MultipleCompaniesForm))\n    def test_multiple_companies_form_valid(self, form):\n        self.assertTrue(form.is_valid())\n"
  },
  {
    "path": "hypothesis-python/tests/django/toystore/test_given_models.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport datetime as dt\nfrom unittest import skipIf\nfrom uuid import UUID\n\nimport django\nfrom django.conf import settings as django_settings\n\nfrom hypothesis import HealthCheck, assume, given, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra.django import (\n    TestCase,\n    TransactionTestCase,\n    from_model,\n    register_field_strategy,\n)\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.strategies import just, lists\n\nif \"django.contrib.auth\" in django_settings.INSTALLED_APPS:\n    from django.contrib.auth.models import User\nelse:\n    User = None\n\nfrom tests.common.debug import check_can_generate_examples\nfrom tests.django.toystore.models import (\n    Car,\n    Company,\n    CompanyExtension,\n    CouldBeCharming,\n    Customer,\n    Customish,\n    CustomishDefault,\n    CustomishField,\n    MandatoryComputed,\n    ManyNumerics,\n    ManyTimes,\n    OddFields,\n    RestrictedFields,\n    SelfLoop,\n    Store,\n    UserSpecifiedAutoId,\n)\n\nregister_field_strategy(CustomishField, just(\"a\"))\n\n\nclass TestGetsBasicModels(TestCase):\n    @given(from_model(Company))\n    def test_is_company(self, company):\n        self.assertIsInstance(company, Company)\n        self.assertIsNotNone(company.pk)\n\n    @given(from_model(Store, company=from_model(Company)))\n    def test_can_get_a_store(self, store):\n        assert store.company.pk\n\n    @given(lists(from_model(Company)))\n    def test_can_get_multiple_models_with_unique_field(self, companies):\n        assume(len(companies) > 1)\n        for c in companies:\n            self.assertIsNotNone(c.pk)\n        self.assertEqual(\n            len({c.pk for c in companies}), len({c.name for c in companies})\n        )\n\n    @settings(suppress_health_check=[HealthCheck.too_slow])\n    @given(from_model(Customer))\n    def test_is_customer(self, customer):\n        self.assertIsInstance(customer, Customer)\n        self.assertIsNotNone(customer.pk)\n        self.assertIsNotNone(customer.email)\n\n    @settings(suppress_health_check=[HealthCheck.too_slow])\n    @given(from_model(Customer))\n    def test_tz_presence(self, customer):\n        if django_settings.USE_TZ:\n            self.assertIsNotNone(customer.birthday.tzinfo)\n        else:\n            self.assertIsNone(customer.birthday.tzinfo)\n\n    @given(from_model(CouldBeCharming))\n    def test_is_not_charming(self, not_charming):\n        self.assertIsInstance(not_charming, CouldBeCharming)\n        self.assertIsNotNone(not_charming.pk)\n        self.assertIsNone(not_charming.charm)\n\n    @given(from_model(SelfLoop))\n    def test_sl(self, sl):\n        self.assertIsNone(sl.me)\n\n    @given(lists(from_model(ManyNumerics)))\n    def test_no_overflow_in_integer(self, manyints):\n        pass\n\n    @given(from_model(Customish))\n    def test_custom_field(self, x):\n        assert x.customish == \"a\"\n\n    def test_mandatory_fields_are_mandatory(self):\n        with self.assertRaises(InvalidArgument):\n            check_can_generate_examples(from_model(Store))\n\n    def test_mandatory_computed_fields_are_mandatory(self):\n        with self.assertRaises(InvalidArgument):\n            check_can_generate_examples(from_model(MandatoryComputed))\n\n    def test_mandatory_computed_fields_may_not_be_provided(self):\n        with self.assertRaises(RuntimeError):\n            check_can_generate_examples(\n                from_model(MandatoryComputed, company=from_model(Company))\n            )\n\n    @given(from_model(CustomishDefault, customish=...))\n    def test_customish_default_overridden_by_infer(self, x):\n        assert x.customish == \"a\"\n\n    @given(from_model(CustomishDefault, customish=...))\n    def test_customish_infer_uses_registered_instead_of_default(self, x):\n        assert x.customish == \"a\"\n\n    @given(from_model(OddFields))\n    def test_odd_fields(self, x):\n        assert isinstance(x.uuid, UUID)\n        assert isinstance(x.slug, str)\n        assert \" \" not in x.slug\n        assert isinstance(x.ipv4, str)\n        assert len(x.ipv4.split(\".\")) == 4\n        assert all(int(i) in range(256) for i in x.ipv4.split(\".\"))\n        assert isinstance(x.ipv6, str)\n        assert set(x.ipv6).issubset(set(\"0123456789abcdefABCDEF:.\"))\n\n    @given(from_model(ManyTimes))\n    def test_time_fields(self, x):\n        assert isinstance(x.time, dt.time)\n        assert isinstance(x.date, dt.date)\n        assert isinstance(x.duration, dt.timedelta)\n\n    @given(from_model(Company))\n    def test_no_null_in_charfield(self, x):\n        # regression test for #1045.  Company just has a convenient CharField.\n        assert \"\\x00\" not in x.name\n\n    @given(st.data())\n    def test_foreign_key_primary(self, data):\n        # Regression test for #1307\n        company_strategy = from_model(Company, name=just(\"test\"))\n        strategy = from_model(\n            CompanyExtension, company=company_strategy, self_modifying=just(2)\n        )\n        data.draw(strategy)\n\n        # Draw again with the same choice sequence. This will cause a duplicate\n        # primary key.\n        d = ConjectureData.for_choices(data.conjecture_data.choices)\n        d.draw(strategy)\n        assert CompanyExtension.objects.all().count() == 1\n\n\nclass TestsNeedingRollback(TransactionTestCase):\n    def test_can_get_examples(self):\n        for _ in range(200):\n            check_can_generate_examples(from_model(Company))\n\n\nclass TestRestrictedFields(TestCase):\n    @given(from_model(RestrictedFields))\n    def test_constructs_valid_instance(self, instance):\n        self.assertIsInstance(instance, RestrictedFields)\n        instance.full_clean()\n        self.assertLessEqual(len(instance.text_field_4), 4)\n        self.assertLessEqual(len(instance.char_field_4), 4)\n        self.assertIn(instance.choice_field_text, (\"foo\", \"bar\"))\n        self.assertIn(instance.choice_field_int, (1, 2))\n        self.assertIn(instance.null_choice_field_int, (1, 2, None))\n        self.assertEqual(\n            instance.choice_field_grouped, instance.choice_field_grouped.lower()\n        )\n        self.assertEqual(instance.even_number_field % 2, 0)\n        self.assertTrue(instance.non_blank_text_field)\n\n\n@skipIf(User is None, \"contrib.auth not installed\")\nclass TestValidatorInference(TestCase):\n    @given(from_model(User))\n    def test_user_issue_1112_regression(self, user):\n        assert user.username\n\n\nclass TestPosOnlyArg(TestCase):\n    @given(from_model(Car))\n    def test_user_issue_2369_regression(self, val):\n        pass\n\n    def test_from_model_signature(self):\n        self.assertRaises(TypeError, from_model)\n        self.assertRaises(TypeError, from_model, Car, None)\n        self.assertRaises(TypeError, from_model, model=Customer)\n\n\nclass TestUserSpecifiedAutoId(TestCase):\n    @given(from_model(UserSpecifiedAutoId))\n    def test_user_specified_auto_id(self, user_specified_auto_id):\n        self.assertIsInstance(user_specified_auto_id, UserSpecifiedAutoId)\n        self.assertIsNotNone(user_specified_auto_id.pk)\n\n\nif django.VERSION >= (5, 0, 0):\n    from tests.django.toystore.models import Pizza\n\n    class TestModelWithGeneratedField(TestCase):\n        @given(from_model(Pizza))\n        def test_create_pizza(self, pizza):\n            \"\"\"\n            Strategies are not inferred for GeneratedField.\n            \"\"\"\n\n            # Check we generate valid objects.\n            pizza.full_clean()\n\n            # Refresh the instance from the database to make sure the\n            # generated fields are populated correctly.\n            pizza.refresh_from_db()\n\n            # Check the expected types of the generated fields.\n            self.assertIsInstance(pizza.slice_area, float)\n            self.assertIsInstance(pizza.total_area, float)\n"
  },
  {
    "path": "hypothesis-python/tests/django/toystore/views.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/dpcontracts/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/dpcontracts/test_contracts.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\nfrom dpcontracts import require\n\nfrom hypothesis import given\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra.dpcontracts import fulfill\nfrom hypothesis.internal.conjecture.utils import identity\nfrom hypothesis.strategies import builds, integers\n\n\n@require(\"division is undefined for zero\", lambda args: args.n != 0)\ndef invert(n):\n    return 1 / n\n\n\n@given(builds(fulfill(invert), integers()))\ndef test_contract_filter_builds(x):\n    assert -1 <= x <= 1\n\n\n@given(integers())\ndef test_contract_filter_inline(n):\n    assert -1 <= fulfill(invert)(n) <= 1\n\n\n@pytest.mark.parametrize(\"f\", [int, identity, lambda x: None])\ndef test_no_vacuous_fulfill(f):\n    with pytest.raises(InvalidArgument):\n        fulfill(f)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/example_code/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/example_code/future_annotations.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom __future__ import annotations\n\nimport collections.abc\n\n\nclass CustomClass:\n    def __init__(self, number: int) -> None:\n        self.number = number\n\n\ndef add_custom_classes(c1: CustomClass, c2: CustomClass | None = None) -> CustomClass:\n    if c2 is None:\n        return CustomClass(c1.number)\n    return CustomClass(c1.number + c2.number)\n\n\ndef merge_dicts(\n    map1: collections.abc.Mapping[str, int], map2: collections.abc.Mapping[str, int]\n) -> collections.abc.Mapping[str, int]:\n    return {**map1, **map2}\n\n\ndef invalid_types(attr1: int, attr2: UnknownClass, attr3: str) -> None:  # noqa: F821\n    pass\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/add_custom_classes.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport example_code.future_annotations\nimport typing\nfrom example_code.future_annotations import CustomClass\nfrom hypothesis import given, strategies as st\n\n\n@given(\n    c1=st.builds(CustomClass, number=st.integers()),\n    c2=st.one_of(st.none(), st.builds(CustomClass, number=st.integers())),\n)\ndef test_fuzz_add_custom_classes(\n    c1: example_code.future_annotations.CustomClass,\n    c2: typing.Union[example_code.future_annotations.CustomClass, None],\n) -> None:\n    example_code.future_annotations.add_custom_classes(c1=c1, c2=c2)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/addition_op_magic.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport test_expected_output\nfrom hypothesis import given, strategies as st\n\nadd_operands = st.floats()\n\n\n@given(a=add_operands, b=add_operands, c=add_operands)\ndef test_associative_binary_operation_add(a: float, b: float, c) -> None:\n    left = test_expected_output.add(a=a, b=test_expected_output.add(a=b, b=c))\n    right = test_expected_output.add(a=test_expected_output.add(a=a, b=b), b=c)\n    assert left == right, (left, right)\n\n\n@given(a=add_operands, b=add_operands)\ndef test_commutative_binary_operation_add(a: float, b: float) -> None:\n    left = test_expected_output.add(a=a, b=b)\n    right = test_expected_output.add(a=b, b=a)\n    assert left == right, (left, right)\n\n\n@given(a=add_operands)\ndef test_identity_binary_operation_add(a: float) -> None:\n    identity = 0.0\n    assert a == test_expected_output.add(a=a, b=identity)\n    assert a == test_expected_output.add(a=identity, b=a)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/addition_op_multimagic.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport numpy\nimport operator\nimport test_expected_output\nfrom hypothesis import given, strategies as st\n\n\n@given(a=st.floats(), b=st.floats())\ndef test_equivalent_add_add_add(a: float, b: float) -> None:\n    result_add_numpy = numpy.add(a, b)\n    result_add_operator = operator.add(a, b)\n    result_add_test_expected_output = test_expected_output.add(a=a, b=b)\n    assert result_add_numpy == result_add_operator, (\n        result_add_numpy,\n        result_add_operator,\n    )\n    assert result_add_numpy == result_add_test_expected_output, (\n        result_add_numpy,\n        result_add_test_expected_output,\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/base64_magic.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport base64\nfrom hypothesis import given, strategies as st\n\n# TODO: replace st.nothing() with appropriate strategies\n\n\n@given(\n    adobe=st.booleans(),\n    b=st.nothing(),\n    foldspaces=st.booleans(),\n    ignorechars=st.just(b\" \\t\\n\\r\\x0b\"),\n    pad=st.booleans(),\n    wrapcol=st.just(0),\n)\ndef test_roundtrip_a85encode_a85decode(adobe, b, foldspaces, ignorechars, pad, wrapcol):\n    value0 = base64.a85encode(\n        b=b, foldspaces=foldspaces, wrapcol=wrapcol, pad=pad, adobe=adobe\n    )\n    value1 = base64.a85decode(\n        b=value0, foldspaces=foldspaces, adobe=adobe, ignorechars=ignorechars\n    )\n    assert b == value1, (b, value1)\n\n\n@given(casefold=st.booleans(), s=st.nothing())\ndef test_roundtrip_b16encode_b16decode(casefold, s):\n    value0 = base64.b16encode(s=s)\n    value1 = base64.b16decode(s=value0, casefold=casefold)\n    assert s == value1, (s, value1)\n\n\n@given(casefold=st.booleans(), map01=st.none(), s=st.nothing())\ndef test_roundtrip_b32encode_b32decode(casefold, map01, s):\n    value0 = base64.b32encode(s=s)\n    value1 = base64.b32decode(s=value0, casefold=casefold, map01=map01)\n    assert s == value1, (s, value1)\n\n\n@given(altchars=st.none(), s=st.nothing(), validate=st.booleans())\ndef test_roundtrip_b64encode_b64decode(altchars, s, validate):\n    value0 = base64.b64encode(s=s, altchars=altchars)\n    value1 = base64.b64decode(s=value0, altchars=altchars, validate=validate)\n    assert s == value1, (s, value1)\n\n\n@given(b=st.nothing(), pad=st.booleans())\ndef test_roundtrip_b85encode_b85decode(b, pad):\n    value0 = base64.b85encode(b=b, pad=pad)\n    value1 = base64.b85decode(b=value0)\n    assert b == value1, (b, value1)\n\n\n@given(input=st.nothing(), output=st.nothing())\ndef test_roundtrip_encode_decode(input, output):\n    value0 = base64.encode(input=input, output=output)\n    value1 = base64.decode(input=value0, output=output)\n    assert input == value1, (input, value1)\n\n\n@given(s=st.nothing())\ndef test_roundtrip_encodebytes_decodebytes(s):\n    value0 = base64.encodebytes(s=s)\n    value1 = base64.decodebytes(s=value0)\n    assert s == value1, (s, value1)\n\n\n@given(s=st.nothing())\ndef test_roundtrip_standard_b64encode_standard_b64decode(s):\n    value0 = base64.standard_b64encode(s=s)\n    value1 = base64.standard_b64decode(s=value0)\n    assert s == value1, (s, value1)\n\n\n@given(s=st.nothing())\ndef test_roundtrip_urlsafe_b64encode_urlsafe_b64decode(s):\n    value0 = base64.urlsafe_b64encode(s=s)\n    value1 = base64.urlsafe_b64decode(s=value0)\n    assert s == value1, (s, value1)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/division_binop_error_handler.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport test_expected_output\nfrom hypothesis import given, strategies as st\n\ndivide_operands = st.integers()\n\n\n@given(a=divide_operands, b=divide_operands, c=divide_operands)\ndef test_associative_binary_operation_divide(a: int, b: int, c) -> None:\n    left = test_expected_output.divide(a=a, b=test_expected_output.divide(a=b, b=c))\n    right = test_expected_output.divide(a=test_expected_output.divide(a=a, b=b), b=c)\n    assert left == right, (left, right)\n\n\n@given(a=divide_operands, b=divide_operands)\ndef test_commutative_binary_operation_divide(a: int, b: int) -> None:\n    left = test_expected_output.divide(a=a, b=b)\n    right = test_expected_output.divide(a=b, b=a)\n    assert left == right, (left, right)\n\n\n@given(a=divide_operands)\ndef test_identity_binary_operation_divide(a: int) -> None:\n    identity = 1\n    assert a == test_expected_output.divide(a=a, b=identity)\n    assert a == test_expected_output.divide(a=identity, b=a)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/division_fuzz_error_handler.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport test_expected_output\nfrom hypothesis import given, reject, strategies as st\n\n\n@given(a=st.integers(), b=st.integers())\ndef test_fuzz_divide(a: int, b: int) -> None:\n    try:\n        test_expected_output.divide(a=a, b=b)\n    except ZeroDivisionError:\n        reject()\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/division_operator.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport operator\nfrom hypothesis import given, strategies as st\n\n# TODO: replace st.nothing() with an appropriate strategy\n\ntruediv_operands = st.nothing()\n\n\n@given(a=truediv_operands)\ndef test_identity_binary_operation_truediv(a):\n    identity = \"identity element here\"\n    assert a == operator.truediv(a, identity)\n    assert a == operator.truediv(identity, a)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/division_operator_with_annotations.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport operator\nfrom hypothesis import given, strategies as st\n\n# TODO: replace st.nothing() with an appropriate strategy\n\ntruediv_operands = st.nothing()\n\n\n@given(a=truediv_operands)\ndef test_identity_binary_operation_truediv(a) -> None:\n    identity = \"identity element here\"\n    assert a == operator.truediv(a, identity)\n    assert a == operator.truediv(identity, a)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/division_roundtrip_arithmeticerror_handler.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport operator\nimport test_expected_output\nfrom hypothesis import given, reject, strategies as st\n\n\n@given(a=st.integers(), b=st.integers())\ndef test_roundtrip_divide_mul(a: int, b: int) -> None:\n    try:\n        value0 = test_expected_output.divide(a=a, b=b)\n        value1 = operator.mul(value0, b)\n    except ArithmeticError:\n        reject()\n    assert a == value1, (a, value1)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/division_roundtrip_error_handler.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport operator\nimport test_expected_output\nfrom hypothesis import given, reject, strategies as st\n\n\n@given(a=st.integers(), b=st.integers())\ndef test_roundtrip_divide_mul(a: int, b: int) -> None:\n    try:\n        value0 = test_expected_output.divide(a=a, b=b)\n    except ZeroDivisionError:\n        reject()\n    value1 = operator.mul(value0, b)\n    assert a == value1, (a, value1)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/division_roundtrip_error_handler_without_annotations.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport operator\nimport test_expected_output\nfrom hypothesis import given, reject, strategies as st\n\n\n@given(a=st.integers(), b=st.integers())\ndef test_roundtrip_divide_mul(a, b):\n    try:\n        value0 = test_expected_output.divide(a=a, b=b)\n    except ZeroDivisionError:\n        reject()\n    value1 = operator.mul(value0, b)\n    assert a == value1, (a, value1)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/division_roundtrip_typeerror_handler.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport operator\nimport test_expected_output\nfrom hypothesis import given, reject, strategies as st\n\n\n@given(a=st.integers(), b=st.integers())\ndef test_roundtrip_divide_mul(a: int, b: int) -> None:\n    try:\n        try:\n            value0 = test_expected_output.divide(a=a, b=b)\n        except ZeroDivisionError:\n            reject()\n        value1 = operator.mul(value0, b)\n    except TypeError:\n        reject()\n    assert a == value1, (a, value1)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/eval_equivalent.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport ast\nfrom hypothesis import given, strategies as st\n\n# TODO: replace st.nothing() with an appropriate strategy\n\n\n@given(\n    globals=st.none(), locals=st.none(), node_or_string=st.text(), source=st.nothing()\n)\ndef test_equivalent_eval_literal_eval(globals, locals, node_or_string, source):\n    result_eval = eval(source, globals, locals)\n    result_literal_eval = ast.literal_eval(node_or_string=node_or_string)\n    assert result_eval == result_literal_eval, (result_eval, result_literal_eval)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/fuzz_classmethod.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport test_expected_output\nfrom hypothesis import given, strategies as st\n\n\n@given(arg=st.integers())\ndef test_fuzz_A_Class_a_classmethod(arg: int) -> None:\n    test_expected_output.A_Class.a_classmethod(arg=arg)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/fuzz_sorted.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nfrom hypothesis import given, strategies as st\n\n\n@given(\n    iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())),\n    key=st.none(),\n    reverse=st.booleans(),\n)\ndef test_fuzz_sorted(iterable, key, reverse):\n    sorted(iterable, key=key, reverse=reverse)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/fuzz_sorted_with_annotations.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nfrom hypothesis import given, strategies as st\n\n\n@given(\n    iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())),\n    key=st.none(),\n    reverse=st.booleans(),\n)\ndef test_fuzz_sorted(iterable, key, reverse) -> None:\n    sorted(iterable, key=key, reverse=reverse)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/fuzz_staticmethod.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport test_expected_output\nfrom hypothesis import given, strategies as st\n\n\n@given(arg=st.integers())\ndef test_fuzz_A_Class_a_staticmethod(arg: int) -> None:\n    test_expected_output.A_Class.a_staticmethod(arg=arg)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/fuzz_ufunc.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport numpy\nfrom hypothesis import given, strategies as st\n\n# TODO: replace st.nothing() with appropriate strategies\n\n\n@given(a=st.nothing(), b=st.nothing())\ndef test_fuzz_add(a, b):\n    numpy.add(a, b)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/fuzz_with_docstring.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport test_expected_output\nfrom hypothesis import given, strategies as st\n\n\n@given(\n    a=st.lists(st.integers()),\n    b=st.one_of(st.none(), st.builds(list), st.builds(tuple)),\n    c=st.sampled_from([\"foo\", \"bar\", None]),\n    d=st.just(int),\n    e=st.just(lambda x: f\"xx{x}xx\"),\n)\ndef test_fuzz_with_docstring(a, b, c, d, e):\n    test_expected_output.with_docstring(a=a, b=b, c=c, d=d, e=e)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/hypothesis_module_magic.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport collections.abc\nimport datetime\nimport hypothesis\nimport random\nimport typing\nfrom collections.abc import Hashable\nfrom hypothesis import given, settings, strategies as st\n\n\n@given(condition=st.from_type(object))\ndef test_fuzz_assume(condition: object) -> None:\n    hypothesis.assume(condition=condition)\n\n\n@given(value=st.text(), payload=st.one_of(st.floats(), st.integers(), st.text()))\ndef test_fuzz_event(value: str, payload: typing.Union[str, int, float]) -> None:\n    hypothesis.event(value=value, payload=payload)\n\n\n@given(\n    specifier=st.from_type(st.SearchStrategy),\n    condition=st.functions(like=lambda *a, **k: None, returns=st.booleans()),\n    settings=st.from_type(typing.Optional[hypothesis.settings]),\n    random=st.one_of(st.none(), st.randoms()),\n    database_key=st.one_of(st.none(), st.binary()),\n)\ndef test_fuzz_find(\n    specifier: st.SearchStrategy,\n    condition: collections.abc.Callable[[typing.Any], bool],\n    settings: typing.Union[hypothesis.settings, None],\n    random: typing.Union[random.Random, None],\n    database_key: typing.Union[bytes, None],\n) -> None:\n    hypothesis.find(\n        specifier=specifier,\n        condition=condition,\n        settings=settings,\n        random=random,\n        database_key=database_key,\n    )\n\n\n@given(f=st.from_type(object))\ndef test_fuzz_is_hypothesis_test(f: object) -> None:\n    hypothesis.is_hypothesis_test(f=f)\n\n\n@given(value=st.from_type(object))\ndef test_fuzz_note(value: object) -> None:\n    hypothesis.note(value=value)\n\n\n@given(r=st.randoms())\ndef test_fuzz_register_random(r: random.Random) -> None:\n    hypothesis.register_random(r=r)\n\n\n@given(version=st.text(), blob=st.binary())\ndef test_fuzz_reproduce_failure(version: str, blob: bytes) -> None:\n    hypothesis.reproduce_failure(version=version, blob=blob)\n\n\n@given(seed=st.from_type(Hashable))\ndef test_fuzz_seed(seed: collections.abc.Hashable) -> None:\n    hypothesis.seed(seed=seed)\n\n\n@given(\n    parent=st.none(),\n    max_examples=st.just(not_set),\n    derandomize=st.just(not_set),\n    database=st.just(not_set),\n    verbosity=st.just(not_set),\n    phases=st.just(not_set),\n    stateful_step_count=st.just(not_set),\n    report_multiple_bugs=st.just(not_set),\n    suppress_health_check=st.just(not_set),\n    deadline=st.just(not_set),\n    print_blob=st.just(not_set),\n    backend=st.just(not_set),\n)\ndef test_fuzz_settings(\n    parent: typing.Optional[hypothesis.settings],\n    max_examples: int,\n    derandomize: bool,\n    database,\n    verbosity: hypothesis.Verbosity,\n    phases,\n    stateful_step_count: int,\n    report_multiple_bugs: bool,\n    suppress_health_check,\n    deadline: typing.Union[int, float, datetime.timedelta, None],\n    print_blob: bool,\n    backend: str,\n) -> None:\n    hypothesis.settings(\n        parent=parent,\n        max_examples=max_examples,\n        derandomize=derandomize,\n        database=database,\n        verbosity=verbosity,\n        phases=phases,\n        stateful_step_count=stateful_step_count,\n        report_multiple_bugs=report_multiple_bugs,\n        suppress_health_check=suppress_health_check,\n        deadline=deadline,\n        print_blob=print_blob,\n        backend=backend,\n    )\n\n\n@given(name=st.text())\ndef test_fuzz_settings_get_profile(name: str) -> None:\n    hypothesis.settings.get_profile(name=name)\n\n\n@given(name=st.text())\ndef test_fuzz_settings_load_profile(name: str) -> None:\n    hypothesis.settings.load_profile(name=name)\n\n\n@given(name=st.text(), parent=st.from_type(typing.Optional[hypothesis.settings]))\ndef test_fuzz_settings_register_profile(\n    name: str, parent: typing.Optional[hypothesis.settings]\n) -> None:\n    hypothesis.settings.register_profile(name=name, parent=parent)\n\n\n@given(observation=st.one_of(st.floats(), st.integers()), label=st.text())\ndef test_fuzz_target(observation: typing.Union[int, float], label: str) -> None:\n    hypothesis.target(observation=observation, label=label)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/invalid_types.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport example_code.future_annotations\nfrom hypothesis import given, strategies as st\n\n# TODO: replace st.nothing() with appropriate strategies\n\n\n@given(attr1=st.nothing(), attr2=st.nothing(), attr3=st.nothing())\ndef test_fuzz_invalid_types(attr1, attr2, attr3) -> None:\n    example_code.future_annotations.invalid_types(attr1=attr1, attr2=attr2, attr3=attr3)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/magic_base64_roundtrip.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport base64\nfrom hypothesis import given, strategies as st\n\n# TODO: replace st.nothing() with an appropriate strategy\n\n\n@given(altchars=st.none(), s=st.nothing(), validate=st.booleans())\ndef test_roundtrip_b64encode_b64decode(altchars, s, validate):\n    value0 = base64.b64encode(s=s, altchars=altchars)\n    value1 = base64.b64decode(s=value0, altchars=altchars, validate=validate)\n    assert s == value1, (s, value1)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/magic_base64_roundtrip_with_annotations.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport base64\nfrom hypothesis import given, strategies as st\n\n# TODO: replace st.nothing() with an appropriate strategy\n\n\n@given(altchars=st.none(), s=st.nothing(), validate=st.booleans())\ndef test_roundtrip_b64encode_b64decode(altchars, s, validate) -> None:\n    value0 = base64.b64encode(s=s, altchars=altchars)\n    value1 = base64.b64decode(s=value0, altchars=altchars, validate=validate)\n    assert s == value1, (s, value1)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/magic_builtins.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nfrom hypothesis import given, strategies as st\n\n# TODO: replace st.nothing() with appropriate strategies\n\n\n@given(x=st.nothing())\ndef test_fuzz_abs(x):\n    abs(x)\n\n\n@given(async_iterable=st.nothing())\ndef test_fuzz_aiter(async_iterable):\n    aiter(async_iterable)\n\n\n@given(iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())))\ndef test_fuzz_all(iterable):\n    all(iterable)\n\n\n@given(iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())))\ndef test_fuzz_any(iterable):\n    any(iterable)\n\n\n@given(obj=st.nothing())\ndef test_fuzz_ascii(obj):\n    ascii(obj)\n\n\n@given(number=st.one_of(st.integers(), st.floats()))\ndef test_fuzz_bin(number):\n    bin(number)\n\n\n@given(frm=st.nothing(), to=st.nothing())\ndef test_fuzz_bytearray_maketrans(frm, to):\n    bytearray.maketrans(frm, to)\n\n\n@given(frm=st.nothing(), to=st.nothing())\ndef test_fuzz_bytes_maketrans(frm, to):\n    bytes.maketrans(frm, to)\n\n\n@given(obj=st.nothing())\ndef test_fuzz_callable(obj):\n    callable(obj)\n\n\n@given(i=st.nothing())\ndef test_fuzz_chr(i):\n    chr(i)\n\n\n@given(\n    source=st.nothing(),\n    filename=st.nothing(),\n    mode=st.nothing(),\n    flags=st.just(0),\n    dont_inherit=st.booleans(),\n    optimize=st.just(-1),\n    _feature_version=st.just(-1),\n)\ndef test_fuzz_compile(\n    source, filename, mode, flags, dont_inherit, optimize, _feature_version\n):\n    compile(\n        source=source,\n        filename=filename,\n        mode=mode,\n        flags=flags,\n        dont_inherit=dont_inherit,\n        optimize=optimize,\n        _feature_version=_feature_version,\n    )\n\n\n@given(real=st.just(0), imag=st.just(0))\ndef test_fuzz_complex(real, imag):\n    complex(real=real, imag=imag)\n\n\n@given(obj=st.nothing(), name=st.text())\ndef test_fuzz_delattr(obj, name):\n    delattr(obj, name)\n\n\n@given(object=st.builds(object))\ndef test_fuzz_dir(object):\n    dir(object)\n\n\n@given(x=st.nothing(), y=st.nothing())\ndef test_fuzz_divmod(x, y):\n    divmod(x, y)\n\n\n@given(\n    iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())),\n    start=st.just(0),\n)\ndef test_fuzz_enumerate(iterable, start):\n    enumerate(iterable=iterable, start=start)\n\n\n@given(source=st.nothing(), globals=st.none(), locals=st.none())\ndef test_fuzz_eval(source, globals, locals):\n    eval(source, globals, locals)\n\n\n@given(source=st.nothing(), globals=st.none(), locals=st.none())\ndef test_fuzz_exec(source, globals, locals):\n    exec(source, globals, locals)\n\n\n@given(x=st.just(0))\ndef test_fuzz_float(x):\n    float(x)\n\n\n@given(value=st.nothing(), format_spec=st.just(\"\"))\ndef test_fuzz_format(value, format_spec):\n    format(value, format_spec)\n\n\n@given(object=st.builds(object), name=st.text(), default=st.nothing())\ndef test_fuzz_getattr(object, name, default):\n    getattr(object, name, default)\n\n\n@given(obj=st.nothing(), name=st.text())\ndef test_fuzz_hasattr(obj, name):\n    hasattr(obj, name)\n\n\n@given(obj=st.nothing())\ndef test_fuzz_hash(obj):\n    hash(obj)\n\n\n@given(number=st.one_of(st.integers(), st.floats()))\ndef test_fuzz_hex(number):\n    hex(number)\n\n\n@given(obj=st.nothing())\ndef test_fuzz_id(obj):\n    id(obj)\n\n\n@given(prompt=st.just(\"\"))\ndef test_fuzz_input(prompt):\n    input(prompt)\n\n\n@given(obj=st.nothing(), class_or_tuple=st.nothing())\ndef test_fuzz_isinstance(obj, class_or_tuple):\n    isinstance(obj, class_or_tuple)\n\n\n@given(cls=st.nothing(), class_or_tuple=st.nothing())\ndef test_fuzz_issubclass(cls, class_or_tuple):\n    issubclass(cls, class_or_tuple)\n\n\n@given(iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())))\ndef test_fuzz_iter(iterable):\n    iter(iterable)\n\n\n@given(obj=st.nothing())\ndef test_fuzz_len(obj):\n    len(obj)\n\n\n@given(iterable=st.just(()))\ndef test_fuzz_list(iterable):\n    list(iterable)\n\n\n@given(\n    iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())),\n    default=st.nothing(),\n    key=st.nothing(),\n)\ndef test_fuzz_max(iterable, default, key):\n    max(iterable, default=default, key=key)\n\n\n@given(object=st.builds(object))\ndef test_fuzz_memoryview(object):\n    memoryview(object=object)\n\n\n@given(\n    iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())),\n    default=st.nothing(),\n    key=st.nothing(),\n)\ndef test_fuzz_min(iterable, default, key):\n    min(iterable, default=default, key=key)\n\n\n@given(iterator=st.nothing(), default=st.nothing())\ndef test_fuzz_next(iterator, default):\n    next(iterator, default)\n\n\n@given(number=st.one_of(st.integers(), st.floats()))\ndef test_fuzz_oct(number):\n    oct(number)\n\n\n@given(\n    file=st.nothing(),\n    mode=st.just(\"r\"),\n    buffering=st.just(-1),\n    encoding=st.none(),\n    errors=st.none(),\n    newline=st.none(),\n    closefd=st.booleans(),\n    opener=st.none(),\n)\ndef test_fuzz_open(file, mode, buffering, encoding, errors, newline, closefd, opener):\n    open(\n        file=file,\n        mode=mode,\n        buffering=buffering,\n        encoding=encoding,\n        errors=errors,\n        newline=newline,\n        closefd=closefd,\n        opener=opener,\n    )\n\n\n@given(c=st.nothing())\ndef test_fuzz_ord(c):\n    ord(c)\n\n\n@given(base=st.nothing(), exp=st.nothing(), mod=st.none())\ndef test_fuzz_pow(base, exp, mod):\n    pow(base=base, exp=exp, mod=mod)\n\n\n@given(\n    value=st.nothing(),\n    sep=st.text(),\n    end=st.nothing(),\n    file=st.nothing(),\n    flush=st.nothing(),\n)\ndef test_fuzz_print(value, sep, end, file, flush):\n    print(value, sep=sep, end=end, file=file, flush=flush)\n\n\n@given(fget=st.none(), fset=st.none(), fdel=st.none(), doc=st.none())\ndef test_fuzz_property(fget, fset, fdel, doc):\n    property(fget=fget, fset=fset, fdel=fdel, doc=doc)\n\n\n@given(obj=st.nothing())\ndef test_fuzz_repr(obj):\n    repr(obj)\n\n\n@given(sequence=st.nothing())\ndef test_fuzz_reversed(sequence):\n    reversed(sequence)\n\n\n@given(number=st.one_of(st.integers(), st.floats()), ndigits=st.none())\ndef test_fuzz_round(number, ndigits):\n    round(number=number, ndigits=ndigits)\n\n\n@given(obj=st.nothing(), name=st.text(), value=st.nothing())\ndef test_fuzz_setattr(obj, name, value):\n    setattr(obj, name, value)\n\n\n@given(\n    iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())),\n    key=st.none(),\n    reverse=st.booleans(),\n)\ndef test_fuzz_sorted(iterable, key, reverse):\n    sorted(iterable, key=key, reverse=reverse)\n\n\n@given(\n    iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())),\n    start=st.just(0),\n)\ndef test_fuzz_sum(iterable, start):\n    sum(iterable, start=start)\n\n\n@given(iterable=st.just(()))\ndef test_fuzz_tuple(iterable):\n    tuple(iterable)\n\n\n@given(object=st.builds(object))\ndef test_fuzz_vars(object):\n    vars(object)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/magic_class.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport test_expected_output\nfrom hypothesis import given, strategies as st\n\n\n@given(arg=st.integers())\ndef test_fuzz_A_Class_a_classmethod(arg: int) -> None:\n    test_expected_output.A_Class.a_classmethod(arg=arg)\n\n\n@given(arg=st.integers())\ndef test_fuzz_A_Class_a_staticmethod(arg: int) -> None:\n    test_expected_output.A_Class.a_staticmethod(arg=arg)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/magic_gufunc.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport numpy\nfrom hypothesis import given, strategies as st\nfrom hypothesis.extra.numpy import arrays, mutually_broadcastable_shapes\n\n\n@given(\n    data=st.data(),\n    shapes=mutually_broadcastable_shapes(signature=\"(n?,k),(k,m?)->(n?,m?)\"),\n    types=st.sampled_from([sig for sig in numpy.matmul.types if \"O\" not in sig]),\n)\ndef test_gufunc_matmul(data, shapes, types):\n    input_shapes, expected_shape = shapes\n    input_dtypes, expected_dtype = types.split(\"->\")\n    array_strats = [\n        arrays(dtype=dtp, shape=shp, elements={\"allow_nan\": True})\n        for dtp, shp in zip(input_dtypes, input_shapes)\n    ]\n\n    a, b = data.draw(st.tuples(*array_strats))\n    result = numpy.matmul(a, b)\n\n    assert result.shape == expected_shape\n    assert result.dtype.char == expected_dtype\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/magic_numpy.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport numpy\nimport test_expected_output\nfrom hypothesis import given, strategies as st\nfrom hypothesis.extra.numpy import array_shapes, arrays\nfrom numpy import dtype\n\n\n@given(\n    f=arrays(dtype=dtype(\"float64\"), shape=array_shapes(max_dims=2)),\n    fc=arrays(dtype=numpy.float64 | numpy.complex128, shape=array_shapes(max_dims=2)),\n    union=st.one_of(\n        st.none(),\n        arrays(dtype=numpy.float64 | numpy.complex128, shape=array_shapes(max_dims=2)),\n    ),\n)\ndef test_fuzz_various_numpy_annotations(f, fc, union):\n    test_expected_output.various_numpy_annotations(f=f, fc=fc, union=union)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/matmul_magic.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport operator\nfrom hypothesis import given, strategies as st\n\n# TODO: replace st.nothing() with an appropriate strategy\n\nmatmul_operands = st.nothing()\n\n\n@given(a=matmul_operands, b=matmul_operands, c=matmul_operands)\ndef test_associative_binary_operation_matmul(a, b, c):\n    left = operator.matmul(a, operator.matmul(b, c))\n    right = operator.matmul(operator.matmul(a, b), c)\n    assert left == right, (left, right)\n\n\n@given(a=matmul_operands)\ndef test_identity_binary_operation_matmul(a):\n    identity = \"identity element here\"\n    assert a == operator.matmul(a, identity)\n    assert a == operator.matmul(identity, a)\n\n\n@given(a=matmul_operands, b=matmul_operands, c=matmul_operands)\ndef test_add_distributes_over_binary_operation_matmul(a, b, c):\n    left = operator.matmul(a, operator.add(b, c))\n    ldist = operator.add(operator.matmul(a, b), operator.matmul(a, c))\n    assert ldist == left, (ldist, left)\n\n    right = operator.matmul(operator.add(a, b), c)\n    rdist = operator.add(operator.matmul(a, c), operator.matmul(b, c))\n    assert rdist == right, (rdist, right)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/merge_dicts.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport collections.abc\nimport example_code.future_annotations\nfrom collections import ChainMap\nfrom hypothesis import given, strategies as st\n\n\n@given(\n    map1=st.one_of(\n        st.dictionaries(keys=st.text(), values=st.integers()).map(ChainMap),\n        st.dictionaries(keys=st.text(), values=st.integers()),\n    ),\n    map2=st.one_of(\n        st.dictionaries(keys=st.text(), values=st.integers()).map(ChainMap),\n        st.dictionaries(keys=st.text(), values=st.integers()),\n    ),\n)\ndef test_fuzz_merge_dicts(\n    map1: collections.abc.Mapping[str, int], map2: collections.abc.Mapping[str, int]\n) -> None:\n    example_code.future_annotations.merge_dicts(map1=map1, map2=map2)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/multiplication_magic.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport operator\nfrom hypothesis import given, strategies as st\n\n# TODO: replace st.nothing() with an appropriate strategy\n\nmul_operands = st.nothing()\n\n\n@given(a=mul_operands, b=mul_operands, c=mul_operands)\ndef test_associative_binary_operation_mul(a, b, c):\n    left = operator.mul(a, operator.mul(b, c))\n    right = operator.mul(operator.mul(a, b), c)\n    assert left == right, (left, right)\n\n\n@given(a=mul_operands, b=mul_operands)\ndef test_commutative_binary_operation_mul(a, b):\n    left = operator.mul(a, b)\n    right = operator.mul(b, a)\n    assert left == right, (left, right)\n\n\n@given(a=mul_operands)\ndef test_identity_binary_operation_mul(a):\n    identity = \"identity element here\"\n    assert a == operator.mul(a, identity)\n    assert a == operator.mul(identity, a)\n\n\n@given(a=mul_operands, b=mul_operands, c=mul_operands)\ndef test_add_distributes_over_binary_operation_mul(a, b, c):\n    left = operator.mul(a, operator.add(b, c))\n    ldist = operator.add(operator.mul(a, b), operator.mul(a, c))\n    assert ldist == left, (ldist, left)\n\n    right = operator.mul(operator.add(a, b), c)\n    rdist = operator.add(operator.mul(a, c), operator.mul(b, c))\n    assert rdist == right, (rdist, right)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/multiplication_operator.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport operator\nfrom hypothesis import given, strategies as st\n\n# TODO: replace st.nothing() with an appropriate strategy\n\nmul_operands = st.nothing()\n\n\n@given(a=mul_operands, b=mul_operands, c=mul_operands)\ndef test_associative_binary_operation_mul(a, b, c):\n    left = operator.mul(a, operator.mul(b, c))\n    right = operator.mul(operator.mul(a, b), c)\n    assert left == right, (left, right)\n\n\n@given(a=mul_operands, b=mul_operands)\ndef test_commutative_binary_operation_mul(a, b):\n    left = operator.mul(a, b)\n    right = operator.mul(b, a)\n    assert left == right, (left, right)\n\n\n@given(a=mul_operands)\ndef test_identity_binary_operation_mul(a):\n    identity = 1\n    assert a == operator.mul(a, identity)\n    assert a == operator.mul(identity, a)\n\n\n@given(a=mul_operands, b=mul_operands, c=mul_operands)\ndef test_add_distributes_over_binary_operation_mul(a, b, c):\n    left = operator.mul(a, operator.add(b, c))\n    ldist = operator.add(operator.mul(a, b), operator.mul(a, c))\n    assert ldist == left, (ldist, left)\n\n    right = operator.mul(operator.add(a, b), c)\n    rdist = operator.add(operator.mul(a, c), operator.mul(b, c))\n    assert rdist == right, (rdist, right)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/multiplication_operator_unittest.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport operator\nimport unittest\nfrom hypothesis import given, strategies as st\n\n# TODO: replace st.nothing() with an appropriate strategy\n\n\nclass TestBinaryOperationmul(unittest.TestCase):\n    mul_operands = st.nothing()\n\n    @given(a=mul_operands, b=mul_operands, c=mul_operands)\n    def test_associative_binary_operation_mul(self, a, b, c):\n        left = operator.mul(a, operator.mul(b, c))\n        right = operator.mul(operator.mul(a, b), c)\n        self.assertEqual(left, right)\n\n    @given(a=mul_operands, b=mul_operands)\n    def test_commutative_binary_operation_mul(self, a, b):\n        left = operator.mul(a, b)\n        right = operator.mul(b, a)\n        self.assertEqual(left, right)\n\n    @given(a=mul_operands)\n    def test_identity_binary_operation_mul(self, a):\n        identity = 1\n        self.assertEqual(a, operator.mul(a, identity))\n        self.assertEqual(a, operator.mul(identity, a))\n\n    @given(a=mul_operands, b=mul_operands, c=mul_operands)\n    def test_add_distributes_over_binary_operation_mul(self, a, b, c):\n        left = operator.mul(a, operator.add(b, c))\n        ldist = operator.add(operator.mul(a, b), operator.mul(a, c))\n        self.assertEqual(ldist, left)\n\n        right = operator.mul(operator.add(a, b), c)\n        rdist = operator.add(operator.mul(a, c), operator.mul(b, c))\n        self.assertEqual(rdist, right)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/nothing_found.txt",
    "content": "# Found no testable functions in foo (from 'foo/__init__.py')\n# Try writing tests for submodules, e.g. by using:\n#     hypothesis write foo.bar\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/optional_parameter.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport test_expected_output\nimport typing\nfrom hypothesis import given, strategies as st\n\n\n@given(a=st.floats(), b=st.one_of(st.none(), st.floats()))\ndef test_fuzz_optional_parameter(a: float, b: typing.Union[float, None]) -> None:\n    test_expected_output.optional_parameter(a=a, b=b)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/optional_union_parameter.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport test_expected_output\nimport typing\nfrom hypothesis import given, strategies as st\n\n\n@given(a=st.floats(), b=st.one_of(st.none(), st.floats(), st.integers()))\ndef test_fuzz_optional_union_parameter(\n    a: float, b: typing.Union[float, int, None]\n) -> None:\n    test_expected_output.optional_union_parameter(a=a, b=b)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/re_compile.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport re\nfrom hypothesis import given, strategies as st\n\n\n@given(pattern=st.text(), flags=st.just(0))\ndef test_fuzz_compile(pattern, flags):\n    re.compile(pattern=pattern, flags=flags)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/re_compile_except.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport re\nfrom hypothesis import given, reject, strategies as st\n\n\n@given(pattern=st.text(), flags=st.just(0))\ndef test_fuzz_compile(pattern, flags):\n    try:\n        re.compile(pattern=pattern, flags=flags)\n    except re.error:\n        reject()\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/re_compile_unittest.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport re\nimport unittest\nfrom hypothesis import given, strategies as st\n\n\nclass TestFuzzCompile(unittest.TestCase):\n\n    @given(pattern=st.text(), flags=st.just(0))\n    def test_fuzz_compile(self, pattern, flags):\n        re.compile(pattern=pattern, flags=flags)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/sequence_from_collections.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport collections.abc\nimport test_expected_output\nfrom hypothesis import given, strategies as st\n\n\n@given(items=st.one_of(st.binary(), st.lists(st.integers())))\ndef test_fuzz_sequence_from_collections(items: collections.abc.Sequence[int]) -> None:\n    test_expected_output.sequence_from_collections(items=items)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/sorted_idempotent.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nfrom hypothesis import given, strategies as st\n\n\n@given(\n    iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())),\n    key=st.none(),\n    reverse=st.booleans(),\n)\ndef test_idempotent_sorted(iterable, key, reverse):\n    result = sorted(iterable, key=key, reverse=reverse)\n    repeat = sorted(result, key=key, reverse=reverse)\n    assert result == repeat, (result, repeat)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/sorted_self_equivalent.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nfrom hypothesis import given, strategies as st\n\n\n@given(\n    iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())),\n    key=st.none(),\n    reverse=st.booleans(),\n)\ndef test_equivalent_sorted_sorted_sorted(iterable, key, reverse):\n    result_0_sorted = sorted(iterable, key=key, reverse=reverse)\n    result_1_sorted = sorted(iterable, key=key, reverse=reverse)\n    result_2_sorted = sorted(iterable, key=key, reverse=reverse)\n    assert result_0_sorted == result_1_sorted, (result_0_sorted, result_1_sorted)\n    assert result_0_sorted == result_2_sorted, (result_0_sorted, result_2_sorted)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/sorted_self_equivalent_with_annotations.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nfrom hypothesis import given, strategies as st\n\n\n@given(\n    iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())),\n    key=st.none(),\n    reverse=st.booleans(),\n)\ndef test_equivalent_sorted_sorted_sorted(iterable, key, reverse) -> None:\n    result_0_sorted = sorted(iterable, key=key, reverse=reverse)\n    result_1_sorted = sorted(iterable, key=key, reverse=reverse)\n    result_2_sorted = sorted(iterable, key=key, reverse=reverse)\n    assert result_0_sorted == result_1_sorted, (result_0_sorted, result_1_sorted)\n    assert result_0_sorted == result_2_sorted, (result_0_sorted, result_2_sorted)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/sorted_self_error_equivalent_1error.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport pytest\nfrom hypothesis import given, reject, strategies as st, target\n\n\n@given(\n    iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())),\n    key=st.none(),\n    reverse=st.booleans(),\n)\ndef test_equivalent_sorted_sorted(iterable, key, reverse):\n    try:\n        result_0_sorted = sorted(iterable, key=key, reverse=reverse)\n        exc_type = None\n        target(1, label=\"input was valid\")\n    except ValueError:\n        reject()\n    except Exception as exc:\n        exc_type = type(exc)\n\n    if exc_type:\n        with pytest.raises(exc_type):\n            sorted(iterable, key=key, reverse=reverse)\n    else:\n        result_1_sorted = sorted(iterable, key=key, reverse=reverse)\n        assert result_0_sorted == result_1_sorted, (result_0_sorted, result_1_sorted)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/sorted_self_error_equivalent_2error_unittest.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport unittest\nfrom hypothesis import given, reject, strategies as st, target\n\n\nclass TestEquivalentSortedSorted(unittest.TestCase):\n\n    @given(\n        iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())),\n        key=st.none(),\n        reverse=st.booleans(),\n    )\n    def test_equivalent_sorted_sorted(self, iterable, key, reverse):\n        try:\n            result_0_sorted = sorted(iterable, key=key, reverse=reverse)\n            exc_type = None\n            target(1, label=\"input was valid\")\n        except (TypeError, ValueError):\n            reject()\n        except Exception as exc:\n            exc_type = type(exc)\n\n        if exc_type:\n            with self.assertRaises(exc_type):\n                sorted(iterable, key=key, reverse=reverse)\n        else:\n            result_1_sorted = sorted(iterable, key=key, reverse=reverse)\n            self.assertEqual(result_0_sorted, result_1_sorted)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/sorted_self_error_equivalent_simple.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport pytest\nfrom hypothesis import given, strategies as st, target\n\n\n@given(\n    iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())),\n    key=st.none(),\n    reverse=st.booleans(),\n)\ndef test_equivalent_sorted_sorted(iterable, key, reverse):\n    try:\n        result_0_sorted = sorted(iterable, key=key, reverse=reverse)\n        exc_type = None\n        target(1, label=\"input was valid\")\n    except Exception as exc:\n        exc_type = type(exc)\n\n    if exc_type:\n        with pytest.raises(exc_type):\n            sorted(iterable, key=key, reverse=reverse)\n    else:\n        result_1_sorted = sorted(iterable, key=key, reverse=reverse)\n        assert result_0_sorted == result_1_sorted, (result_0_sorted, result_1_sorted)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/sorted_self_error_equivalent_threefuncs.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport pytest\nfrom hypothesis import given, strategies as st, target\n\n\n@given(\n    iterable=st.one_of(st.iterables(st.integers()), st.iterables(st.text())),\n    key=st.none(),\n    reverse=st.booleans(),\n)\ndef test_equivalent_sorted_sorted_sorted(iterable, key, reverse):\n    try:\n        result_0_sorted = sorted(iterable, key=key, reverse=reverse)\n        exc_type = None\n        target(1, label=\"input was valid\")\n    except Exception as exc:\n        exc_type = type(exc)\n\n    if exc_type:\n        with pytest.raises(exc_type):\n            sorted(iterable, key=key, reverse=reverse)\n    else:\n        result_1_sorted = sorted(iterable, key=key, reverse=reverse)\n        assert result_0_sorted == result_1_sorted, (result_0_sorted, result_1_sorted)\n\n    if exc_type:\n        with pytest.raises(exc_type):\n            sorted(iterable, key=key, reverse=reverse)\n    else:\n        result_2_sorted = sorted(iterable, key=key, reverse=reverse)\n        assert result_0_sorted == result_2_sorted, (result_0_sorted, result_2_sorted)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/timsort_idempotent.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport collections.abc\nimport test_expected_output\nfrom hypothesis import given, strategies as st\n\n\n@given(seq=st.one_of(st.binary(), st.lists(st.integers())))\ndef test_idempotent_timsort(seq: collections.abc.Sequence[int]) -> None:\n    result = test_expected_output.timsort(seq=seq)\n    repeat = test_expected_output.timsort(seq=result)\n    assert result == repeat, (result, repeat)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/timsort_idempotent_asserts.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport collections.abc\nimport test_expected_output\nfrom hypothesis import given, reject, strategies as st\n\n\n@given(seq=st.one_of(st.binary(), st.lists(st.integers())))\ndef test_idempotent_timsort(seq: collections.abc.Sequence[int]) -> None:\n    try:\n        result = test_expected_output.timsort(seq=seq)\n        repeat = test_expected_output.timsort(seq=result)\n    except AssertionError:\n        reject()\n    assert result == repeat, (result, repeat)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/recorded/union_sequence_parameter.txt",
    "content": "# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport collections.abc\nimport test_expected_output\nimport typing\nfrom hypothesis import given, strategies as st\n\n\n@given(items=st.one_of(st.binary(), st.lists(st.one_of(st.floats(), st.integers()))))\ndef test_fuzz_union_sequence_parameter(\n    items: collections.abc.Sequence[typing.Union[float, int]],\n) -> None:\n    test_expected_output.union_sequence_parameter(items=items)\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/test_expected_output.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\n'Golden master' tests for the ghostwriter.\n\nTo update the recorded outputs, run:\n\n    pytest test_expected_output.py --hypothesis-update-outputs\n\"\"\"\n\nimport ast\nimport base64\nimport builtins\nimport collections.abc\nimport operator\nimport pathlib\nimport re\nimport subprocess\nimport sys\nfrom collections.abc import Sequence\n\nimport black\nimport numpy\nimport numpy.typing\nimport pytest\nfrom example_code.future_annotations import (\n    add_custom_classes,\n    invalid_types,\n    merge_dicts,\n)\n\nimport hypothesis\nfrom hypothesis import settings\nfrom hypothesis.extra import ghostwriter\nfrom hypothesis.utils.conventions import not_set\n\npytestmark = pytest.mark.skipif(\n    settings.get_current_profile_name() == \"threading\",\n    reason=\"ghostwriter is not thread safe\",\n)\n\n\n@pytest.fixture\ndef update_recorded_outputs(request):\n    return request.config.getoption(\"--hypothesis-update-outputs\")\n\n\ndef get_recorded(name, actual=\"\"):\n    file_ = pathlib.Path(__file__).parent / \"recorded\" / f\"{name}.txt\"\n    if actual:\n        file_.write_text(actual, encoding=\"utf-8\")\n    return file_.read_text(encoding=\"utf-8\")\n\n\ndef timsort(seq: Sequence[int]) -> Sequence[int]:\n    return sorted(seq)\n\n\ndef with_docstring(a, b, c, d=int, e=lambda x: f\"xx{x}xx\") -> None:\n    \"\"\"Demonstrates parsing params from the docstring\n\n    :param a: sphinx docstring style\n    :type a: sequence of integers\n\n    b (list, tuple, or None): Google docstring style\n\n    c : {\"foo\", \"bar\", or None}\n        Numpy docstring style\n    \"\"\"\n\n\nclass A_Class:\n    @classmethod\n    def a_classmethod(cls, arg: int):\n        pass\n\n    @staticmethod\n    def a_staticmethod(arg: int):\n        pass\n\n\ndef add(a: float, b: float) -> float:\n    return a + b\n\n\ndef divide(a: int, b: int) -> float:\n    \"\"\"This is a RST-style docstring for `divide`.\n\n    :raises ZeroDivisionError: if b == 0\n    \"\"\"\n    return a / b\n\n\ndef optional_parameter(a: float, b: float | None) -> float:\n    return optional_union_parameter(a, b)\n\n\ndef optional_union_parameter(a: float, b: float | int | None) -> float:\n    return a if b is None else a + b\n\n\ndef union_sequence_parameter(items: Sequence[float | int]) -> float:\n    return sum(items)\n\n\ndef sequence_from_collections(items: collections.abc.Sequence[int]) -> int:\n    return min(items)\n\n\ndef various_numpy_annotations(\n    f: numpy.typing.NDArray[numpy.float64],\n    fc: numpy.typing.NDArray[numpy.float64 | numpy.complex128],\n    union: numpy.typing.NDArray[numpy.float64 | numpy.complex128] | None,\n):\n    pass\n\n\n# Note: for some of the `expected` outputs, we replace away some small\n#       parts which vary between minor versions of Python.\n@pytest.mark.parametrize(\n    \"data\",\n    [\n        (\"fuzz_sorted\", lambda: ghostwriter.fuzz(sorted)),\n        (\n            \"fuzz_sorted_with_annotations\",\n            lambda: ghostwriter.fuzz(sorted, annotate=True),\n        ),\n        (\"fuzz_with_docstring\", lambda: ghostwriter.fuzz(with_docstring)),\n        (\"fuzz_classmethod\", lambda: ghostwriter.fuzz(A_Class.a_classmethod)),\n        (\"fuzz_staticmethod\", lambda: ghostwriter.fuzz(A_Class.a_staticmethod)),\n        (\"fuzz_ufunc\", lambda: ghostwriter.fuzz(numpy.add)),\n        (\"magic_gufunc\", lambda: ghostwriter.magic(numpy.matmul)),\n        (\"optional_parameter\", lambda: ghostwriter.magic(optional_parameter)),\n        (\n            \"optional_union_parameter\",\n            lambda: ghostwriter.magic(optional_union_parameter),\n        ),\n        (\n            \"union_sequence_parameter\",\n            lambda: ghostwriter.magic(union_sequence_parameter),\n        ),\n        (\n            \"sequence_from_collections\",\n            lambda: ghostwriter.magic(sequence_from_collections),\n        ),\n        (\"add_custom_classes\", lambda: ghostwriter.magic(add_custom_classes)),\n        (\"merge_dicts\", lambda: ghostwriter.magic(merge_dicts)),\n        (\"invalid_types\", lambda: ghostwriter.magic(invalid_types)),\n        (\"magic_base64_roundtrip\", lambda: ghostwriter.magic(base64.b64encode)),\n        (\n            \"magic_base64_roundtrip_with_annotations\",\n            lambda: ghostwriter.magic(base64.b64encode, annotate=True),\n        ),\n        (\"re_compile\", lambda: ghostwriter.fuzz(re.compile)),\n        (\n            \"re_compile_except\",\n            lambda: ghostwriter.fuzz(re.compile, except_=re.error).replace(\n                \"re.PatternError\", \"re.error\"  # changed in Python 3.13\n            ),\n        ),\n        (\"re_compile_unittest\", lambda: ghostwriter.fuzz(re.compile, style=\"unittest\")),\n        pytest.param(\n            (\"base64_magic\", lambda: ghostwriter.magic(base64)),\n            marks=pytest.mark.skipif(\"sys.version_info[:2] >= (3, 10)\"),\n        ),\n        (\"sorted_idempotent\", lambda: ghostwriter.idempotent(sorted)),\n        (\"timsort_idempotent\", lambda: ghostwriter.idempotent(timsort)),\n        (\n            \"timsort_idempotent_asserts\",\n            lambda: ghostwriter.idempotent(timsort, except_=AssertionError),\n        ),\n        pytest.param(\n            (\"eval_equivalent\", lambda: ghostwriter.equivalent(eval, ast.literal_eval)),\n            marks=[pytest.mark.skipif(sys.version_info[:2] >= (3, 13), reason=\"kw\")],\n        ),\n        (\n            \"sorted_self_equivalent\",\n            lambda: ghostwriter.equivalent(sorted, sorted, sorted),\n        ),\n        (\n            \"sorted_self_equivalent_with_annotations\",\n            lambda: ghostwriter.equivalent(sorted, sorted, sorted, annotate=True),\n        ),\n        (\"addition_op_magic\", lambda: ghostwriter.magic(add)),\n        (\"multiplication_magic\", lambda: ghostwriter.magic(operator.mul)),\n        (\"matmul_magic\", lambda: ghostwriter.magic(operator.matmul)),\n        (\n            \"addition_op_multimagic\",\n            lambda: ghostwriter.magic(add, operator.add, numpy.add),\n        ),\n        (\"division_fuzz_error_handler\", lambda: ghostwriter.fuzz(divide)),\n        (\n            \"division_binop_error_handler\",\n            lambda: ghostwriter.binary_operation(divide, identity=1),\n        ),\n        (\n            \"division_roundtrip_error_handler\",\n            lambda: ghostwriter.roundtrip(divide, operator.mul),\n        ),\n        (\n            \"division_roundtrip_error_handler_without_annotations\",\n            lambda: ghostwriter.roundtrip(divide, operator.mul, annotate=False),\n        ),\n        (\n            \"division_roundtrip_arithmeticerror_handler\",\n            lambda: ghostwriter.roundtrip(\n                divide, operator.mul, except_=ArithmeticError\n            ),\n        ),\n        (\n            \"division_roundtrip_typeerror_handler\",\n            lambda: ghostwriter.roundtrip(divide, operator.mul, except_=TypeError),\n        ),\n        (\n            \"division_operator\",\n            lambda: ghostwriter.binary_operation(\n                operator.truediv, associative=False, commutative=False\n            ),\n        ),\n        (\n            \"division_operator_with_annotations\",\n            lambda: ghostwriter.binary_operation(\n                operator.truediv, associative=False, commutative=False, annotate=True\n            ),\n        ),\n        (\n            \"multiplication_operator\",\n            lambda: ghostwriter.binary_operation(\n                operator.mul, identity=1, distributes_over=operator.add\n            ),\n        ),\n        (\n            \"multiplication_operator_unittest\",\n            lambda: ghostwriter.binary_operation(\n                operator.mul,\n                identity=1,\n                distributes_over=operator.add,\n                style=\"unittest\",\n            ),\n        ),\n        (\n            \"sorted_self_error_equivalent_simple\",\n            lambda: ghostwriter.equivalent(sorted, sorted, allow_same_errors=True),\n        ),\n        (\n            \"sorted_self_error_equivalent_threefuncs\",\n            lambda: ghostwriter.equivalent(\n                sorted, sorted, sorted, allow_same_errors=True\n            ),\n        ),\n        (\n            \"sorted_self_error_equivalent_1error\",\n            lambda: ghostwriter.equivalent(\n                sorted,\n                sorted,\n                allow_same_errors=True,\n                except_=ValueError,\n            ),\n        ),\n        (\n            \"sorted_self_error_equivalent_2error_unittest\",\n            lambda: ghostwriter.equivalent(\n                sorted,\n                sorted,\n                allow_same_errors=True,\n                except_=(TypeError, ValueError),\n                style=\"unittest\",\n            ),\n        ),\n        (\"magic_class\", lambda: ghostwriter.magic(A_Class)),\n        pytest.param(\n            (\"magic_builtins\", lambda: ghostwriter.magic(builtins)),\n            marks=[\n                pytest.mark.skipif(\n                    sys.version_info[:2] != (3, 10),\n                    reason=\"often small changes\",\n                )\n            ],\n        ),\n        pytest.param(\n            (\n                \"magic_numpy\",\n                lambda: ghostwriter.magic(various_numpy_annotations, annotate=False),\n            ),\n            marks=pytest.mark.skipif(various_numpy_annotations is add, reason=\"<=3.9\"),\n        ),\n    ],\n    ids=lambda x: x[0],\n)\ndef test_ghostwriter_example_outputs(update_recorded_outputs, data):\n    name, get_actual = data\n    # ghostwriter computations can be expensive, so defer collection-time\n    # computations until test-time\n    actual = get_actual()\n    expected = get_recorded(name, actual * update_recorded_outputs)\n    assert actual == expected  # We got the expected source code\n    exec(expected, {})  # and there are no SyntaxError or NameErrors\n\n\ndef test_ghostwriter_on_hypothesis(update_recorded_outputs):\n    actual = (\n        ghostwriter.magic(hypothesis)\n        .replace(\"Strategy[+Ex]\", \"Strategy\")\n        .replace(\"hypothesis._settings.settings\", \"hypothesis.settings\")\n    )\n    # hypothesis._settings.settings wraps the line before replacement, and doesn't\n    # after replacement\n    actual = black.format_str(actual, mode=black.Mode())\n    expected = get_recorded(\"hypothesis_module_magic\", actual * update_recorded_outputs)\n    if sys.version_info[:2] == (3, 10):\n        assert actual == expected\n    exec(expected, {\"not_set\": not_set})\n\n\ndef test_ghostwriter_suggests_submodules_for_empty_toplevel(\n    tmp_path, update_recorded_outputs\n):\n    foo = tmp_path / \"foo\"\n    foo.mkdir()\n    (foo / \"__init__.py\").write_text(\"from . import bar\\n\", encoding=\"utf-8\")\n    (foo / \"bar.py\").write_text(\"def baz(x: int): ...\\n\", encoding=\"utf-8\")\n\n    proc = subprocess.run(\n        [\"hypothesis\", \"write\", \"foo\"],\n        check=True,\n        capture_output=True,\n        encoding=\"utf-8\",\n        cwd=tmp_path,\n    )\n    actual = proc.stdout.replace(re.search(r\"from '(.+)foo/\", proc.stdout).group(1), \"\")\n\n    expected = get_recorded(\"nothing_found\", actual * update_recorded_outputs)\n    assert actual == expected  # We got the expected source code\n    exec(expected, {})  # and there are no SyntaxError or NameErrors\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/test_ghostwriter.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport ast\nimport enum\nimport json\nimport re\nimport socket\nimport sys\nimport unittest\nimport unittest.mock\nfrom collections.abc import KeysView, Sequence, Sized, ValuesView\nfrom decimal import Decimal\nfrom pathlib import Path\nfrom textwrap import dedent\nfrom types import FunctionType, ModuleType\nfrom typing import Any, ForwardRef\n\nimport attr\nimport click\nimport pytest\n\nfrom hypothesis import HealthCheck, assume, settings\nfrom hypothesis.errors import InvalidArgument, Unsatisfiable\nfrom hypothesis.extra import cli, ghostwriter\nfrom hypothesis.internal.compat import BaseExceptionGroup\nfrom hypothesis.strategies import builds, from_type, just, lists\nfrom hypothesis.strategies._internal.core import from_regex\nfrom hypothesis.strategies._internal.lazy import LazyStrategy\n\nvaried_excepts = pytest.mark.parametrize(\"ex\", [(), ValueError, (TypeError, re.error)])\n\n\npytestmark = pytest.mark.skipif(\n    settings.get_current_profile_name() == \"threading\",\n    reason=\"ghostwriter is not thread safe\",\n)\n\n\ndef get_test_function(source_code, settings_decorator=lambda fn: fn):\n    # A helper function to get the dynamically-defined test function.\n    # Note that this also tests that the module is syntatically-valid,\n    # AND free from undefined names, import problems, and so on.\n    namespace = {}\n    try:\n        exec(source_code, namespace)\n    except Exception:\n        print(f\"************\\n{source_code}\\n************\")\n        raise\n    tests = [\n        v\n        for k, v in namespace.items()\n        if k.startswith((\"test_\", \"Test\")) and not isinstance(v, ModuleType)\n    ]\n    assert len(tests) == 1, tests\n    return settings_decorator(tests[0])\n\n\n@pytest.mark.parametrize(\n    \"badness\", [\"not an exception\", BaseException, [ValueError], (Exception, \"bad\")]\n)\ndef test_invalid_exceptions(badness):\n    with pytest.raises(InvalidArgument):\n        ghostwriter._check_except(badness)\n\n\ndef test_style_validation():\n    ghostwriter._check_style(\"pytest\")\n    ghostwriter._check_style(\"unittest\")\n    with pytest.raises(InvalidArgument):\n        ghostwriter._check_style(\"not a valid style\")\n\n\ndef test_strategies_with_invalid_syntax_repr_as_nothing():\n    msg = \"$$ this repr is not Python syntax $$\"\n\n    class NoRepr:\n        def __repr__(self):\n            return msg\n\n    s = just(NoRepr())\n    assert repr(s) == f\"just({msg})\"\n    assert ghostwriter._valid_syntax_repr(s)[1] == \"nothing()\"\n\n\nclass AnEnum(enum.Enum):\n    a = \"value of AnEnum.a\"\n    b = \"value of AnEnum.b\"\n\n\ndef takes_enum(foo=AnEnum.a):\n    # This can only fail if we use the default argument to guess\n    # that any instance of that enum type should be allowed.\n    assert foo != AnEnum.b\n\n\ndef test_ghostwriter_exploits_arguments_with_enum_defaults():\n    source_code = ghostwriter.fuzz(takes_enum)\n    test = get_test_function(source_code)\n    with pytest.raises(AssertionError):\n        test()\n\n\ndef timsort(seq: Sequence[int]) -> list[int]:\n    return sorted(seq)\n\n\ndef non_type_annotation(x: 3):  # type: ignore\n    pass\n\n\ndef annotated_any(x: Any):\n    pass\n\n\nspace_in_name = type(\"a name\", (type,), {\"__init__\": lambda self: None})\n\n\nclass NotResolvable:\n    def __init__(self, unannotated_required):\n        pass\n\n\ndef non_resolvable_arg(x: NotResolvable):\n    pass\n\n\ndef test_flattens_one_of_repr():\n    strat = from_type(int | Sequence[int])\n    assert repr(strat).count(\"one_of(\") == 2\n    assert ghostwriter._valid_syntax_repr(strat)[1].count(\"one_of(\") == 1\n\n\ndef takes_keys(x: KeysView[int]) -> None:\n    pass\n\n\ndef takes_values(x: ValuesView[int]) -> None:\n    pass\n\n\ndef takes_match(x: re.Match[bytes]) -> None:\n    pass\n\n\ndef takes_pattern(x: re.Pattern[str]) -> None:\n    pass\n\n\ndef takes_sized(x: Sized) -> None:\n    pass\n\n\ndef takes_frozensets(a: frozenset[int], b: frozenset[int]) -> None:\n    pass\n\n\n@attr.s()\nclass Foo:\n    foo: str = attr.ib()\n\n\ndef takes_attrs_class(x: Foo) -> None:\n    pass\n\n\n@varied_excepts\n@pytest.mark.parametrize(\n    \"func\",\n    [\n        re.compile,\n        json.loads,\n        json.dump,\n        timsort,\n        ast.literal_eval,\n        non_type_annotation,\n        annotated_any,\n        space_in_name,\n        non_resolvable_arg,\n        takes_keys,\n        takes_values,\n        takes_match,\n        takes_pattern,\n        takes_sized,\n        takes_frozensets,\n        takes_attrs_class,\n    ],\n)\ndef test_ghostwriter_fuzz(func, ex):\n    source_code = ghostwriter.fuzz(func, except_=ex)\n    get_test_function(source_code)\n\n\ndef test_socket_module():\n    source_code = ghostwriter.magic(socket)\n    exec(source_code, {})\n\n\ndef test_binary_op_also_handles_frozensets():\n    # Using str.replace in a loop would convert `frozensets()` into\n    # `st.frozenst.sets()` instead of `st.frozensets()`; fixed with re.sub.\n    source_code = ghostwriter.binary_operation(takes_frozensets)\n    exec(source_code, {})\n\n\ndef test_binary_op_with_numpy_arrays_includes_imports():\n    # Regression test for issue #4576: binary_operation should include imports\n    # for numpy strategies like arrays(), scalar_dtypes(), and array_shapes()\n    pytest.importorskip(\"numpy\")\n    import numpy as np\n\n    def numpy_add(a: np.ndarray, b: np.ndarray) -> np.ndarray:\n        return a + b\n\n    source_code = ghostwriter.binary_operation(\n        numpy_add, associative=True, commutative=True, identity=None\n    )\n    # Check that the necessary imports are present\n    assert \"from hypothesis.extra.numpy import\" in source_code\n    assert \"arrays\" in source_code\n    assert \"scalar_dtypes\" in source_code\n    assert \"array_shapes\" in source_code\n    # Most importantly: the code should execute without NameError\n    exec(source_code, {})\n\n\n@varied_excepts\n@pytest.mark.parametrize(\n    \"func\", [re.compile, json.loads, json.dump, timsort, ast.literal_eval]\n)\ndef test_ghostwriter_unittest_style(func, ex):\n    source_code = ghostwriter.fuzz(func, except_=ex, style=\"unittest\")\n    assert issubclass(get_test_function(source_code), unittest.TestCase)\n\n\ndef no_annotations(foo=None, *, bar=False):\n    pass\n\n\ndef test_inference_from_defaults_and_none_booleans_reprs_not_just_and_sampled_from():\n    source_code = ghostwriter.fuzz(no_annotations)\n    assert \"@given(foo=st.none(), bar=st.booleans())\" in source_code\n\n\ndef hopefully_hashable(foo: set[Decimal]):\n    pass\n\n\ndef test_no_hashability_filter():\n    # In from_type, we ordinarily protect users from really weird cases like\n    # `Decimal('snan')` - a unhashable value of a hashable type - but in the\n    # ghostwriter we instead want to present this to the user for an explicit\n    # decision.  They can pass `allow_nan=False`, fix their custom type's\n    # hashing logic, or whatever else; simply doing nothing will usually work.\n    source_code = ghostwriter.fuzz(hopefully_hashable)\n    assert \"@given(foo=st.sets(st.decimals()))\" in source_code\n    assert \"_can_hash\" not in source_code\n\n\n@pytest.mark.parametrize(\n    \"gw,args\",\n    [\n        (ghostwriter.fuzz, [\"not callable\"]),\n        (ghostwriter.idempotent, [\"not callable\"]),\n        (ghostwriter.roundtrip, []),\n        (ghostwriter.roundtrip, [\"not callable\"]),\n        (ghostwriter.equivalent, [sorted]),\n        (ghostwriter.equivalent, [sorted, \"not callable\"]),\n    ],\n)\ndef test_invalid_func_inputs(gw, args):\n    with pytest.raises(InvalidArgument):\n        gw(*args)\n\n\nclass A:\n    @classmethod\n    def to_json(cls, obj: dict | list) -> str:\n        return json.dumps(obj)\n\n    @classmethod\n    def from_json(cls, obj: str) -> dict | list:\n        return json.loads(obj)\n\n    @staticmethod\n    def static_sorter(seq: Sequence[int]) -> list[int]:\n        return sorted(seq)\n\n\n@pytest.mark.parametrize(\n    \"gw,args\",\n    [\n        (ghostwriter.fuzz, [A.static_sorter]),\n        (ghostwriter.idempotent, [A.static_sorter]),\n        (ghostwriter.roundtrip, [A.to_json, A.from_json]),\n        (ghostwriter.equivalent, [A.to_json, json.dumps]),\n    ],\n)\ndef test_class_methods_inputs(gw, args):\n    source_code = gw(*args)\n    get_test_function(source_code)()\n\n\ndef test_run_ghostwriter_fuzz():\n    # Our strategy-guessing code works for all the arguments to sorted,\n    # and we handle positional-only arguments in calls correctly too.\n    source_code = ghostwriter.fuzz(sorted)\n    assert \"st.nothing()\" not in source_code\n    get_test_function(source_code)()\n\n\nclass MyError(UnicodeDecodeError):\n    pass\n\n\n@pytest.mark.parametrize(\n    \"exceptions,output\",\n    [\n        # Discard subclasses of other exceptions to catch, including non-builtins,\n        # and replace OSError aliases with OSError.\n        ((Exception, UnicodeError), \"Exception\"),\n        ((UnicodeError, MyError), \"UnicodeError\"),\n        ((IOError,), \"OSError\"),\n        ((IOError, UnicodeError), \"(OSError, UnicodeError)\"),\n    ],\n)\ndef test_exception_deduplication(exceptions, output):\n    _, body = ghostwriter._make_test_body(\n        lambda: None,\n        ghost=\"\",\n        test_body=\"pass\",\n        except_=exceptions,\n        style=\"pytest\",\n        annotate=False,\n    )\n    assert f\"except {output}:\" in body\n\n\ndef test_run_ghostwriter_roundtrip():\n    # This test covers the whole lifecycle: first, we get the default code.\n    # The first argument is unknown, so we fail to draw from st.nothing()\n    source_code = ghostwriter.roundtrip(json.dumps, json.loads)\n    with pytest.raises(Unsatisfiable):\n        get_test_function(source_code)()\n\n    # Replacing that nothing() with a strategy for JSON allows us to discover\n    # two possible failures: `nan` is not equal to itself, and if dumps is\n    # passed allow_nan=False it is a ValueError to pass a non-finite float.\n    source_code = source_code.replace(\n        \"st.nothing()\",\n        \"st.recursive(st.one_of(st.none(), st.booleans(), st.floats(), st.text()), \"\n        \"lambda v: st.lists(v, max_size=2) | st.dictionaries(st.text(), v, max_size=2)\"\n        \", max_leaves=2)\",\n    )\n    s = settings(deadline=None, suppress_health_check=[HealthCheck.too_slow])\n    try:\n        get_test_function(source_code, settings_decorator=s)()\n    except (AssertionError, ValueError, BaseExceptionGroup):\n        pass\n\n    # Finally, restricting ourselves to finite floats makes the test pass!\n    source_code = source_code.replace(\n        \"st.floats()\", \"st.floats(allow_nan=False, allow_infinity=False)\"\n    )\n    get_test_function(source_code, settings_decorator=s)()\n\n\n@varied_excepts\n@pytest.mark.parametrize(\"func\", [sorted, timsort])\ndef test_ghostwriter_idempotent(func, ex):\n    source_code = ghostwriter.idempotent(func, except_=ex)\n    test = get_test_function(source_code)\n    if \"=st.nothing()\" in source_code:\n        with pytest.raises(Unsatisfiable):\n            test()\n    else:\n        test()\n\n\ndef test_overlapping_args_use_union_of_strategies():\n    def f(arg: int) -> None:\n        pass\n\n    def g(arg: float) -> None:\n        pass\n\n    source_code = ghostwriter.equivalent(f, g)\n    assert \"arg=st.one_of(st.integers(), st.floats())\" in source_code\n\n\ndef test_module_with_mock_does_not_break():\n    # Before we added an explicit check for unspec'd mocks, they would pass\n    # through the initial validation and then fail when used in more detailed\n    # logic in the ghostwriter machinery.\n    ghostwriter.magic(unittest.mock)\n\n\ndef compose_types(x: type, y: type):\n    pass\n\n\ndef test_unrepr_identity_elem():\n    # Works with inferred identity element\n    source_code = ghostwriter.binary_operation(compose_types)\n    exec(source_code, {})\n    # and also works with explicit identity element\n    source_code = ghostwriter.binary_operation(compose_types, identity=type)\n    exec(source_code, {})\n\n\n@pytest.mark.parametrize(\n    \"strategy, imports\",\n    # The specifics don't matter much here; we're just demonstrating that\n    # we can walk the strategy and collect all the objects to import.\n    [\n        # Lazy from_type() is handled without being unwrapped\n        (LazyStrategy(from_type, (enum.Enum,), {}), {(\"enum\", \"Enum\")}),\n        # Mapped, filtered, and flatmapped check both sides of the method\n        (\n            builds(enum.Enum).map(Decimal),\n            {(\"enum\", \"Enum\"), (\"decimal\", \"Decimal\")},\n        ),\n        (\n            builds(enum.Enum).flatmap(Decimal),\n            {(\"enum\", \"Enum\"), (\"decimal\", \"Decimal\")},\n        ),\n        (\n            builds(enum.Enum).filter(Decimal).filter(re.compile),\n            {(\"enum\", \"Enum\"), (\"decimal\", \"Decimal\"), (\"re\", \"compile\")},\n        ),\n        # one_of() strategies recurse into all the branches\n        (\n            builds(enum.Enum) | builds(Decimal) | builds(re.compile),\n            {(\"enum\", \"Enum\"), (\"decimal\", \"Decimal\"), (\"re\", \"compile\")},\n        ),\n        # and builds() checks the arguments as well as the target\n        (\n            builds(enum.Enum, builds(Decimal), kw=builds(re.compile)),\n            {(\"enum\", \"Enum\"), (\"decimal\", \"Decimal\"), (\"re\", \"compile\")},\n        ),\n        # lists recurse on imports\n        (\n            lists(builds(Decimal)),\n            {(\"decimal\", \"Decimal\")},\n        ),\n        # find the needed import for from_regex if needed\n        (\n            from_regex(re.compile(\".+\")),\n            {\"re\"},\n        ),\n        # but don't add superfluous imports\n        (\n            from_regex(\".+\"),\n            set(),\n        ),\n    ],\n)\ndef test_get_imports_for_strategy(strategy, imports):\n    assert ghostwriter._imports_for_strategy(strategy) == imports\n\n\n@pytest.fixture\ndef temp_script_file():\n    \"\"\"Fixture to yield a Path to a temporary file in the local directory. File name will end\n    in .py and will include an importable function.\n    \"\"\"\n    p = Path(\"my_temp_script.py\")\n    if p.exists():\n        raise FileExistsError(f\"Did not expect {p} to exist during testing\")\n    p.write_text(\n        dedent(\n            \"\"\"\n            def say_hello():\n                print(\"Hello world!\")\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    yield p\n    p.unlink()\n\n\n@pytest.fixture\ndef temp_script_file_with_py_function():\n    \"\"\"Fixture to yield a Path to a temporary file in the local directory. File name will end\n    in .py and will include an importable function named \"py\"\n    \"\"\"\n    p = Path(\"my_temp_script_with_py_function.py\")\n    if p.exists():\n        raise FileExistsError(f\"Did not expect {p} to exist during testing\")\n    p.write_text(\n        dedent(\n            \"\"\"\n            def py():\n                print('A function named \"py\" has been called')\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    yield p\n    p.unlink()\n\n\ndef test_obj_name(temp_script_file, temp_script_file_with_py_function):\n    # Module paths (strings including a \"/\") should raise a meaningful UsageError\n    with pytest.raises(click.exceptions.UsageError) as e:\n        cli.obj_name(\"mydirectory/myscript.py\")\n    assert e.match(\n        \"Remember that the ghostwriter should be passed the name of a module, not a path.\"\n    )\n    # Windows paths (strings including a \"\\\") should also raise a meaningful UsageError\n    with pytest.raises(click.exceptions.UsageError) as e:\n        cli.obj_name(R\"mydirectory\\myscript.py\")\n    assert e.match(\n        \"Remember that the ghostwriter should be passed the name of a module, not a path.\"\n    )\n    # File names of modules (strings ending in \".py\") should raise a meaningful UsageError\n    with pytest.raises(click.exceptions.UsageError) as e:\n        cli.obj_name(\"myscript.py\")\n    assert e.match(\n        \"Remember that the ghostwriter should be passed the name of a module, not a file.\"\n    )\n    # File names of modules (strings ending in \".py\") that exist should get a suggestion\n    with pytest.raises(click.exceptions.UsageError) as e:\n        cli.obj_name(str(temp_script_file))\n    assert e.match(\n        \"Remember that the ghostwriter should be passed the name of a module, not a file.\"\n        f\"\\n\\tTry: hypothesis write {temp_script_file.stem}\"\n    )\n    # File names of modules (strings ending in \".py\") that define a py function should succeed\n    assert isinstance(\n        cli.obj_name(str(temp_script_file_with_py_function)), FunctionType\n    )\n\n\ndef test_gets_public_location_not_impl_location():\n    assert ghostwriter._get_module(assume) == \"hypothesis\"  # not \"hypothesis.control\"\n\n\nclass ForwardRefA:\n    pass\n\n\n@pytest.mark.parametrize(\n    \"parameter, type_name\",\n    [\n        (ForwardRef(\"this_ref_does_not_exist\"), None),\n        # ForwardRef.evaluate() logic is new in 3.14\n        *(\n            []\n            if sys.version_info[:2] < (3, 14)\n            else [\n                (\n                    ForwardRef(\"ForwardRefA\", owner=A),\n                    ghostwriter._AnnotationData(\n                        \"test_ghostwriter.ForwardRefA\", {\"test_ghostwriter\"}\n                    ),\n                )\n            ]\n        ),\n    ],\n)\ndef test_parameter_to_annotation(parameter, type_name):\n    assert ghostwriter._parameter_to_annotation(parameter) == type_name\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/test_ghostwriter_cli.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport ast\nimport itertools\nimport json\nimport operator\nimport re\nimport subprocess\nimport sys\n\nimport pytest\n\nfrom hypothesis import settings, strategies as st\nfrom hypothesis.errors import StopTest\nfrom hypothesis.extra.ghostwriter import (\n    binary_operation,\n    equivalent,\n    fuzz,\n    idempotent,\n    magic,\n    roundtrip,\n)\nfrom hypothesis.internal.reflection import get_pretty_function_description\n\npytestmark = pytest.mark.skipif(\n    settings.get_current_profile_name() == \"threading\",\n    reason=\"ghostwriter is not thread safe\",\n)\n\n\ndef run(cmd, *, cwd=None):\n    return subprocess.run(\n        cmd, capture_output=True, shell=True, text=True, cwd=cwd, encoding=\"utf-8\"\n    )\n\n\n@pytest.mark.parametrize(\n    \"cli,code\",\n    [\n        # Passing one argument falls back to one-argument tests\n        (\"--equivalent re.compile\", lambda: fuzz(re.compile)),\n        (\"--roundtrip sorted\", lambda: idempotent(sorted)),\n        # For multiple arguments, they're equivalent to the function call\n        (\n            \"--equivalent eval ast.literal_eval\",\n            lambda: equivalent(eval, ast.literal_eval),\n        ),\n        (\n            \"--roundtrip json.loads json.dumps --except ValueError\",\n            lambda: roundtrip(json.loads, json.dumps, except_=ValueError),\n        ),\n        # Imports submodule (importlib.import_module passes; __import__ fails)\n        pytest.param(\n            \"hypothesis.strategies\",\n            lambda: magic(st),\n            marks=pytest.mark.skipif(sys.version_info[:2] != (3, 10), reason=\"varies\"),\n        ),\n        # We can write tests for classes even without classmethods or staticmethods\n        (\"hypothesis.errors.StopTest\", lambda: fuzz(StopTest)),\n        # Search for identity element does not print e.g. \"You can use @seed ...\"\n        (\"--binary-op operator.add\", lambda: binary_operation(operator.add)),\n        # Annotations are passed correctly\n        (\"sorted --annotate\", lambda: fuzz(sorted, annotate=True)),\n        (\"sorted --no-annotate\", lambda: fuzz(sorted, annotate=False)),\n    ],\n    ids=get_pretty_function_description,\n)\ndef test_cli_python_equivalence(cli, code):\n    result = run(\"hypothesis write \" + cli)\n    result.check_returncode()\n    cli_output = result.stdout.strip()\n    assert cli == \"hypothesis.strategies\" or not result.stderr\n    code_output = code().strip()\n    assert code_output == cli_output\n\n\n@pytest.mark.parametrize(\n    \"cli,err_msg\",\n    [\n        (\"--idempotent sorted sorted\", \"Test functions for idempotence one at a time.\"),\n        (\n            \"xxxx\",\n            \"Found the 'builtins' module, but it doesn't have a 'xxxx' attribute.\",\n        ),\n        (\n            \"re.srch\",\n            \"Found the 're' module, but it doesn't have a 'srch' attribute.  \"\n            \"Closest matches: ['search']\",\n        ),\n        (\n            \"re.fmatch\",\n            \"Found the 're' module, but it doesn't have a 'fmatch' attribute.  \"\n            \"Closest matches: ['match', 'fullmatch'\",\n            # Python >= 3.7 has 'Match' objects too\n        ),\n    ],\n)\ndef test_cli_too_many_functions(cli, err_msg):\n    # Supplying multiple functions to writers that only cope with one\n    result = run(\"hypothesis write \" + cli)\n    assert result.returncode == 2\n    assert \"Error: \" + err_msg in result.stderr\n    assert (\"Closest matches\" in err_msg) == (\"Closest matches\" in result.stderr)\n\n\nCODE_TO_TEST = \"\"\"\nfrom typing import Sequence, List\n\ndef sorter(seq: Sequence[int]) -> List[int]:\n    return sorted(seq)\n\"\"\"\n\n\ndef test_can_import_from_scripts_in_working_dir(tmp_path):\n    (tmp_path / \"mycode.py\").write_text(CODE_TO_TEST, encoding=\"utf-8\")\n    result = run(\"hypothesis write mycode.sorter\", cwd=tmp_path)\n    assert result.returncode == 0\n    assert \"Error: \" not in result.stderr\n\n\nCLASS_CODE_TO_TEST = \"\"\"\nfrom typing import Sequence, List\n\ndef my_func(seq: Sequence[int]) -> List[int]:\n    return sorted(seq)\n\nclass MyClass:\n\n    @staticmethod\n    def my_staticmethod(seq: Sequence[int]) -> List[int]:\n        return sorted(seq)\n\n    @classmethod\n    def my_classmethod(cls, seq: Sequence[int]) -> List[int]:\n        return sorted(seq)\n\"\"\"\n\n\n@pytest.mark.parametrize(\"func\", [\"my_staticmethod\", \"my_classmethod\"])\ndef test_can_import_from_class(tmp_path, func):\n    (tmp_path / \"mycode.py\").write_text(CLASS_CODE_TO_TEST, encoding=\"utf-8\")\n    result = run(f\"hypothesis write mycode.MyClass.{func}\", cwd=tmp_path)\n    assert result.returncode == 0\n    assert \"Error: \" not in result.stderr\n\n\n@pytest.mark.parametrize(\n    \"classname,thing,kind\",\n    [\n        (\"XX\", \"\", \"class\"),\n        (\"MyClass\", \" and 'MyClass' class\", \"attribute\"),\n        (\"my_func\", \" and 'my_func' attribute\", \"attribute\"),\n    ],\n)\ndef test_error_import_from_class(tmp_path, classname, thing, kind):\n    (tmp_path / \"mycode.py\").write_text(CLASS_CODE_TO_TEST, encoding=\"utf-8\")\n    result = run(f\"hypothesis write mycode.{classname}.XX\", cwd=tmp_path)\n    msg = f\"Error: Found the 'mycode' module{thing}, but it doesn't have a 'XX' {kind}.\"\n    assert result.returncode == 2\n    assert msg in result.stderr\n\n\ndef test_magic_discovery_from_module(tmp_path):\n    (tmp_path / \"mycode.py\").write_text(CLASS_CODE_TO_TEST, encoding=\"utf-8\")\n    result = run(\"hypothesis write mycode\", cwd=tmp_path)\n    assert result.returncode == 0\n    assert \"my_func\" in result.stdout\n    assert \"MyClass.my_staticmethod\" in result.stdout\n    assert \"MyClass.my_classmethod\" in result.stdout\n\n\nROUNDTRIP_CODE_TO_TEST = \"\"\"\nfrom typing import Union\nimport json\n\ndef to_json(json: Union[dict,list]) -> str:\n    return json.dumps(json)\n\ndef from_json(json: str) -> Union[dict,list]:\n    return json.loads(json)\n\nclass MyClass:\n\n    @staticmethod\n    def to_json(json: Union[dict,list]) -> str:\n        return json.dumps(json)\n\n    @staticmethod\n    def from_json(json: str) -> Union[dict,list]:\n        return json.loads(json)\n\nclass OtherClass:\n\n    @classmethod\n    def to_json(cls, json: Union[dict,list]) -> str:\n        return json.dumps(json)\n\n    @classmethod\n    def from_json(cls, json: str) -> Union[dict,list]:\n        return json.loads(json)\n\"\"\"\n\n\ndef test_roundtrip_correct_pairs(tmp_path):\n    (tmp_path / \"mycode.py\").write_text(ROUNDTRIP_CODE_TO_TEST, encoding=\"utf-8\")\n    result = run(\"hypothesis write mycode\", cwd=tmp_path)\n    assert result.returncode == 0\n    for scope1, scope2 in itertools.product(\n        [\"mycode.MyClass\", \"mycode.OtherClass\", \"mycode\"], repeat=2\n    ):\n        round_trip_code = f\"\"\"value0 = {scope1}.to_json(json=json)\n    value1 = {scope2}.from_json(json=value0)\"\"\"\n        if scope1 == scope2:\n            assert round_trip_code in result.stdout\n        else:\n            assert round_trip_code not in result.stdout\n\n\ndef test_empty_module_is_not_error(tmp_path):\n    (tmp_path / \"mycode.py\").write_text(\"# Nothing to see here\\n\", encoding=\"utf-8\")\n    result = run(\"hypothesis write mycode\", cwd=tmp_path)\n    assert result.returncode == 0\n    assert \"Error: \" not in result.stderr\n    assert \"# Found no testable functions\" in result.stdout\n"
  },
  {
    "path": "hypothesis-python/tests/ghostwriter/try-writing-for-installed.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"Try running `hypothesis write ...` on all available modules.\n\nPrints a list of module names which caused some kind of internal error.\n\nThe idea here is to check that we at least don't crash on anything that\npeople actually ship, or at least only on the cases we know and don't\nreally care about - there are a lot of strange things in a python install.\nSome have import-time side effects or errors so we skip them; others\njust have such weird semantics that we don't _want_ to support them.\n\"\"\"\n\nimport multiprocessing\nimport os\nimport subprocess\nimport sysconfig\n\nskip = (\n    \"idlelib curses antigravity pip prompt_toolkit IPython .popen_ django. .test. \"\n    \"execnet.script lib2to3.pgen2.conv tests. Cython. ~ - ._ libcst.codemod. \"\n    \"modernize flask. sphinx. pyasn1 dbm.ndbm doctest\"\n).split()\n\n\ndef getmodules():\n    std_lib = sysconfig.get_python_lib(standard_lib=True)\n    for top, _, files in os.walk(std_lib):\n        for nm in files:\n            if nm.endswith(\".py\") and nm not in (\"__init__.py\", \"__main__.py\"):\n                modname = (\n                    os.path.join(top, nm)[len(std_lib) + 1 : -3]\n                    .replace(os.sep, \".\")\n                    .replace(\"site-packages.\", \"\")\n                )\n                if not any(bad in modname for bad in skip):\n                    yield modname\n\n\ndef write_for(mod):\n    try:\n        subprocess.run(\n            [\"hypothesis\", \"write\", mod],\n            check=True,\n            capture_output=True,\n            timeout=10,\n            text=True,\n            encoding=\"utf-8\",\n        )\n    except subprocess.SubprocessError as e:\n        # Only report the error if we could load _but not process_ the module\n        if (\n            \"Error: Found the '\" not in e.stderr\n            and \"Error: Failed to import\" not in e.stderr\n        ):\n            return mod\n\n\nif __name__ == \"__main__\":\n    print(\"# prints the names of modules for which `hypothesis write` errors out\")\n    with multiprocessing.Pool() as pool:\n        for name in pool.imap(write_for, getmodules()):\n            if name is not None:\n                print(name, flush=True)\n"
  },
  {
    "path": "hypothesis-python/tests/lark/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/lark/test_grammar.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport json\n\nimport pytest\nfrom lark.lark import Lark\n\nfrom hypothesis import given\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra.lark import from_lark\nfrom hypothesis.strategies import characters, data, just\n\nfrom tests.common.debug import check_can_generate_examples, find_any\n\n# Adapted from the official Lark tutorial, with modifications to ensure\n# that the generated JSON is valid.  i.e. no numbers starting with \".\",\n# \\f is not ignorable whitespace, and restricted strings only.  Source:\n# https://github.com/lark-parser/lark/blob/master/docs/json_tutorial.md\nEBNF_GRAMMAR = r\"\"\"\n    value: dict\n         | list\n         | STRING\n         | NUMBER\n         | \"true\"  -> true\n         | \"false\" -> false\n         | \"null\"  -> null\n    list : \"[\" [value (\",\" value)*] \"]\"\n    dict : \"{\" [STRING \":\" value (\",\" STRING \":\" value)*] \"}\"\n\n    STRING : /\"[a-z]*\"/\n    NUMBER : /-?[1-9][0-9]*(\\.[0-9]+)?([eE][+-]?[0-9]+)?/\n\n    WS : /[ \\t\\r\\n]+/\n    %ignore WS\n\"\"\"\n\nLIST_GRAMMAR = r\"\"\"\nlist : \"[\" [NUMBER (\",\" NUMBER)*] \"]\"\nNUMBER: /[0-9]|[1-9][0-9]*/\n\"\"\"\n\n\n@given(from_lark(Lark(EBNF_GRAMMAR, start=\"value\")))\ndef test_generates_valid_json(string):\n    json.loads(string)\n\n\n@pytest.mark.parametrize(\n    \"start, type_\",\n    [\n        (\"dict\", dict),\n        (\"list\", list),\n        (\"STRING\", str),\n        (\"NUMBER\", (int, float)),\n        (\"TRUE\", bool),\n        (\"FALSE\", bool),\n        (\"NULL\", type(None)),\n    ],\n)\n@given(data=data())\ndef test_can_specify_start_rule(data, start, type_):\n    string = data.draw(from_lark(Lark(EBNF_GRAMMAR, start=\"value\"), start=start))\n    value = json.loads(string)\n    assert isinstance(value, type_)\n\n\ndef test_can_generate_ignored_tokens():\n    list_grammar = r\"\"\"\n    list : \"[\" [STRING (\",\" STRING)*] \"]\"\n    STRING : /\"[a-z]*\"/\n    WS : /[ \\t\\r\\n]+/\n    %ignore WS\n    \"\"\"\n    strategy = from_lark(Lark(list_grammar, start=\"list\"))\n    # A JSON list of strings in canonical form which does not round-trip,\n    # must contain ignorable whitespace in the initial string.\n    find_any(strategy, lambda s: \"\\t\" in s)\n\n\ndef test_generation_without_whitespace():\n    find_any(from_lark(Lark(LIST_GRAMMAR, start=\"list\")), lambda g: \" \" not in g)\n\n\ndef test_cannot_convert_EBNF_to_strategy_directly():\n    with pytest.raises(InvalidArgument):\n        # Not a Lark object\n        check_can_generate_examples(from_lark(EBNF_GRAMMAR))\n    with pytest.raises(TypeError):\n        # Not even the right number of arguments\n        check_can_generate_examples(from_lark(EBNF_GRAMMAR, start=\"value\"))\n    with pytest.raises(InvalidArgument):\n        # Wrong type for explicit_strategies\n        check_can_generate_examples(\n            from_lark(Lark(LIST_GRAMMAR, start=\"list\"), explicit=[])\n        )\n\n\ndef test_required_undefined_terminals_require_explicit_strategies():\n    elem_grammar = r\"\"\"\n    list : \"[\" ELEMENT (\",\" ELEMENT)* \"]\"\n    %declare ELEMENT\n    \"\"\"\n    with pytest.raises(InvalidArgument, match=r\"%declare\"):\n        check_can_generate_examples(from_lark(Lark(elem_grammar, start=\"list\")))\n    strategy = {\"ELEMENT\": just(\"200\")}\n    check_can_generate_examples(\n        from_lark(Lark(elem_grammar, start=\"list\"), explicit=strategy)\n    )\n\n\ndef test_cannot_use_explicit_strategies_for_unknown_terminals():\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(\n            from_lark(\n                Lark(LIST_GRAMMAR, start=\"list\"), explicit={\"unused_name\": just(\"\")}\n            )\n        )\n\n\ndef test_non_string_explicit_strategies_are_invalid():\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(\n            from_lark(Lark(LIST_GRAMMAR, start=\"list\"), explicit={\"NUMBER\": just(0)})\n        )\n\n\n@given(\n    string=from_lark(Lark(LIST_GRAMMAR, start=\"list\"), explicit={\"NUMBER\": just(\"0\")})\n)\ndef test_can_override_defined_terminal(string):\n    assert sum(json.loads(string)) == 0\n\n\n@given(string=from_lark(Lark(LIST_GRAMMAR, start=\"list\"), alphabet=\"[0,]\"))\ndef test_can_generate_from_limited_alphabet(string):\n    assert sum(json.loads(string)) == 0\n\n\n@given(string=from_lark(Lark(LIST_GRAMMAR, start=\"list\"), alphabet=\"[9]\"))\ndef test_can_generate_from_limited_alphabet_no_comma(string):\n    assert len(json.loads(string)) <= 1\n\n\n@given(\n    string=from_lark(\n        Lark(EBNF_GRAMMAR, start=\"value\"),\n        alphabet=characters(codec=\"ascii\", exclude_characters=\",\"),\n    )\n)\ndef test_can_generate_from_limited_alphabet_no_comma_json(string):\n    assert \",\" not in string\n\n\ndef test_error_if_alphabet_bans_all_start_rules():\n    with pytest.raises(\n        InvalidArgument, match=r\"No start rule .+ is allowed by alphabet=\"\n    ):\n        check_can_generate_examples(\n            from_lark(Lark(LIST_GRAMMAR, start=\"list\"), alphabet=\"abc\")\n        )\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_argument_validation.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport inspect\nfrom inspect import Parameter\n\nimport pytest\n\nfrom hypothesis import strategies as st\nfrom hypothesis.strategies._internal.utils import _all_strategies\n\nfrom tests.common.arguments import argument_validation_test, e\n\nBAD_ARGS = []\n\n\ndef adjust(ex, **kwargs):\n    f, a, b = ex\n    b = dict(b)\n    b.update(kwargs)\n    BAD_ARGS.append((f, a, b))\n\n\nfor ex in [\n    e(st.lists, st.integers()),\n    e(st.sets, st.integers()),\n    e(st.frozensets, st.integers()),\n    e(st.dictionaries, st.integers(), st.integers()),\n    e(st.text),\n    e(st.binary),\n]:\n    adjust(ex, min_size=-1)\n    adjust(ex, max_size=-1)\n    adjust(ex, min_size=\"no\")\n    adjust(ex, max_size=\"no\")\n\n\nBAD_ARGS.extend([e(st.lists, st.nothing(), unique=True, min_size=1)])\n\ntest_raise_invalid_argument = argument_validation_test(BAD_ARGS)\n\n\n@pytest.mark.parametrize(\"name\", sorted(_all_strategies))\ndef test_consistent_with_api_guide_on_kwonly_args(name):\n    # Enforce our style-guide: if it has a default value, it should be\n    # keyword-only, with a few exceptions.\n    strategy = _all_strategies[name]\n    for arg in inspect.signature(strategy).parameters.values():\n        assert (\n            arg.default == Parameter.empty\n            or arg.kind != Parameter.POSITIONAL_OR_KEYWORD\n            or arg.name in (\"min_value\", \"max_value\", \"subtype_strategy\", \"columns\")\n            or name in (\"text\", \"range_indexes\", \"badly_draw_lists\", \"write_pattern\")\n        ), f\"need kwonly args in {name}\"\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_bad_repr.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, strategies as st\n\n\nclass BadRepr:\n    def __init__(self, value):\n        self.value = value\n\n    def __repr__(self):\n        return self.value\n\n\nFrosty = BadRepr(\"☃\")\n\n\ndef test_just_frosty():\n    assert repr(st.just(Frosty)) == \"just(☃)\"\n\n\ndef test_sampling_snowmen():\n    assert repr(st.sampled_from((Frosty, \"hi\"))) == \"sampled_from((☃, 'hi'))\"\n\n\ndef varargs(*args, **kwargs):\n    pass\n\n\n@given(\n    st.sampled_from(\n        [\n            \"✐\",\n            \"✑\",\n            \"✒\",\n            \"✓\",\n            \"✔\",\n            \"✕\",\n            \"✖\",\n            \"✗\",\n            \"✘\",\n            \"✙\",\n            \"✚\",\n            \"✛\",\n            \"✜\",\n            \"✝\",\n            \"✞\",\n            \"✟\",\n            \"✠\",\n            \"✡\",\n            \"✢\",\n            \"✣\",\n        ]\n    )\n)\ndef test_sampled_from_bad_repr(c):\n    pass\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_baseexception.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given\nfrom hypothesis.errors import Flaky, FlakyFailure\nfrom hypothesis.strategies import composite, integers, none\n\nfrom tests.common.utils import Why, skipif_threading, xfail_on_crosshair\n\n\n@pytest.mark.parametrize(\n    \"e\", [KeyboardInterrupt, SystemExit, GeneratorExit, ValueError]\n)\ndef test_exception_propagates_fine(e):\n    @given(integers())\n    def test_raise(x):\n        raise e\n\n    with pytest.raises(e):\n        test_raise()\n\n\n@pytest.mark.parametrize(\n    \"e\", [KeyboardInterrupt, SystemExit, GeneratorExit, ValueError]\n)\ndef test_exception_propagates_fine_from_strategy(e):\n    @composite\n    def interrupt_eventually(draw):\n        raise e\n        # this line will not be executed, but must be here\n        # to pass draw function static reference check\n        return draw(none())\n\n    @given(interrupt_eventually())\n    def test_do_nothing(x):\n        pass\n\n    with pytest.raises(e):\n        test_do_nothing()\n\n\n@xfail_on_crosshair(Why.other, strict=False)  # extra replay from backend switch\n@pytest.mark.parametrize(\"e\", [KeyboardInterrupt, ValueError])\ndef test_baseexception_no_rerun_no_flaky(e):\n    runs = 0\n    interrupt = 3\n\n    @given(integers())\n    def test_raise_baseexception(x):\n        nonlocal runs\n        runs += 1\n        if runs == interrupt:\n            raise e\n\n    if issubclass(e, (KeyboardInterrupt, SystemExit, GeneratorExit)):\n        # Here SystemExit and GeneratorExit are passed through\n        with pytest.raises(e):\n            test_raise_baseexception()\n\n        assert runs == interrupt\n    else:\n        with pytest.raises(FlakyFailure):\n            test_raise_baseexception()\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)  # KI and GE only\n@pytest.mark.parametrize(\n    \"e\", [KeyboardInterrupt, SystemExit, GeneratorExit, ValueError]\n)\ndef test_baseexception_in_strategy_no_rerun_no_flaky(e):\n    runs = 0\n    interrupt = 3\n\n    @composite\n    def interrupt_eventually(draw):\n        nonlocal runs\n        runs += 1\n        if runs == interrupt:\n            raise e\n        return draw(integers())\n\n    @given(interrupt_eventually())\n    def test_do_nothing(x):\n        pass\n\n    if issubclass(e, KeyboardInterrupt):\n        with pytest.raises(e):\n            test_do_nothing()\n\n        assert runs == interrupt\n\n    else:\n        # Now SystemExit and GeneratorExit are caught like other exceptions\n        with pytest.raises(Flaky):\n            test_do_nothing()\n\n\nTEMPLATE = \"\"\"\nfrom hypothesis import given, note, strategies as st\n\n@st.composite\ndef things(draw):\n    raise {exception}\n    # this line will not be executed, but must be here\n    # to pass draw function static reference check\n    return draw(st.none())\n\n\n@given(st.data(), st.integers())\ndef test(data, x):\n    if x > 100:\n        data.draw({strategy})\n        raise {exception}\n\"\"\"\n\n\n@skipif_threading  # something in pytest here is not thread safe\n@pytest.mark.parametrize(\"exc_name\", [\"SystemExit\", \"GeneratorExit\"])\n@pytest.mark.parametrize(\"use_composite\", [True, False])\ndef test_explanations(testdir, exc_name, use_composite):\n    code = TEMPLATE.format(\n        exception=exc_name, strategy=\"things()\" if use_composite else \"st.none()\"\n    )\n    test_file = str(testdir.makepyfile(code))\n    pytest_stdout = str(testdir.runpytest_inprocess(test_file, \"--tb=native\").stdout)\n    assert \"x=101\" in pytest_stdout\n    assert exc_name in pytest_stdout\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_boundary_exploration.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import HealthCheck, Verbosity, given, reject, settings, strategies as st\nfrom hypothesis.errors import Unsatisfiable\n\nfrom tests.common.debug import minimal\nfrom tests.common.utils import no_shrink\n\n\n@pytest.mark.parametrize(\"strat\", [st.text(min_size=5)])\n@settings(phases=no_shrink, deadline=None, suppress_health_check=list(HealthCheck))\n@given(st.data())\ndef test_explore_arbitrary_function(strat, data):\n    cache = {}\n\n    def predicate(x):\n        try:\n            return cache[x]\n        except KeyError:\n            return cache.setdefault(x, data.draw(st.booleans(), label=repr(x)))\n\n    try:\n        minimal(\n            strat,\n            predicate,\n            settings=settings(\n                max_examples=10, database=None, verbosity=Verbosity.quiet\n            ),\n        )\n    except Unsatisfiable:\n        reject()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_build_signature.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom inspect import signature\nfrom typing import get_type_hints\n\nfrom hypothesis import given, strategies as st\n\nfrom tests.common.debug import find_any\n\n\ndef use_this_signature(self, a: int, b: list | None = None, *, x: float, y: str):\n    pass\n\n\nclass Model:\n    # Emulates the implementation of Pydantic models.  See e.g.\n    # https://github.com/timothycrosley/hypothesis-auto/issues/10\n    __annotations__ = get_type_hints(use_this_signature)\n    __signature__ = signature(use_this_signature)\n\n    def __init__(self, **kwargs):\n        # Check that we're being called with the expected arguments\n        assert set(kwargs) == {\"a\", \"x\", \"y\"}\n        assert isinstance(kwargs[\"a\"], int)\n        assert isinstance(kwargs[\"x\"], float)\n        assert isinstance(kwargs[\"y\"], str)\n\n\n@given(st.builds(Model))\ndef test_builds_uses_signature_attribute(val):\n    assert isinstance(val, Model)\n\n\nclass ModelForFromType(Model):\n    def __init__(self, **kwargs):\n        assert set(kwargs) == {\"a\", \"b\", \"x\", \"y\"}\n        self.b = kwargs[\"b\"]\n        assert self.b is None or isinstance(self.b, list)\n\n\n@given(st.from_type(ModelForFromType))\ndef test_from_type_uses_signature_attribute(val):\n    assert isinstance(val, ModelForFromType)\n\n\ndef test_from_type_can_be_default_or_annotation():\n    find_any(st.from_type(ModelForFromType), lambda m: m.b is None)\n    find_any(st.from_type(ModelForFromType), lambda m: isinstance(m.b, list))\n\n\ndef use_annotations(\n    self, test_a: int, test_b: str | None = None, *, test_x: float, test_y: str\n):\n    pass\n\n\ndef use_signature(\n    self, testA: int, testB: str | None = None, *, testX: float, testY: list[str]\n):\n    pass\n\n\nclass ModelWithAlias:\n    __annotations__ = get_type_hints(use_annotations)\n    __signature__ = signature(use_signature)\n\n    def __init__(self, **kwargs):\n        # Check that we're being called with the expected arguments\n        assert set(kwargs) == {\"testA\", \"testX\", \"testY\"}\n        assert isinstance(kwargs[\"testA\"], int)\n        assert isinstance(kwargs[\"testX\"], float)\n        assert isinstance(kwargs[\"testY\"], list)\n        assert all(isinstance(elem, str) for elem in kwargs[\"testY\"])\n\n\n@given(st.builds(ModelWithAlias))\ndef test_build_using_different_signature_and_annotations(val):\n    assert isinstance(val, ModelWithAlias)\n\n\ndef use_bad_signature(self, testA: 1, *, testX: float):\n    pass\n\n\nclass ModelWithBadAliasSignature:\n    __annotations__ = get_type_hints(use_annotations)\n    __signature__ = signature(use_bad_signature)\n\n    def __init__(self, **kwargs):\n        assert set(kwargs) == {\"testX\"}\n        assert isinstance(kwargs[\"testX\"], float)\n\n\n@given(st.builds(ModelWithBadAliasSignature))\ndef test_build_with_non_types_in_signature(val):\n    assert isinstance(val, ModelWithBadAliasSignature)\n\n\nclass UnconventionalSignature:\n    def __init__(x: int = 0, self: bool = True):  # noqa\n        assert not isinstance(x, int)\n        x.self = self\n\n\ndef test_build_in_from_type_with_self_named_something_else():\n    find_any(st.from_type(UnconventionalSignature), lambda x: x.self is True)\n    find_any(st.from_type(UnconventionalSignature), lambda x: x.self is False)\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_cache_implementation.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections import Counter\n\nfrom hypothesis import strategies as st\nfrom hypothesis.internal.cache import GenericCache\nfrom hypothesis.stateful import (\n    Bundle,\n    RuleBasedStateMachine,\n    initialize,\n    invariant,\n    rule,\n)\n\n\nclass CacheWithScores(GenericCache):\n    def __init__(self, max_size):\n        super().__init__(max_size)\n        self.scores = {}\n\n    def new_entry(self, key, value):\n        return self.scores[key]\n\n\nclass CacheRules(RuleBasedStateMachine):\n    keys = Bundle(\"keys\")\n\n    @initialize(max_size=st.integers(1, 8))\n    def create_cache(self, max_size):\n        self.cache = CacheWithScores(max_size)\n        self.__values = {}\n\n        self.__total_pins = 0\n        self.__pins = Counter()\n        self.__live = set()\n        self.__next_value = 0\n        self.__last_key = None\n\n        def on_evict(evicted_key, value, score):\n            assert self.__pins[evicted_key] == 0\n            assert score == self.cache.scores[evicted_key]\n            assert value == self.__values[evicted_key]\n            for k in self.cache:\n                assert (\n                    self.__pins[k] > 0\n                    or self.cache.scores[k] >= score\n                    or k == self.__last_key\n                )\n\n        self.cache.on_evict = on_evict\n\n    @rule(key=st.integers(), score=st.integers(0, 100), target=keys)\n    def new_key(self, key, score):\n        if key not in self.cache.scores:\n            self.cache.scores[key] = score\n        return key\n\n    @rule(key=keys)\n    def set_key(self, key):\n        if self.__total_pins < self.cache.max_size or key in self.cache:\n            self.__last_key = key\n            self.cache[key] = self.__next_value\n            self.__values[key] = self.__next_value\n            self.__next_value += 1\n\n    @invariant()\n    def check_values(self):\n        self.cache.check_valid()\n        for key in self.cache:\n            assert self.__values[key] == self.cache[key]\n\n    @rule(key=keys)\n    def pin_key(self, key):\n        if key in self.cache:\n            self.cache.pin(key, self.__values[key])\n            if self.__pins[key] == 0:\n                self.__total_pins += 1\n            self.__pins[key] += 1\n\n    @rule(key=keys)\n    def unpin_key(self, key):\n        if self.__pins[key] > 0:\n            self.cache.unpin(key)\n            self.__pins[key] -= 1\n            if self.__pins[key] == 0:\n                self.__total_pins -= 1\n                assert self.__total_pins >= 0\n\n\nTestCache = CacheRules.TestCase\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_cacheable.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport gc\nimport weakref\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\n\nfrom tests.common.utils import xfail_if_gil_disabled\n\n\n@pytest.mark.parametrize(\n    \"s\",\n    [\n        st.floats(),\n        st.tuples(st.integers()),\n        st.tuples(),\n        st.one_of(st.integers(), st.text()),\n    ],\n)\ndef test_is_cacheable(s):\n    assert s.is_cacheable\n\n\n@pytest.mark.parametrize(\n    \"s\",\n    [\n        st.just([]),\n        st.tuples(st.integers(), st.just([])),\n        st.one_of(st.integers(), st.text(), st.just([])),\n    ],\n)\ndef test_is_not_cacheable(s):\n    assert not s.is_cacheable\n\n\ndef test_non_cacheable_things_are_not_cached():\n    x = st.just([])\n    assert st.tuples(x) != st.tuples(x)\n\n\ndef test_cacheable_things_are_cached():\n    x = st.just(())\n    assert st.tuples(x) == st.tuples(x)\n\n\n@xfail_if_gil_disabled\ndef test_local_types_are_garbage_collected_issue_493():\n    store = None\n\n    def run_locally():\n        class Test:\n            @settings(database=None)\n            @given(st.integers())\n            def test(self, i):\n                pass\n\n        nonlocal store\n        store = weakref.ref(Test)\n        Test().test()\n\n    run_locally()\n    del run_locally\n    assert store() is not None\n    gc.collect()\n    assert store() is None\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_characters.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport string\nfrom encodings.aliases import aliases\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\n\nfrom tests.common.utils import Why, xfail_on_crosshair\n\nIDENTIFIER_CHARS = string.ascii_letters + string.digits + \"_\"\n\n\n@given(st.characters(exclude_characters=IDENTIFIER_CHARS))\ndef test_large_blacklist(c):\n    assert c not in IDENTIFIER_CHARS\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context)  # seems like a crosshair bug here\n@given(st.data())\ndef test_arbitrary_blacklist(data):\n    blacklist = data.draw(st.text(st.characters(max_codepoint=1000), min_size=1))\n    ords = list(map(ord, blacklist))\n    c = data.draw(\n        st.characters(\n            exclude_characters=blacklist,\n            min_codepoint=max(0, min(ords) - 1),\n            max_codepoint=max(0, max(ords) + 1),\n        )\n    )\n    assert c not in blacklist\n\n\ndef _enc(cdc):\n    try:\n        \"\".encode(cdc)\n        return True\n    except Exception:\n        return False\n\n\nlots_of_encodings = sorted(x for x in set(aliases).union(aliases.values()) if _enc(x))\nassert len(lots_of_encodings) > 100  # sanity-check\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"takes 2000s; large & slow symbolic strings\",\n)\n@given(data=st.data(), codec=st.sampled_from(lots_of_encodings))\n@settings(max_examples=5)\ndef test_can_constrain_characters_to_codec(data, codec):\n    s = data.draw(st.text(st.characters(codec=codec), min_size=25))\n    s.encode(codec)\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_collective_minimization.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import Phase, settings\nfrom hypothesis.errors import Unsatisfiable\nfrom hypothesis.strategies import lists\n\nfrom tests.common import standard_types\nfrom tests.common.debug import minimal\n\n\n@pytest.mark.parametrize(\"spec\", standard_types, ids=repr)\ndef test_can_collectively_minimize(spec):\n    n = 10\n    try:\n        xs = minimal(\n            lists(spec, min_size=n, max_size=n),\n            lambda x: len(set(map(repr, x))) >= 2,\n            settings(max_examples=2000, phases=(Phase.generate, Phase.shrink)),\n        )\n        assert len(xs) == n\n        assert 2 <= len(set(map(repr, xs))) <= 3\n    except Unsatisfiable:\n        pass\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_compat.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.internal.compat import ceil, floor, int_from_bytes, int_to_bytes\n\n\n@given(st.binary())\ndef test_convert_back(bs):\n    bs = bytearray(bs)\n    assert int_to_bytes(int_from_bytes(bs), len(bs)) == bs\n\n\nbytes8 = st.builds(bytearray, st.binary(min_size=8, max_size=8))\n\n\n@given(bytes8, bytes8)\ndef test_to_int_in_big_endian_order(x, y):\n    x, y = sorted((x, y))\n    assert 0 <= int_from_bytes(x) <= int_from_bytes(y)\n\n\nints8 = st.integers(min_value=0, max_value=2**63 - 1)\n\n\n@given(ints8, ints8)\ndef test_to_bytes_in_big_endian_order(x, y):\n    x, y = sorted((x, y))\n    assert int_to_bytes(x, 8) <= int_to_bytes(y, 8)\n\n\n@given(st.fractions())\ndef test_ceil(x):\n    assert isinstance(ceil(x), int)\n    assert x <= ceil(x) < x + 1\n    assert ceil(x) == math.ceil(x)\n\n\n@given(st.fractions())\ndef test_floor(x):\n    assert isinstance(floor(x), int)\n    assert x - 1 < floor(x) <= x\n    assert floor(x) == math.floor(x)\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_completion.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, strategies as st\n\n\n@given(st.data())\ndef test_never_draw_anything(data):\n    pass\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_complex_numbers.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\n\n\n@pytest.mark.parametrize(\"width\", [32, 64, 128])\n@pytest.mark.parametrize(\"keyword\", [\"min_magnitude\", \"max_magnitude\"])\n@given(data=st.data())\ndef test_magnitude_validates(width, keyword, data):\n    # See https://github.com/HypothesisWorks/hypothesis/issues/3573\n    component_width = width / 2\n    magnitude = data.draw(\n        # 1.8 is a known example that hasn't validated in the past\n        st.floats(0, width=component_width) | st.just(1.8),\n        label=keyword,\n    )\n    strat = st.complex_numbers(width=width, **{keyword: magnitude})\n    data.draw(strat)\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_conjecture_engine.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis.database import InMemoryExampleDatabase, choices_from_bytes\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.conjecture.engine import ConjectureRunner\nfrom hypothesis.internal.conjecture.shrinker import Shrinker\n\nfrom tests.common.utils import (\n    Why,\n    counts_calls,\n    non_covering_examples,\n    xfail_on_crosshair,\n)\nfrom tests.conjecture.common import interesting_origin, run_to_nodes, shrinking_from\n\n\n@xfail_on_crosshair(Why.nested_given)\ndef test_lot_of_dead_nodes():\n    @run_to_nodes\n    def nodes(data):\n        for i in range(4):\n            if data.draw_integer(0, 2**7 - 1) != i:\n                data.mark_invalid()\n        data.mark_interesting(interesting_origin())\n\n    assert tuple(n.value for n in nodes) == (0, 1, 2, 3)\n\n\ndef test_saves_data_while_shrinking(monkeypatch):\n    key = b\"hi there\"\n    n = 5\n    db = InMemoryExampleDatabase()\n    assert list(db.fetch(key)) == []\n    seen = set()\n\n    monkeypatch.setattr(\n        ConjectureRunner,\n        \"generate_new_examples\",\n        lambda runner: runner.cached_test_function([bytes([255] * 10)]),\n    )\n\n    def f(data):\n        x = data.draw_bytes(10, 10)\n        if sum(x) >= 2000 and len(seen) < n:\n            seen.add(x)\n        if x in seen:\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(f, settings=settings(database=db), database_key=key)\n    runner.run()\n    assert runner.interesting_examples\n    assert len(seen) == n\n\n    in_db = {choices_from_bytes(b)[0] for b in non_covering_examples(db)}\n    assert in_db.issubset(seen)\n    assert in_db == seen\n\n\ndef test_can_discard(monkeypatch):\n    n = 8\n\n    monkeypatch.setattr(\n        ConjectureRunner,\n        \"generate_new_examples\",\n        lambda runner: runner.cached_test_function(\n            tuple(bytes(v) for i in range(n) for v in [i, i])\n        ),\n    )\n\n    @run_to_nodes\n    def nodes(data):\n        seen = set()\n        while len(seen) < n:\n            seen.add(data.draw_bytes())\n        data.mark_interesting(interesting_origin())\n\n    assert len(nodes) == n\n\n\n@xfail_on_crosshair(Why.nested_given)\n@given(st.integers(0, 255), st.integers(0, 255))\ndef test_cached_with_masked_byte_agrees_with_results(a, b):\n    def f(data):\n        data.draw_integer(0, 3)\n\n    runner = ConjectureRunner(f)\n\n    cached_a = runner.cached_test_function([a])\n    cached_b = runner.cached_test_function([b])\n\n    data_b = ConjectureData.for_choices([b], observer=runner.tree.new_observer())\n    runner.test_function(data_b)\n\n    # If the cache found an old result, then it should match the real result.\n    # If it did not, then it must be because A and B were different.\n    assert (cached_a is cached_b) == (cached_a.nodes == data_b.nodes)\n\n\ndef test_node_programs_fail_efficiently(monkeypatch):\n    # Create 256 byte-sized nodes. None of the nodes can be deleted, and\n    # every deletion attempt produces a different buffer.\n    @shrinking_from(range(256))\n    def shrinker(data: ConjectureData):\n        values = set()\n        for _ in range(256):\n            v = data.draw_integer(0, 2**8 - 1)\n            values.add(v)\n        if len(values) == 256:\n            data.mark_interesting(interesting_origin())\n\n    monkeypatch.setattr(\n        Shrinker, \"run_node_program\", counts_calls(Shrinker.run_node_program)\n    )\n    shrinker.max_stall = 500\n    shrinker.fixate_shrink_passes([shrinker.node_program(\"XX\")])\n\n    assert shrinker.shrinks == 0\n    assert 250 <= shrinker.calls <= 260\n    # The node program should have been run roughly 255 times, with a little\n    # bit of wiggle room for implementation details.\n    #   - Too many calls mean that failing steps are doing too much work.\n    #   - Too few calls mean that this test is probably miscounting and buggy.\n    assert 250 <= Shrinker.run_node_program.calls <= 260\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_conjecture_int_list.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import strategies as st\nfrom hypothesis.internal.conjecture.junkdrawer import IntList\nfrom hypothesis.stateful import RuleBasedStateMachine, initialize, invariant, rule\n\nINTEGERS = st.integers(0, 2**68)\n\n\n@st.composite\ndef valid_index(draw):\n    machine = draw(st.runner())\n    if not machine.model:\n        return draw(st.nothing())\n    return draw(st.integers(0, len(machine.model) - 1))\n\n\nclass IntListRules(RuleBasedStateMachine):\n    @initialize(ls=st.lists(INTEGERS))\n    def starting_lists(self, ls):\n        self.model = list(ls)\n        self.target = IntList(ls)\n\n    @invariant()\n    def lists_are_equivalent(self):\n        if hasattr(self, \"model\"):\n            assert isinstance(self.model, list)\n            assert isinstance(self.target, IntList)\n            assert len(self.model) == len(self.target)\n            assert list(self.target) == self.model\n\n    @rule(n=INTEGERS)\n    def append(self, n):\n        self.model.append(n)\n        self.target.append(n)\n\n    @rule(i=valid_index())\n    def delete(self, i):\n        del self.model[i]\n        del self.target[i]\n\n    @rule(i=valid_index())\n    def agree_on_values(self, i):\n        assert self.model[i] == self.target[i]\n\n\nTestIntList = IntListRules.TestCase\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_conjecture_utils.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport sys\nfrom collections import Counter\n\nfrom hypothesis import assume, example, given, settings, strategies as st, target\nfrom hypothesis.internal.conjecture import utils as cu\nfrom hypothesis.internal.conjecture.engine import BUFFER_SIZE\nfrom hypothesis.internal.conjecture.provider_conformance import integer_weights\n\nfrom tests.conjecture.common import fresh_data\n\n\n@given(integer_weights(), st.randoms(use_true_random=True))\n@settings(max_examples=3)\ndef test_sampler_matches_distribution(weights, random):\n    # if we randomly sample from Sampler(weights), the resulting distribution\n    # should match the weights (to some tolerance).\n\n    weights = weights.values()\n    sampler = cu.Sampler(weights)\n    counter = Counter()\n    for _ in range(10_000):\n        cd = fresh_data(random=random)\n        n = sampler.sample(cd)\n        counter[n] += 1\n\n    # if we ever pull in scipy to our test suite, we should do a chi squared\n    # test here instead.\n    expected = [w / sum(weights) for w in weights]\n    counter_total = sum(counter.values())  # Counter.total() new in py3.10\n    actual = [counter[i] / counter_total for i in range(len(weights))]\n    for p1, p2 in zip(expected, actual, strict=True):\n        assert abs(p1 - p2) < 0.05, (expected, actual)\n\n\n@example(0, 1)\n@example(0, float(\"inf\"))\n@example(cu.SMALLEST_POSITIVE_FLOAT, 2 * cu.SMALLEST_POSITIVE_FLOAT)\n@example(cu.SMALLEST_POSITIVE_FLOAT, 1)\n@example(cu.SMALLEST_POSITIVE_FLOAT, float(\"inf\"))\n@example(sys.float_info.min, 1)\n@example(sys.float_info.min, float(\"inf\"))\n@example(10, 10)\n@example(10, float(\"inf\"))\n# BUFFER_SIZE divided by (2bytes coin + 0byte element) gives the\n# maximum number of elements that we would ever be able to generate.\n@given(st.floats(0, BUFFER_SIZE // 2), st.integers(0, BUFFER_SIZE // 2))\ndef test_p_continue(average_size, max_size):\n    assume(average_size <= max_size)\n    p = cu._calc_p_continue(average_size, max_size)\n    assert 0 <= target(p, label=\"p\") <= 1\n    assert 0 < target(p, label=\"-p\") or average_size < 1e-5\n    abs_err = abs(average_size - cu._p_continue_to_avg(p, max_size))\n    assert target(abs_err, label=\"abs_err\") < 0.01\n\n\n@example(1.1, 10)\n@given(st.floats(0, 1), st.integers(0, BUFFER_SIZE // 2))\ndef test_p_continue_to_average(p_continue, max_size):\n    average = cu._p_continue_to_avg(p_continue, max_size)\n    assert 0 <= average <= max_size\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_conventions.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.utils.conventions import UniqueIdentifier\n\n\ndef test_unique_identifier_repr():\n    assert repr(UniqueIdentifier(\"hello_world\")) == \"hello_world\"\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_database_agreement.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport shutil\nimport tempfile\n\nimport pytest\n\nfrom hypothesis import settings, strategies as st\nfrom hypothesis.database import (\n    BackgroundWriteDatabase,\n    DirectoryBasedExampleDatabase,\n    InMemoryExampleDatabase,\n)\nfrom hypothesis.stateful import Bundle, RuleBasedStateMachine, rule\n\n\nclass DatabaseComparison(RuleBasedStateMachine):\n    def __init__(self):\n        super().__init__()\n        self.tempd = tempfile.mkdtemp()\n        exampledir = os.path.join(self.tempd, \"examples\")\n\n        self.dbs = [\n            InMemoryExampleDatabase(),\n            DirectoryBasedExampleDatabase(exampledir),\n            BackgroundWriteDatabase(InMemoryExampleDatabase()),\n        ]\n\n    keys = Bundle(\"keys\")\n    values = Bundle(\"values\")\n\n    @rule(target=keys, k=st.binary())\n    def k(self, k):\n        return k\n\n    @rule(target=values, v=st.binary())\n    def v(self, v):\n        return v\n\n    @rule(k=keys, v=values)\n    def save(self, k, v):\n        for db in self.dbs:\n            db.save(k, v)\n\n    @rule(k=keys, v=values)\n    def delete(self, k, v):\n        for db in self.dbs:\n            db.delete(k, v)\n\n    @rule(k1=keys, k2=keys, v=values)\n    def move(self, k1, k2, v):\n        for db in self.dbs:\n            db.move(k1, k2, v)\n\n    @rule(k=keys)\n    def values_agree(self, k):\n        last = None\n        last_db = None\n        for db in self.dbs:\n            keys = set(db.fetch(k))\n            if last is not None:\n                assert last == keys, (last_db, db)\n            last = keys\n            last_db = db\n\n    def teardown(self):\n        shutil.rmtree(self.tempd)\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\", reason=\"isn't threadsafe\"\n)\ndef test_database_equivalence():\n    DatabaseComparison.TestCase().runTest()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_database_usage.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import assume, core, find, given, settings, strategies as st\nfrom hypothesis.database import (\n    DirectoryBasedExampleDatabase,\n    GitHubArtifactDatabase,\n    InMemoryExampleDatabase,\n    ReadOnlyDatabase,\n)\nfrom hypothesis.errors import NoSuchExample, Unsatisfiable\n\nfrom tests.common.utils import (\n    Why,\n    all_values,\n    non_covering_examples,\n    skipif_threading,\n    xfail_on_crosshair,\n)\n\n\ndef has_a_non_zero_byte(x):\n    return any(bytes(x))\n\n\ndef test_saves_incremental_steps_in_database():\n    key = b\"a database key\"\n    database = InMemoryExampleDatabase()\n    find(\n        st.binary(min_size=10),\n        has_a_non_zero_byte,\n        settings=settings(database=database),\n        database_key=key,\n    )\n    assert len(all_values(database)) > 1\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context, strict=False)\ndef test_clears_out_database_as_things_get_boring():\n    key = b\"a database key\"\n    database = InMemoryExampleDatabase()\n    do_we_care = True\n\n    def stuff():\n        try:\n            find(\n                st.binary(min_size=50),\n                lambda x: do_we_care and has_a_non_zero_byte(x),\n                settings=settings(database=database, max_examples=10),\n                database_key=key,\n            )\n        except NoSuchExample:\n            pass\n\n    stuff()\n    assert len(non_covering_examples(database)) > 1\n    do_we_care = False\n    stuff()\n    initial = len(non_covering_examples(database))\n    assert initial > 0\n\n    for _ in range(initial):\n        stuff()\n        keys = len(non_covering_examples(database))\n        if not keys:\n            break\n    else:\n        raise AssertionError\n\n\n@xfail_on_crosshair(Why.other, strict=False)\ndef test_trashes_invalid_examples():\n    database = InMemoryExampleDatabase()\n\n    invalid = set()\n\n    def stuff():\n        try:\n\n            def condition(x):\n                assume(x not in invalid)\n                return not invalid and has_a_non_zero_byte(x)\n\n            return find(\n                st.binary(min_size=5),\n                condition,\n                settings=settings(database=database),\n                database_key=b\"a database key\",\n            )\n        except (Unsatisfiable, NoSuchExample):\n            pass\n\n    value = stuff()\n\n    original = len(all_values(database))\n    assert original > 1\n\n    invalid.add(value)\n    stuff()\n    assert len(all_values(database)) < original\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"condition is easy for crosshair, stops early\",\n)\ndef test_respects_max_examples_in_database_usage():\n    database = InMemoryExampleDatabase()\n    do_we_care = True\n    counter = 0\n\n    def check(x):\n        nonlocal counter\n        counter += 1\n        return do_we_care and has_a_non_zero_byte(x)\n\n    def stuff():\n        try:\n            find(\n                st.binary(min_size=100),\n                check,\n                settings=settings(database=database, max_examples=10),\n                database_key=b\"a database key\",\n            )\n        except NoSuchExample:\n            pass\n\n    stuff()\n    assert len(all_values(database)) > 10\n\n    do_we_care = False\n    counter = 0\n    stuff()\n\n    assert counter == 10\n\n\ndef test_does_not_use_database_when_seed_is_forced(monkeypatch):\n    monkeypatch.setattr(core, \"global_force_seed\", 42)\n    database = InMemoryExampleDatabase()\n    database.fetch = None  # type: ignore\n\n    @settings(database=database)\n    @given(st.integers())\n    def test(i):\n        pass\n\n    test()\n\n\n@skipif_threading  # pytest .mktemp is not thread safe\n@given(st.binary(), st.binary())\ndef test_database_not_created_when_not_used(tmp_path_factory, key, value):\n    path = tmp_path_factory.mktemp(\"hypothesis\") / \"examples\"\n    assert not path.exists()\n    database = DirectoryBasedExampleDatabase(path)\n    assert not list(database.fetch(key))\n    assert not path.exists()\n    database.save(key, value)\n    assert path.exists()\n    assert list(database.fetch(key)) == [value]\n\n\n@skipif_threading\ndef test_ga_database_not_created_when_not_used(tmp_path_factory):\n    path = tmp_path_factory.mktemp(\"hypothesis\") / \"github-actions\"\n    assert not path.exists()\n    ReadOnlyDatabase(GitHubArtifactDatabase(\"mock\", \"mock\", path=path))\n    assert not path.exists()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_deferred_errors.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import find, given, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.strategies._internal.core import defines_strategy\n\nfrom tests.common.debug import check_can_generate_examples\n\n\ndef test_does_not_error_on_initial_calculation():\n    st.floats(max_value=float(\"nan\"))\n    st.sampled_from([])\n    st.lists(st.integers(), min_size=5, max_size=2)\n    st.floats(min_value=2.0, max_value=1.0)\n\n\ndef test_errors_each_time():\n    s = st.integers(max_value=1, min_value=3)\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(s)\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(s)\n\n\ndef test_errors_on_test_invocation():\n    @given(st.integers(max_value=1, min_value=3))\n    def test(x):\n        pass\n\n    with pytest.raises(InvalidArgument):\n        test()\n\n\ndef test_errors_on_find():\n    s = st.lists(st.integers(), min_size=5, max_size=2)\n    with pytest.raises(InvalidArgument):\n        find(s, lambda x: True)\n\n\ndef test_errors_on_example():\n    s = st.floats(min_value=2.0, max_value=1.0)\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(s)\n\n\ndef test_does_not_recalculate_the_strategy():\n    calls = 0\n\n    @defines_strategy()\n    def foo():\n        nonlocal calls\n        calls += 1\n        return st.just(1)\n\n    f = foo()\n    assert calls == 0\n    check_can_generate_examples(f)\n    assert calls == 1\n    check_can_generate_examples(f)\n    assert calls == 1\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_drypython_returns.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom typing import Generic, TypeVar\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import ResolutionFailed\n\nfrom tests.common.debug import check_can_generate_examples, find_any\nfrom tests.common.utils import temp_registered\n\n# Primitives:\n# ===========\n\n_InstanceType = TypeVar(\"_InstanceType\", covariant=True)\n_TypeArgType1 = TypeVar(\"_TypeArgType1\", covariant=True)\n_FirstType = TypeVar(\"_FirstType\")\n_LawType = TypeVar(\"_LawType\")\n\n\nclass KindN(Generic[_InstanceType, _TypeArgType1]):\n    pass\n\n\nclass Lawful(Generic[_LawType]):\n    \"\"\"This type defines law-related operations.\"\"\"\n\n\nclass MappableN(Generic[_FirstType], Lawful[\"MappableN[_FirstType]\"]):\n    \"\"\"Behaves like a functor.\"\"\"\n\n\n# End definition:\n# ===============\n\n_ValueType = TypeVar(\"_ValueType\")\n\n\nclass MyFunctor(KindN[\"MyFunctor\", _ValueType], MappableN[_ValueType]):\n    def __init__(self, inner_value: _ValueType) -> None:\n        self.inner_value = inner_value\n\n\n# Testing part:\n# =============\n\n\ndef target_func(mappable: \"MappableN[_FirstType]\") -> bool:\n    return isinstance(mappable, MappableN)\n\n\n@given(st.data())\ndef test_my_mappable(source: st.DataObject) -> None:\n    \"\"\"\n    Checks that complex types with multiple inheritance levels and strings are fine.\n\n    Regression test for https://github.com/HypothesisWorks/hypothesis/issues/3060\n    \"\"\"\n    # In `returns` we register all types in `__mro__`\n    # to be this exact type at the moment. But here, we only need `Mappable`.\n    # Current `__mro__` is `MyFunctor / Kind / Mappable`:\n    assert MyFunctor.__mro__[2] is MappableN\n    with temp_registered(\n        MyFunctor.__mro__[2],\n        st.builds(MyFunctor),\n    ):\n        assert source.draw(st.builds(target_func)) is True\n\n\nA = TypeVar(\"A\")\nB = TypeVar(\"B\")\nC = TypeVar(\"C\")\nD = TypeVar(\"D\")\n\n\nclass _FirstBase(Generic[A, B]):\n    pass\n\n\nclass _SecondBase(Generic[C, D]):\n    pass\n\n\n# To be tested:\n\n\nclass TwoGenericBases1(_FirstBase[A, B], _SecondBase[C, D]):\n    pass\n\n\nclass TwoGenericBases2(_FirstBase[C, D], _SecondBase[A, B]):\n    pass\n\n\nclass OneGenericOneConrete1(_FirstBase[int, str], _SecondBase[A, B]):\n    pass\n\n\nclass OneGenericOneConrete2(_FirstBase[A, B], _SecondBase[float, bool]):\n    pass\n\n\nclass MixedGenerics1(_FirstBase[int, B], _SecondBase[C, bool]):\n    pass\n\n\nclass MixedGenerics2(_FirstBase[A, str], _SecondBase[float, D]):\n    pass\n\n\nclass AllConcrete(_FirstBase[int, str], _SecondBase[float, bool]):\n    pass\n\n\n_generic_test_types = (\n    TwoGenericBases1,\n    TwoGenericBases2,\n    OneGenericOneConrete1,\n    OneGenericOneConrete2,\n    MixedGenerics1,\n    MixedGenerics2,\n    AllConcrete,\n)\n\n\n@pytest.mark.parametrize(\"type_\", _generic_test_types)\ndef test_several_generic_bases(type_):\n    with temp_registered(_FirstBase, st.builds(type_)):\n        find_any(st.builds(_FirstBase))\n\n    with temp_registered(_SecondBase, st.builds(type_)):\n        find_any(st.builds(_SecondBase))\n\n\ndef var_generic_func1(obj: _FirstBase[A, B]):\n    pass\n\n\ndef var_generic_func2(obj: _SecondBase[A, B]):\n    pass\n\n\ndef concrete_generic_func1(obj: _FirstBase[int, str]):\n    pass\n\n\ndef concrete_generic_func2(obj: _SecondBase[float, bool]):\n    pass\n\n\ndef mixed_generic_func1(obj: _FirstBase[A, str]):\n    pass\n\n\ndef mixed_generic_func2(obj: _SecondBase[float, D]):\n    pass\n\n\n@pytest.mark.parametrize(\"type_\", _generic_test_types)\n@pytest.mark.parametrize(\n    \"func\",\n    [\n        var_generic_func1,\n        var_generic_func2,\n        concrete_generic_func1,\n        concrete_generic_func2,\n        mixed_generic_func1,\n        mixed_generic_func2,\n    ],\n)\ndef test_several_generic_bases_functions(type_, func):\n    with (\n        temp_registered(_FirstBase, st.builds(type_)),\n        temp_registered(_SecondBase, st.builds(type_)),\n    ):\n        find_any(st.builds(func))\n\n    with temp_registered(type_, st.builds(type_)):\n        find_any(st.builds(func))\n\n\ndef wrong_generic_func1(obj: _FirstBase[A, None]):\n    pass\n\n\ndef wrong_generic_func2(obj: _SecondBase[None, bool]):\n    pass\n\n\n@pytest.mark.parametrize(\"func\", [wrong_generic_func1, wrong_generic_func2])\ndef test_several_generic_bases_wrong_functions(func):\n    with (\n        temp_registered(AllConcrete, st.builds(AllConcrete)),\n        pytest.raises(ResolutionFailed),\n    ):\n        check_can_generate_examples(st.builds(func))\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_duplication.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections import Counter\n\nimport pytest\n\nfrom hypothesis import given, settings\nfrom hypothesis.strategies._internal import SearchStrategy\n\nfrom tests.common.utils import Why, xfail_on_crosshair\n\n\nclass Blocks(SearchStrategy):\n    def __init__(self, n):\n        super().__init__()\n        self.n = n\n\n    def do_draw(self, data):\n        return data.draw_bytes(self.n, self.n)\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context)\n@pytest.mark.parametrize(\"n\", range(1, 5))\ndef test_does_not_duplicate_blocks(n):\n    counts = Counter()\n\n    @given(Blocks(n))\n    @settings(database=None)\n    def test(b):\n        counts[b] += 1\n\n    test()\n    assert set(counts.values()) == {1}\n\n\n@xfail_on_crosshair(Why.other, strict=False)  # CrosshairInternal for n>0\n@pytest.mark.parametrize(\"n\", range(1, 5))\ndef test_mostly_does_not_duplicate_blocks_even_when_failing(n):\n    counts = Counter()\n\n    @settings(database=None)\n    @given(Blocks(n))\n    def test(b):\n        counts[b] += 1\n        if len(counts) > 3:\n            raise ValueError\n\n    try:\n        test()\n    except ValueError:\n        pass\n    # There are two circumstances in which a duplicate is allowed: We replay\n    # the failing test once to check for flakiness, and then we replay the\n    # fully minimized failing test at the end to display the error. The\n    # complication comes from the fact that these may or may not be the same\n    # test case, so we can see either two test cases each run twice or one\n    # test case which has been run three times.\n    assert set(counts.values()) in ({1, 2}, {1, 3})\n    assert len([k for k, v in counts.items() if v > 1]) <= 2\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_dynamic_variable.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.utils.dynamicvariables import DynamicVariable\n\n\ndef test_can_assign():\n    d = DynamicVariable(1)\n    assert d.value == 1\n    with d.with_value(2):\n        assert d.value == 2\n    assert d.value == 1\n\n\ndef test_can_nest():\n    d = DynamicVariable(1)\n    with d.with_value(2):\n        assert d.value == 2\n        with d.with_value(3):\n            assert d.value == 3\n        assert d.value == 2\n    assert d.value == 1\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_emails.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given, settings\nfrom hypothesis.strategies import emails, just\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"takes ~7 mins; first barrier: the `sampled_from(get_top_level_domains())` decision is \"\n    \"realized via iterative comparisons; see https://github.com/pschanely/CrossHair/issues/332\",\n)\n@given(emails())\ndef test_is_valid_email(address: str):\n    local, at_, domain = address.rpartition(\"@\")\n    assert len(address) <= 254\n    assert at_ == \"@\"\n    assert local\n    assert domain\n    assert not domain.lower().endswith(\".arpa\")\n\n\n@given(emails(domains=just(\"mydomain.com\")))\ndef test_can_restrict_email_domains(address: str):\n    assert address.endswith(\"@mydomain.com\")\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_eval_as_source.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.internal.reflection import source_exec_as_module\n\n\ndef test_can_eval_as_source():\n    assert source_exec_as_module(\"foo=1\").foo == 1\n\n\ndef test_caches():\n    x = source_exec_as_module(\"foo=2\")\n    y = source_exec_as_module(\"foo=2\")\n    assert x is y\n\n\nRECURSIVE = \"\"\"\nfrom hypothesis.internal.reflection import source_exec_as_module\n\ndef test_recurse():\n    assert not (\n        source_exec_as_module(\"too_much_recursion = False\").too_much_recursion)\n\"\"\"\n\n\ndef test_can_call_self_recursively():\n    source_exec_as_module(RECURSIVE).test_recurse()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_exceptiongroup.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport asyncio\nimport sys\nfrom collections.abc import Callable\n\nimport pytest\n\nfrom hypothesis import errors, given, reject, strategies as st\nfrom hypothesis.internal.compat import ExceptionGroup\nfrom hypothesis.strategies import DataObject\n\n# this file is not typechecked by mypy, which only runs py310\n\nif sys.version_info < (3, 11):\n    pytest.skip(\"asyncio.TaskGroup not available on <py3.11\", allow_module_level=True)\n\n\ndef test_exceptiongroup_discard_frozen():\n    \"\"\"Basic test that raises Frozen+Unsatisfiable.\n    Frozen is thrown out, and Unsatisfiable is raised\"\"\"\n\n    @given(st.data())\n    def test_function(data):\n        async def task(pred):\n            return data.draw(st.booleans().filter(pred))\n\n        async def _main():\n            async with asyncio.TaskGroup() as tg:\n                tg.create_task(task(bool))\n                tg.create_task(task(lambda _: False))\n\n        asyncio.run(_main())\n\n    with pytest.raises(errors.Unsatisfiable):\n        test_function()\n\n\ndef test_exceptiongroup_nested() -> None:\n    @given(st.data())\n    def test_function(data: DataObject) -> None:\n        async def task(pred: Callable[[bool], bool]) -> None:\n            data.draw(st.booleans().filter(pred))\n\n        async def _main() -> None:\n            async with asyncio.TaskGroup(), asyncio.TaskGroup() as tg2:\n                tg2.create_task(task(bool))\n                tg2.create_task(task(lambda _: False))\n\n        asyncio.run(_main())\n\n    with pytest.raises(errors.Unsatisfiable):\n        test_function()\n\n\ndef test_exceptiongroup_user_originated() -> None:\n    @given(st.data())\n    def test_function(data):\n        raise ExceptionGroup(\"foo\", [ValueError(), ValueError()])\n\n    with pytest.raises(ExceptionGroup) as exc_info:\n        test_function()\n    e = exc_info.value\n    assert e.message == \"foo\"\n    assert isinstance(e, ExceptionGroup)\n    assert len(e.exceptions) == 2\n    assert all(isinstance(child_e, ValueError) for child_e in e.exceptions)\n\n    @given(st.data())\n    def test_single_exc_group(data):\n        raise ExceptionGroup(\"important message for user\", [ValueError()])\n\n    with pytest.raises(ExceptionGroup) as exc_info:\n        test_single_exc_group()\n    e = exc_info.value\n    assert e.message == \"important message for user\"\n    assert isinstance(e, ExceptionGroup)\n    assert len(e.exceptions) == 1\n    assert isinstance(e.exceptions[0], ValueError)\n\n\ndef test_exceptiongroup_multiple_stop() -> None:\n    @given(st.data())\n    def test_function(data):\n        async def task(d: DataObject) -> None:\n            d.conjecture_data.mark_invalid()\n\n        async def _main(d: DataObject) -> None:\n            async with asyncio.TaskGroup() as tg:\n                tg.create_task(task(d))\n                tg.create_task(task(d))\n\n        asyncio.run(_main(data))\n\n    # multiple stoptests -> single stoptest -> unsatisfiable\n    with pytest.raises(errors.Unsatisfiable):\n        test_function()\n\n\ndef test_exceptiongroup_stop_and_hypothesisexception() -> None:\n    # group with stoptest+invalidargument -> invalidargument\n    @given(st.data())\n    def test_function(data):\n        async def task_stoptest(d: DataObject) -> None:\n            # only mark some runs as invalid to not raise Unsatisfiable\n            if d.draw(st.integers(min_value=0, max_value=1)) == 1:\n                d.conjecture_data.mark_invalid()\n\n        async def task_invalid_argument(d: DataObject) -> None:\n            d.draw(st.integers(max_value=2, min_value=3))\n\n        async def _main(d: DataObject) -> None:\n            async with asyncio.TaskGroup() as tg:\n                tg.create_task(task_stoptest(d))\n                tg.create_task(task_invalid_argument(d))\n\n        asyncio.run(_main(data))\n\n    with pytest.raises(errors.InvalidArgument):\n        test_function()\n\n\ndef test_exceptiongroup_multiple_hypothesisexception() -> None:\n    # multiple UnsatisfiedAssumption => first one is reraised => engine suppresses it\n\n    @given(st.integers(min_value=0, max_value=3))\n    def test_function(val: int) -> None:\n        async def task(value: int) -> None:\n            if value == 0:\n                reject()\n\n        async def _main(value: int) -> None:\n            async with asyncio.TaskGroup() as tg:\n                tg.create_task(task(value))\n                tg.create_task(task(value))\n\n        asyncio.run(_main(val))\n\n    test_function()\n\n\ndef test_exceptiongroup_multiple_InvalidArgument() -> None:\n    # multiple InvalidArgument => only first one is reraised... which seems bad.\n    # But raising a group might break ghostwriter(?)\n\n    @given(st.data())\n    def test_function(data: DataObject) -> None:\n        async def task1(d: DataObject) -> None:\n            d.draw(st.integers(max_value=1, min_value=3))\n\n        async def task2(d: DataObject) -> None:\n            d.draw(st.integers(max_value=2, min_value=3))\n\n        async def _main(d: DataObject) -> None:\n            async with asyncio.TaskGroup() as tg:\n                tg.create_task(task1(d))\n                tg.create_task(task2(d))\n\n        asyncio.run(_main(data))\n\n    with pytest.raises(errors.InvalidArgument):\n        test_function()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_explore_arbitrary_languages.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom dataclasses import dataclass, field\nfrom random import Random\nfrom typing import Any\n\nimport pytest\n\nfrom hypothesis import (\n    HealthCheck,\n    Phase,\n    Verbosity,\n    assume,\n    given,\n    note,\n    settings,\n    strategies as st,\n)\nfrom hypothesis.internal.conjecture.data import Status\nfrom hypothesis.internal.conjecture.engine import ConjectureRunner\n\nfrom tests.common.utils import Why, xfail_on_crosshair\nfrom tests.conjecture.common import interesting_origin\n\n\n@dataclass\nclass Write:\n    value: Any\n    child: Any\n\n\n@dataclass\nclass Branch:\n    bits: Any\n    children: Any = field(default_factory=dict)\n\n\n@dataclass\nclass Terminal:\n    status: Any\n    payload: Any = field(default=None)\n\n\nnodes = st.deferred(lambda: terminals | writes | branches)\n# Does not include Status.OVERRUN by design: That happens because of the size\n# of the string, not the input language.\nterminals = st.one_of(\n    st.just(Terminal(Status.VALID)),\n    st.just(Terminal(Status.INVALID)),\n    st.builds(Terminal, status=st.just(Status.INTERESTING), payload=st.integers(0, 10)),\n)\nbranches = st.builds(Branch, bits=st.integers(1, 64))\nwrites = st.builds(Write, value=st.binary(min_size=1), child=nodes)\n\n\n# Remember what the default phases are with no test running, so that we can\n# run an outer test with non-default phases and then restore the defaults for\n# the inner test.\n_default_phases = settings.default.phases\n\n\ndef run_language_test_for(root, data, seed):\n    def test(local_data):\n        node = root\n        while not isinstance(node, Terminal):\n            if isinstance(node, Write):\n                local_data.draw_bytes(\n                    len(node.value), len(node.value), forced=node.value\n                )\n                node = node.child\n            else:\n                assert isinstance(node, Branch)\n                c = local_data.draw_integer(0, 2**node.bits - 1)\n                try:\n                    node = node.children[c]\n                except KeyError:\n                    if data is None:\n                        return\n                    node = node.children.setdefault(c, data.draw(nodes))\n        assert isinstance(node, Terminal)\n        if node.status == Status.INTERESTING:\n            local_data.mark_interesting(interesting_origin(node.payload))\n        elif node.status == Status.INVALID:\n            local_data.mark_invalid()\n\n    runner = ConjectureRunner(\n        test,\n        settings=settings(\n            max_examples=1,\n            database=None,\n            suppress_health_check=list(HealthCheck),\n            verbosity=Verbosity.quiet,\n            # Restore the global default phases, so that we don't inherit the\n            # phases setting from the outer test.\n            phases=_default_phases,\n        ),\n        random=Random(seed),\n    )\n    try:\n        runner.run()\n    finally:\n        if data is not None:\n            note(root)\n    assume(runner.interesting_examples)\n\n\n# technically nested-engine, but same problem\n@xfail_on_crosshair(Why.nested_given, strict=False)\n@settings(\n    suppress_health_check=list(HealthCheck),\n    deadline=None,\n    phases=set(settings.default.phases) - {Phase.shrink},\n)\n@given(st.data())\ndef test_explore_an_arbitrary_language(data):\n    root = data.draw(writes | branches)\n    seed = data.draw(st.integers(0, 2**64 - 1))\n    run_language_test_for(root, data, seed)\n\n\n@pytest.mark.parametrize(\"seed, language\", [])\ndef test_run_specific_example(seed, language):\n    \"\"\"This test recreates individual languages generated with the main test.\n\n    These are typically manually pruned down a bit - e.g. it's\n    OK to remove VALID nodes because KeyError is treated as if it lead to one\n    in this test (but not in the @given test).\n\n    These tests are likely to be fairly fragile with respect to changes in the\n    underlying engine. Feel free to delete examples if they start failing after\n    a change.\n    \"\"\"\n    run_language_test_for(language, None, seed)\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_fancy_repr.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import strategies as st\n\n\ndef test_floats_is_floats():\n    assert repr(st.floats()) == \"floats()\"\n\n\ndef test_includes_non_default_values():\n    assert repr(st.floats(max_value=1.0)) == \"floats(max_value=1.0)\"\n\n\ndef foo(*args, **kwargs):\n    pass\n\n\n# fmt: off\n# The linebreaks here can force our lambda repr code into specific paths,\n# so we tell Black to leave them as-is.\n\n\ndef test_builds_repr():\n    assert repr(st.builds(foo, st.just(1), x=st.just(10))) == \\\n        'builds(foo, just(1), x=just(10))'\n\n\ndef test_map_repr():\n    assert repr(st.integers().map(abs)) == 'integers().map(abs)'\n    assert repr(st.integers().map(lambda x: x * 2)) == \\\n        'integers().map(lambda x: x * 2)'\n\n\ndef test_filter_repr():\n    assert repr(st.integers().filter(lambda x: x != 3)) == \\\n        'integers().filter(lambda x: x != 3)'\n\n\ndef test_flatmap_repr():\n    assert repr(st.integers().flatmap(lambda x: st.booleans())) == \\\n        'integers().flatmap(lambda x: st.booleans())'\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_filtering.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.strategies import integers, lists\n\n\n@pytest.mark.parametrize(\n    (\"specifier\", \"condition\"),\n    [(integers(), lambda x: x > 1), (lists(integers()), bool)],\n)\ndef test_filter_correctly(specifier, condition):\n    @given(specifier.filter(condition))\n    def test_is_filtered(x):\n        assert condition(x)\n\n    test_is_filtered()\n\n\n# A variety of strategies that generate the integers 1-20 inclusive, but might\n# differ in their support for special-case filtering.\none_to_twenty_strategies = [\n    st.integers(1, 20),\n    st.integers(0, 19).map(lambda x: x + 1),\n    st.sampled_from(range(1, 21)),\n    st.sampled_from(range(20)).map(lambda x: x + 1),\n]\n\n\n@pytest.mark.parametrize(\"base\", one_to_twenty_strategies)\n@given(\n    data=st.data(),\n    forbidden_values=st.lists(st.integers(1, 20), max_size=19, unique=True),\n)\ndef test_chained_filters_agree(data, forbidden_values, base):\n    def forbid(s, forbidden):\n        \"\"\"Helper function to avoid Python variable scoping issues.\"\"\"\n        return s.filter(lambda x: x != forbidden)\n\n    s = base\n    for forbidden in forbidden_values:\n        s = forbid(s, forbidden)\n\n    x = data.draw(s)\n    assert 1 <= x <= 20\n    assert x not in forbidden_values\n\n\n@pytest.mark.parametrize(\"base\", one_to_twenty_strategies)\ndef test_chained_filters_repr(base):\n    def foo(x):\n        return x != 0\n\n    def bar(x):\n        return x != 2\n\n    filtered = base.filter(foo)\n    chained = filtered.filter(bar)\n    assert repr(chained) == f\"{base!r}.filter(foo).filter(bar)\"\n    assert repr(filtered) == f\"{base!r}.filter(foo)\"\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_find.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\n\nimport pytest\n\nfrom hypothesis import find, settings as Settings\nfrom hypothesis.errors import NoSuchExample\nfrom hypothesis.strategies import booleans, dictionaries, floats, integers, lists\n\nfrom tests.common.debug import minimal\n\n\ndef test_can_find_an_int():\n    assert minimal(integers()) == 0\n    assert minimal(integers(), lambda x: x >= 13) == 13\n\n\ndef test_can_find_list():\n    x = minimal(lists(integers()), lambda x: sum(x) >= 10)\n    assert sum(x) == 10\n\n\ndef test_can_find_nan():\n    minimal(floats(), math.isnan)\n\n\ndef test_can_find_nans():\n    x = minimal(lists(floats()), lambda x: math.isnan(sum(x)))\n    if len(x) == 1:\n        assert math.isnan(x[0])\n    else:\n        assert 2 <= len(x) <= 3\n\n\ndef test_condition_is_name():\n    settings = Settings(max_examples=20)\n    with pytest.raises(NoSuchExample) as e:\n        find(booleans(), lambda x: False, settings=settings)\n    assert \"lambda x:\" in e.value.args[0]\n\n    with pytest.raises(NoSuchExample) as e:\n        find(integers(), lambda x: \"☃\" in str(x), settings=settings)\n    assert \"lambda x:\" in e.value.args[0]\n\n    def bad(x):\n        return False\n\n    with pytest.raises(NoSuchExample) as e:\n        find(integers(), bad, settings=settings)\n    assert \"bad\" in e.value.args[0]\n\n\ndef test_find_dictionary():\n    smallest = minimal(\n        dictionaries(keys=integers(), values=integers()),\n        lambda xs: any(kv[0] > kv[1] for kv in xs.items()),\n    )\n    assert len(smallest) == 1\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_fixtures.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport time\n\nfrom tests.common import TIME_INCREMENT\nfrom tests.common.utils import skipif_time_unpatched\n\n\n@skipif_time_unpatched\ndef test_time_consistently_increments_in_tests():\n    x = time.time()\n    y = time.time()\n    z = time.time()\n    assert y == x + TIME_INCREMENT\n    assert z == y + TIME_INCREMENT\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_flatmap.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections import Counter\n\nimport pytest\n\nfrom hypothesis import HealthCheck, assume, given, settings\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.strategies import (\n    booleans,\n    builds,\n    floats,\n    integers,\n    just,\n    lists,\n    text,\n    tuples,\n)\n\nfrom tests.common.debug import find_any, minimal\nfrom tests.common.utils import Why, xfail_on_crosshair\n\nConstantLists = integers().flatmap(lambda i: lists(just(i)))\n\nOrderedPairs = integers(1, 200).flatmap(lambda e: tuples(integers(0, e - 1), just(e)))\n\n\n# This health check fails very very occasionally - rarely enough to not be worth\n# investigation\n@settings(max_examples=100, suppress_health_check=[HealthCheck.filter_too_much])\n@given(ConstantLists)\ndef test_constant_lists_are_constant(x):\n    assume(len(x) >= 3)\n    assert len(set(x)) == 1\n\n\n@settings(max_examples=100)\n@given(OrderedPairs)\ndef test_in_order(x):\n    assert x[0] < x[1]\n\n\n@xfail_on_crosshair(\n    Why.undiscovered\n)  # (SampledFromStrategy.calc_label() hashes a symbolic float)\ndef test_flatmap_retrieve_from_db():\n    track = []\n\n    @given(floats(0, 1).flatmap(lambda x: lists(just(x))))\n    @settings(database=InMemoryExampleDatabase())\n    def record_and_test_size(xs):\n        if sum(xs) >= 1:\n            track.append(xs)\n            raise AssertionError\n\n    with pytest.raises(AssertionError):\n        record_and_test_size()\n\n    assert track\n    example = track[-1]\n    track = []\n\n    with pytest.raises(AssertionError):\n        record_and_test_size()\n\n    assert track[0] == example\n\n\ndef test_flatmap_does_not_reuse_strategies():\n    s = builds(list).flatmap(just)\n    assert find_any(s) is not find_any(s)\n\n\ndef test_flatmap_has_original_strategy_repr():\n    ints = integers()\n    ints_up = ints.flatmap(lambda n: integers(min_value=n))\n    assert repr(ints) in repr(ints_up)\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"takes ~6 mins in CI, but ~7 sec in isolation. Unsure why\",\n)\ndef test_mixed_list_flatmap():\n    s = lists(booleans().flatmap(lambda b: booleans() if b else text()))\n\n    def criterion(ls):\n        c = Counter(type(l) for l in ls)\n        return len(c) >= 2 and min(c.values()) >= 3\n\n    result = minimal(s, criterion)\n    assert len(result) == 6\n    assert set(result) == {False, \"\"}\n\n\n@xfail_on_crosshair(Why.undiscovered)  # for n >= 8 at least\n@pytest.mark.parametrize(\"n\", range(1, 10))\ndef test_can_shrink_through_a_binding(n):\n    bool_lists = integers(0, 100).flatmap(\n        lambda k: lists(booleans(), min_size=k, max_size=k)\n    )\n    assert minimal(bool_lists, lambda x: x.count(True) >= n) == [True] * n\n\n\n@xfail_on_crosshair(Why.undiscovered)  # for n >= 8 at least\n@pytest.mark.parametrize(\"n\", range(1, 10))\ndef test_can_delete_in_middle_of_a_binding(n):\n    bool_lists = integers(1, 100).flatmap(\n        lambda k: lists(booleans(), min_size=k, max_size=k)\n    )\n    result = minimal(bool_lists, lambda x: x[0] and x[-1] and x.count(False) >= n)\n    assert result == [True] + [False] * n + [True]\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_floating.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"Tests for being able to generate weird and wonderful floating point numbers.\"\"\"\n\nimport math\nimport sys\n\nimport pytest\n\nfrom hypothesis import HealthCheck, assume, given, settings\nfrom hypothesis.internal.floats import float_to_int\nfrom hypothesis.strategies import data, floats, lists\n\nfrom tests.common.debug import find_any\nfrom tests.common.utils import fails\n\nTRY_HARDER = settings(\n    max_examples=1000, suppress_health_check=[HealthCheck.filter_too_much]\n)\n\n\n@given(floats())\n@TRY_HARDER\ndef test_is_float(x):\n    assert isinstance(x, float)\n\n\n@fails\n@given(floats())\n@TRY_HARDER\ndef test_inversion_is_imperfect(x):\n    assume(x != 0.0)\n    y = 1.0 / x\n    assert x * y == 1.0\n\n\n@given(floats(-sys.float_info.max, sys.float_info.max))\ndef test_largest_range(x):\n    assert not math.isinf(x)\n\n\n@given(floats())\n@TRY_HARDER\ndef test_negation_is_self_inverse(x):\n    assume(not math.isnan(x))\n    y = -x\n    assert -y == x\n\n\n@fails\n@given(lists(floats()))\n@TRY_HARDER\ndef test_is_not_nan(xs):\n    assert not any(math.isnan(x) for x in xs)\n\n\n@fails\n@given(floats())\n@TRY_HARDER\ndef test_is_not_positive_infinite(x):\n    assume(x > 0)\n    assert not math.isinf(x)\n\n\n@fails\n@given(floats())\n@TRY_HARDER\ndef test_is_not_negative_infinite(x):\n    assume(x < 0)\n    assert not math.isinf(x)\n\n\n@fails\n@given(floats())\n@TRY_HARDER\ndef test_is_int(x):\n    assume(math.isfinite(x))\n    assert x == int(x)\n\n\n@fails\n@given(floats())\n@TRY_HARDER\ndef test_is_not_int(x):\n    assume(math.isfinite(x))\n    assert x != int(x)\n\n\n@fails\n@given(floats())\n@TRY_HARDER\ndef test_is_in_exact_int_range(x):\n    assume(math.isfinite(x))\n    assert x + 1 != x\n\n\n@fails\n@given(floats())\n@TRY_HARDER\ndef test_can_find_floats_that_do_not_round_trip_through_strings(x):\n    assert float(str(x)) == x\n\n\n@fails\n@given(floats())\n@TRY_HARDER\ndef test_can_find_floats_that_do_not_round_trip_through_reprs(x):\n    assert float(repr(x)) == x\n\n\nfinite_floats = floats(allow_infinity=False, allow_nan=False)\n\n\n@settings(deadline=None)\n@given(finite_floats, finite_floats, data())\ndef test_floats_are_in_range(x, y, data):\n    x, y = sorted((x, y))\n    assume(x < y)\n\n    t = data.draw(floats(x, y))\n    assert x <= t <= y\n\n\n@pytest.mark.parametrize(\"neg\", [False, True])\n@pytest.mark.parametrize(\"snan\", [False, True])\ndef test_can_find_negative_and_signaling_nans(neg, snan):\n    find_any(\n        floats().filter(math.isnan),\n        lambda x: (\n            snan is (float_to_int(abs(x)) != float_to_int(float(\"nan\")))\n            and neg is (math.copysign(1, x) == -1)\n        ),\n        settings=TRY_HARDER,\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_from_type_recipe.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.strategies._internal.types import _global_type_lookup\n\nfrom tests.common.debug import find_any\n\nTYPES = sorted(\n    (\n        x\n        for x in _global_type_lookup\n        if x.__module__ != \"typing\" and x.__name__ != \"ByteString\"\n    ),\n    key=str,\n)\n\n\ndef everything_except(excluded_types):\n    \"\"\"Recipe copied from the docstring of ``from_type``\"\"\"\n    return (\n        st.from_type(type)\n        .flatmap(st.from_type)\n        .filter(lambda x: not isinstance(x, excluded_types))\n    )\n\n\n@given(\n    excluded_types=st.lists(\n        st.sampled_from(TYPES), min_size=1, max_size=3, unique=True\n    ).map(tuple),\n    data=st.data(),\n)\ndef test_recipe_for_everything_except(excluded_types, data):\n    value = data.draw(everything_except(excluded_types))\n    assert not isinstance(value, excluded_types)\n\n\ndef test_issue_4144_regression():\n    find_any(everything_except(()), lambda t: t is not type)\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_given_error_conditions.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import HealthCheck, given, reject, settings\nfrom hypothesis.errors import Unsatisfiable\nfrom hypothesis.strategies import integers\n\nfrom tests.common.utils import fails_with\n\n\n@fails_with(Unsatisfiable)\n@given(integers())\n@settings(max_examples=50, suppress_health_check=list(HealthCheck))\ndef test_raises_unsatisfiable_if_all_false(x):\n    reject()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_given_reuse.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\n\ngiven_booleans = given(st.booleans())\n\n\n@given_booleans\ndef test_has_an_arg_named_x(x):\n    pass\n\n\n@given_booleans\ndef test_has_an_arg_named_y(y):\n    pass\n\n\ngiven_named_booleans = given(z=st.text())\n\n\ndef test_fail_independently():\n    @given_named_booleans\n    def test_z1(z):\n        raise AssertionError\n\n    @given_named_booleans\n    def test_z2(z):\n        pass\n\n    with pytest.raises(AssertionError):\n        test_z1()\n\n    test_z2()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_health_checks.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport time\n\nimport pytest\nfrom pytest import raises\n\nfrom hypothesis import HealthCheck, Phase, given, seed, settings, strategies as st\nfrom hypothesis.errors import FailedHealthCheck\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.conjecture.engine import BUFFER_SIZE\nfrom hypothesis.strategies._internal.lazy import LazyStrategy\n\npytestmark = pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"slow - large number of symbolics\",\n)\n\nlarge_strategy = st.binary(min_size=7000, max_size=7000)\ntoo_large_strategy = st.tuples(large_strategy, large_strategy)\n\n\ndef test_large_data_will_fail_a_health_check():\n    @given(st.none() | too_large_strategy)\n    @settings(database=None)\n    def test(x):\n        pass\n\n    with raises(FailedHealthCheck) as e:\n        test()\n    assert \"maximum allowed entropy\" in e.value.args[0]\n\n\ndef test_large_base_example_fails_health_check():\n    @given(large_strategy)\n    def test(b):\n        pass\n\n    with pytest.raises(FailedHealthCheck) as exc:\n        test()\n\n    assert str(HealthCheck.large_base_example) in str(exc.value)\n\n\ndef test_example_that_shrinks_to_overrun_fails_health_check():\n    @given(too_large_strategy | st.none())\n    def test(b):\n        pass\n\n    with pytest.raises(FailedHealthCheck) as exc:\n        test()\n\n    assert str(HealthCheck.large_base_example) in str(exc.value)\n\n\nslow_down_init = True\n\n\ndef slow_init_integers(*args, **kwargs):\n    # This mimics st.characters() or st.text(), which perform some\n    # expensive Unicode calculations when the cache is empty.\n    global slow_down_init\n    if slow_down_init:\n        time.sleep(0.5)  # We monkeypatch time, so this is fast\n        slow_down_init = False\n    return st.integers(*args, **kwargs)\n\n\n@given(st.data())\ndef test_lazy_slow_initialization_issue_2108_regression(data):\n    # Slow init in strategies wrapped in a LazyStrategy, inside an interactive draw,\n    # should be attributed to drawing from the strategy (not the test function).\n    # Specifically, this used to fail with a DeadlineExceeded error.\n    data.draw(LazyStrategy(slow_init_integers, (), {}))\n\n\ndef test_does_not_trigger_health_check_on_simple_strategies(monkeypatch):\n    existing_draw = ConjectureData.draw_integer\n\n    # We need to make drawing data artificially slow in order to trigger this\n    # effect. This isn't actually slow because time is fake in our CI, but\n    # we need it to pretend to be.\n    def draw_integer(*args, **kwargs):\n        time.sleep(0.001)\n        return existing_draw(*args, **kwargs)\n\n    monkeypatch.setattr(ConjectureData, \"draw_integer\", draw_integer)\n\n    for _ in range(100):\n        # Setting max_examples=11 ensures we have enough examples for the\n        # health checks to finish running, but cuts the generation short\n        # after that point to allow this test to run in reasonable time.\n        @settings(database=None, max_examples=11, phases=[Phase.generate])\n        @given(st.integers())\n        def test(n):\n            pass\n\n        test()\n\n\ndef test_does_not_trigger_health_check_when_most_examples_are_small():\n    for i in range(10):\n\n        @seed(i)\n        # Setting max_examples=11 ensures we have enough examples for the\n        # health checks to finish running, but cuts the generation short\n        # after that point to allow this test to run in reasonable time.\n        @settings(database=None, max_examples=11, phases=[Phase.generate])\n        @given(\n            st.integers(0, 100).flatmap(\n                lambda n: st.binary(\n                    min_size=min(n * 100, BUFFER_SIZE), max_size=n * 100\n                )\n            )\n        )\n        def test(b):\n            pass\n\n        test()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_imports.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import *\nfrom hypothesis.strategies import *\n\n\ndef test_can_star_import_from_hypothesis():\n    find(\n        lists(integers()),\n        lambda x: sum(x) > 1,\n        settings=settings(max_examples=10000, verbosity=Verbosity.quiet),\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_integer_ranges.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, settings\nfrom hypothesis.strategies import integers\n\nfrom tests.common.utils import Why, xfail_on_crosshair\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context)\ndef test_bounded_integers_distribution_of_bit_width_issue_1387_regression():\n    values = []\n\n    @settings(database=None, max_examples=1000)\n    @given(integers(0, 1e100))\n    def test(x):\n        if 2 <= x <= int(1e100) - 2:  # skip forced-endpoints\n            values.append(x)\n\n    test()\n\n    # We draw from a shaped distribution up to 128bit ~7/8 of the time, and\n    # uniformly the rest.  So we should get some very large but not too many.\n    huge = sum(x > 1e97 for x in values)\n    assert huge != 0 or len(values) < 800\n    assert huge <= 0.5 * len(values)  # expected ~1/8\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_interesting_origin.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis.internal.compat import ExceptionGroup\n\nfrom tests.common.utils import flaky\n\n\ndef go_wrong_naive(a, b):\n    try:\n        assert a + b < 100\n        a / b\n    except Exception:\n        # Hiding the actual problem is terrible, but this pattern can make sense\n        # if you're raising a library-specific or semantically meaningful error.\n        raise ValueError(\"Something went wrong\")  # noqa\n\n\ndef go_wrong_with_cause(a, b):\n    try:\n        assert a + b < 100\n        a / b\n    except Exception as err:\n        # Explicit chaining is the *right way* to change exception type.\n        raise ValueError(\"Something went wrong\") from err\n\n\ndef go_wrong_coverup(a, b):\n    try:\n        assert a + b < 100\n        a / b\n    except Exception:\n        # This pattern SHOULD be local enough that it never distinguishes\n        # errors in practice... but if it does, we're ready.\n        raise ValueError(\"Something went wrong\") from None\n\n\n@pytest.mark.parametrize(\n    \"function\",\n    [go_wrong_naive, go_wrong_with_cause, go_wrong_coverup],\n    ids=lambda f: f.__name__,\n)\n@flaky(max_runs=3, min_passes=1)\ndef test_can_generate_specified_version(function):\n    @given(st.integers(), st.integers())\n    @settings(database=None, report_multiple_bugs=True)\n    def test_fn(x, y):\n        # Indirection to fix https://github.com/HypothesisWorks/hypothesis/issues/2888\n        return function(x, y)\n\n    with pytest.raises(ExceptionGroup):\n        test_fn()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_labels.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import strategies as st\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.strategies._internal.lazy import LazyStrategy\n\n\ndef test_labels_are_cached():\n    x = st.integers()\n    assert x.label is x.label\n\n\ndef test_labels_are_distinct():\n    assert st.integers().label != st.text().label\n\n\n@st.composite\ndef foo(draw):\n    return draw(st.none())\n\n\n@st.composite\ndef bar(draw):\n    return draw(st.none())\n\n\n@st.composite\ndef baz(draw):\n    return draw(st.booleans())\n\n\ndef test_equivalent_composites_have_same_label():\n    assert foo().label == bar().label\n\n\ndef test_different_composites_have_different_labels():\n    assert foo().label != baz().label\n\n\ndef test_one_of_label_is_distinct():\n    a = st.integers()\n    b = st.booleans()\n    assert st.one_of(a, b).label != st.one_of(b, a).label\n\n\ndef test_lists_label_by_element():\n    assert st.lists(st.integers()).label != st.lists(st.booleans()).label\n\n\ndef test_label_of_deferred_strategy_is_well_defined():\n    recursive = st.deferred(lambda: st.lists(recursive))\n    recursive.label\n\n\n@pytest.mark.parametrize(\n    \"strategy\",\n    [\n        lambda: [st.none()],\n        lambda: [st.integers()],\n        lambda: [st.lists(st.floats())],\n        lambda: [st.none(), st.integers(), st.lists(st.floats())],\n    ],\n)\ndef test_sampled_from_label_with_strategies_does_not_change(strategy):\n    s1 = st.sampled_from(strategy())\n    s2 = st.sampled_from(strategy())\n    assert s1.label == s2.label\n\n\ndef test_label_of_enormous_sampled_range():\n    # this should not take forever.\n    st.sampled_from(range(2**30)).label\n\n\n@pytest.mark.parametrize(\n    \"strategy\",\n    [\n        lambda: st.deferred(lambda: st.integers()),\n        lambda: LazyStrategy(st.integers, (), {}),\n    ],\n)\ndef test_draw_uses_wrapped_label(strategy):\n    cd = ConjectureData.for_choices([0])\n    strategy = strategy()\n    cd.draw(strategy)\n    cd.freeze()\n\n    assert len(cd.spans) == 2\n    assert cd.spans[1].label == st.integers().label\n\n\ndef test_deferred_label():\n    strategy = st.deferred(lambda: st.integers())\n    assert strategy.label != st.integers().label\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_large_examples.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import strategies as st\n\nfrom tests.common.debug import find_any\n\n\ndef test_can_generate_large_lists_with_min_size():\n    find_any(st.lists(st.integers(), min_size=400))\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_limits.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, settings, strategies as st\n\nfrom tests.common.utils import Why, xfail_on_crosshair\n\n\n@xfail_on_crosshair(Why.other, strict=False)  # might run fewer\ndef test_max_examples_are_respected():\n    counter = 0\n\n    @given(st.random_module(), st.integers())\n    @settings(max_examples=100)\n    def test(rnd, i):\n        nonlocal counter\n        counter += 1\n\n    test()\n    assert counter == 100\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_modify_inner_test.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom functools import wraps\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import InvalidArgument\n\n\ndef always_passes(*args, **kwargs):\n    \"\"\"Stand-in for a fixed version of an inner test.\n\n    For example, pytest-trio would take the inner test, wrap it in an\n    async-to-sync converter, and use the new func (not always_passes).\n    \"\"\"\n\n\n@given(st.integers())\ndef test_can_replace_inner_test(x):\n    raise AssertionError(\"This should be replaced\")\n\n\ntest_can_replace_inner_test.hypothesis.inner_test = always_passes\n\n\ndef decorator(func):\n    \"\"\"An example of a common decorator pattern.\"\"\"\n\n    @wraps(func)\n    def inner(*args, **kwargs):\n        return func(*args, **kwargs)\n\n    return inner\n\n\n@decorator\n@given(st.integers())\ndef test_can_replace_when_decorated(x):\n    raise AssertionError(\"This should be replaced\")\n\n\ntest_can_replace_when_decorated.hypothesis.inner_test = always_passes\n\n\n@pytest.mark.parametrize(\"x\", [1, 2])\n@given(y=st.integers())\ndef test_can_replace_when_parametrized(x, y):\n    raise AssertionError(\"This should be replaced\")\n\n\ntest_can_replace_when_parametrized.hypothesis.inner_test = always_passes\n\n\ndef test_can_replace_when_original_is_invalid():\n    # Invalid: @given with too many positional arguments\n    @given(st.integers(), st.integers())\n    def invalid_test(x):\n        raise AssertionError\n\n    invalid_test.hypothesis.inner_test = always_passes\n\n    # Even after replacing the inner test, calling the wrapper should still\n    # fail.\n    with pytest.raises(InvalidArgument, match=\"Too many positional arguments\"):\n        invalid_test()\n\n\ndef test_inner_is_original_even_when_invalid():\n    def invalid_test(x):\n        raise AssertionError\n\n    original = invalid_test\n\n    # Invalid: @given with no arguments\n    invalid_test = given()(invalid_test)\n\n    # Verify that the test is actually invalid\n    with pytest.raises(\n        InvalidArgument,\n        match=\"given must be called with at least one argument\",\n    ):\n        invalid_test()\n\n    assert invalid_test.hypothesis.inner_test == original\n\n\ndef test_invokes_inner_function_with_args_by_name():\n    # Regression test for https://github.com/HypothesisWorks/hypothesis/issues/3245\n    @given(st.integers())\n    def test(x):\n        pass\n\n    f = test.hypothesis.inner_test\n    test.hypothesis.inner_test = wraps(f)(lambda **kw: f(**kw))\n    test()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_nesting.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom pytest import raises\n\nfrom hypothesis import HealthCheck, Verbosity, given, settings, strategies as st\n\nfrom tests.common.utils import Why, no_shrink, xfail_on_crosshair\n\n\n@xfail_on_crosshair(Why.nested_given)\ndef test_nesting_1():\n    @given(st.integers(0, 100))\n    @settings(\n        max_examples=5,\n        database=None,\n        deadline=None,\n        suppress_health_check=[HealthCheck.nested_given],\n    )\n    def test_blah(x):\n        @given(st.integers())\n        @settings(\n            max_examples=100, phases=no_shrink, database=None, verbosity=Verbosity.quiet\n        )\n        def test_nest(y):\n            if y >= x:\n                raise ValueError\n\n        with raises(ValueError):\n            test_nest()\n\n    test_blah()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_precise_shrinking.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"\nThis file tests for our ability to make precise shrinks.\n\nTerminology: A shrink is *precise* if there is a single span (draw call) that\nit replaces, without leaving any of the data before or after that draw call changed.\nOtherwise, it is sloppy.\n\nPrecise shrinks correspond to the changes we can make to drawn data in isolation\nof the rest of the test case. e.g. if we draw a list, we want to always be able\nto delete an element from it without affecting things outside that list. If we\ndraw an integer, we always want to be able to subtract from it.\n\nAn example of a sloppy shrink is that we can sloppily replace any list with a prefix\nof it by changing the boolean that says if we should draw more elements with False.\nHowever leaves all the data corresponding to the rest of the list after that prefix\nin the test case, so everything after the drawn list is deleted.\n\nHaving a rich vocabulary of precise shrinks we can make allows us to more easily\nreason about shrunk data, because we can look at the data and think in terms of\nwhat changes the shrinker would have made to it, and the fact that it hasn't\nmeans we know that it's important. e.g. this numeric value can't be smaller, this\nlist can't have fewer elements.\n\nSloppy shrinks in contrast just make the test case smaller. This is still good,\nobviously, and we rely on sloppy shrinks for a lot of shrinker performance and\nquality - often what we can expect is that we get to a smaller test case faster\nthrough sloppy shrinks, and then precise shrinks guarantee properties of the final\nresult.\n\"\"\"\n\n\nimport itertools\nfrom collections.abc import Callable\nfrom functools import lru_cache\nfrom random import Random\nfrom typing import TypeVar\n\nimport pytest\n\nfrom hypothesis import find, settings, strategies as st\nfrom hypothesis.control import BuildContext\nfrom hypothesis.errors import StopTest, UnsatisfiedAssumption\nfrom hypothesis.internal.conjecture.data import ConjectureData, ConjectureResult, Status\nfrom hypothesis.internal.conjecture.engine import (\n    ConjectureRunner,\n    ExitReason,\n    RunIsComplete,\n)\nfrom hypothesis.internal.conjecture.shrinker import sort_key\n\nfrom tests.conjecture.common import interesting_origin\n\nT = TypeVar(\"T\")\n\npytestmark = [\n    pytest.mark.skipif(\n        settings.get_current_profile_name() == \"crosshair\",\n        reason=\"using internals for testing in a way crosshair doesn't support\",\n    ),\n    pytest.mark.skipif(\n        settings.get_current_profile_name() == \"threading\",\n        reason=\"not worth making thread-safe atm\",\n    ),\n]\n\n\ndef safe_draw(data, strategy):\n    \"\"\"Set up just enough of the Hypothesis machinery to use draw on\n    a strategy.\"\"\"\n    with BuildContext(data, wrapped_test=None):\n        try:\n            return data.draw(strategy)\n        except UnsatisfiedAssumption:\n            data.mark_invalid()\n\n\ndef precisely_shrink(\n    strategy,\n    is_interesting=lambda x: True,\n    initial_condition=lambda x: True,\n    end_marker=st.integers(),\n    seed=0,\n):\n    \"\"\"Generates a random value from the strategy and then precisely shrinks it,\n    by shrinking it with some value immediately afterwards that is not allowed to\n    be modified during shrinking.\"\"\"\n    random = Random(seed)\n\n    while True:\n        data = ConjectureData(random=random)\n        try:\n            initial_value = safe_draw(data, strategy)\n        except StopTest:\n            continue\n        if is_interesting(initial_value) and initial_condition(initial_value):\n            break\n\n    target_check_value = safe_draw(data, end_marker)\n\n    initial_choices = data.choices\n\n    replay = ConjectureData.for_choices(initial_choices)\n    assert safe_draw(replay, strategy) == initial_value\n    assert safe_draw(replay, end_marker) == target_check_value\n\n    def test_function(data):\n        value = safe_draw(data, strategy)\n        check_value = safe_draw(data, end_marker)\n        if is_interesting(value) and check_value == target_check_value:\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(test_function, random=random)\n    try:\n        buf = runner.cached_test_function(initial_choices)\n        assert buf.status == Status.INTERESTING\n        assert buf.choices == initial_choices\n        assert runner.interesting_examples\n        runner.shrink_interesting_examples()\n    except RunIsComplete:\n        assert runner.exit_reason in (ExitReason.finished, ExitReason.max_shrinks)\n    (result,) = runner.interesting_examples.values()\n\n    data = ConjectureData.for_choices(result.choices)\n    result_value = safe_draw(data, strategy)\n    data.freeze()\n    return data.as_result(), result_value\n\n\ncommon_strategies_with_types = [\n    (type(None), st.none()),\n    (bool, st.booleans()),\n    (bytes, st.binary()),\n    (str, st.text()),\n    (int, st.integers()),\n]\n\ncommon_strategies = [v for _, v in common_strategies_with_types]\n\n\n@lru_cache\ndef minimal_for_strategy(s):\n    return precisely_shrink(s, end_marker=st.none())\n\n\ndef minimal_nodes_for_strategy(s):\n    return minimal_for_strategy(s)[0].nodes\n\n\ndef test_strategy_list_is_in_sorted_order():\n    assert common_strategies == sorted(\n        common_strategies, key=lambda s: sort_key(minimal_nodes_for_strategy(s))\n    )\n\n\n@pytest.mark.parametrize(\"typ,strat\", common_strategies_with_types)\n@pytest.mark.parametrize(\"require_truthy\", [False, True])\ndef test_can_precisely_shrink_values(typ, strat, require_truthy):\n    if typ is type(None) and require_truthy:\n        pytest.skip(\"None is falsey\")\n    if require_truthy:\n        cond = bool\n    else:\n        cond = lambda x: True\n    _result, shrunk = precisely_shrink(strat, is_interesting=cond)\n    assert shrunk == find(strat, cond)\n\n\nalternatives = [\n    comb\n    for n in (2, 3, 4)\n    for comb in itertools.combinations(common_strategies_with_types, n)\n]\n\nindexed_alternatives = [\n    (i, j, a) for a in alternatives for i, j in itertools.combinations(range(len(a)), 2)\n]\n\n\n@pytest.mark.parametrize(\"i,j,a\", indexed_alternatives)\n@pytest.mark.parametrize(\"seed\", [0, 4389048901])\ndef test_can_precisely_shrink_alternatives(i, j, a, seed):\n    types = [u for u, _ in a]\n    combined_strategy = st.one_of(*[v for _, v in a])\n\n    _result, value = precisely_shrink(\n        combined_strategy,\n        initial_condition=lambda x: isinstance(x, types[j]),\n        is_interesting=lambda x: not any(isinstance(x, types[k]) for k in range(i)),\n        seed=seed,\n    )\n    assert isinstance(value, types[i])\n\n\n@pytest.mark.parametrize(\n    \"a\", list(itertools.combinations(common_strategies_with_types, 3))\n)\n@pytest.mark.parametrize(\"seed\", [0, 4389048901])\ndef test_precise_shrink_with_blocker(a, seed):\n    # We're reordering this so that there is a \"blocking\" unusually large\n    # strategy in the middle.\n    x, y, z = a\n    a = (x, z, y)\n\n    types = [u for u, _ in a]\n    combined_strategy = st.one_of(*[v for _, v in a])\n\n    _result, value = precisely_shrink(\n        combined_strategy,\n        initial_condition=lambda x: isinstance(x, types[2]),\n        is_interesting=lambda x: True,\n        seed=seed,\n    )\n\n    assert isinstance(value, types[0])\n\n\ndef find_random(\n    s: st.SearchStrategy[T], condition: Callable[[T], bool], seed=None\n) -> tuple[ConjectureResult, T]:\n    random = Random(seed)\n    while True:\n        data = ConjectureData(random=random)\n        try:\n            with BuildContext(data=data, wrapped_test=None):\n                value = data.draw(s)\n                if condition(value):\n                    data.freeze()\n                    return (data.as_result(), value)\n        except (StopTest, UnsatisfiedAssumption):\n            continue\n\n\ndef shrinks(strategy, nodes, *, allow_sloppy=True, seed=0):\n    results = {}\n    random = Random(seed)\n    choices = tuple(n.value for n in nodes)\n\n    if allow_sloppy:\n\n        def test_function(data):\n            value = safe_draw(data, strategy)\n            results[data.nodes] = value\n\n        runner = ConjectureRunner(test_function, settings=settings(max_examples=10**9))\n        initial = runner.cached_test_function(choices)\n        assert isinstance(initial, ConjectureResult)\n        try:\n            runner.shrink(initial, lambda x: x.choices == initial.choices)\n        except RunIsComplete:\n            assert runner.exit_reason in (ExitReason.finished, ExitReason.max_shrinks)\n    else:\n        trial = ConjectureData(prefix=choices, random=random)\n        with BuildContext(trial, wrapped_test=None):\n            trial.draw(strategy)\n            assert trial.choices == choices, \"choice sequence is already sloppy\"\n            padding = safe_draw(trial, st.integers())\n        initial_choices = trial.choices\n\n        def test_function(data):\n            value = safe_draw(data, strategy)\n            key = data.nodes\n            padding_check = safe_draw(data, st.integers())\n            if padding_check == padding:\n                results[key] = value\n\n        runner = ConjectureRunner(test_function, settings=settings(max_examples=10**9))\n        initial = runner.cached_test_function(initial_choices)\n        assert len(results) == 1\n        try:\n            runner.shrink(initial, lambda x: x.choices == initial_choices)\n        except RunIsComplete:\n            assert runner.exit_reason in (ExitReason.finished, ExitReason.max_shrinks)\n\n    results.pop(nodes)\n    seen = set()\n    result_list = []\n\n    for k, v in sorted(results.items(), key=lambda x: sort_key(x[0])):\n        t = repr(v)\n        if t in seen:\n            continue\n        seen.add(t)\n        result_list.append((k, v))\n    return result_list\n\n\n@pytest.mark.parametrize(\"a\", list(itertools.product(*([common_strategies[1:]] * 2))))\n@pytest.mark.parametrize(\"block_falsey\", [False, True])\n@pytest.mark.parametrize(\"allow_sloppy\", [False, True])\n@pytest.mark.parametrize(\"seed\", [0, 2452, 99085240570])\ndef test_always_shrinks_to_none(a, seed, block_falsey, allow_sloppy):\n    combined_strategy = st.one_of(st.none(), *a)\n\n    result, _value = find_random(combined_strategy, lambda x: x is not None)\n    shrunk_values = shrinks(\n        combined_strategy, result.nodes, allow_sloppy=allow_sloppy, seed=seed\n    )\n    assert shrunk_values[0][1] is None\n\n\n@pytest.mark.parametrize(\n    \"i,alts\", [(i, alt) for alt in alternatives for i in range(1, len(alt))]\n)\n@pytest.mark.parametrize(\"force_small\", [False, True])\n@pytest.mark.parametrize(\"seed\", [0, 2452, 99085240570])\ndef test_can_shrink_to_every_smaller_alternative(i, alts, seed, force_small):\n    types = [t for t, _ in alts]\n    strats = [s for _, s in alts]\n    combined_strategy = st.one_of(*strats)\n    if force_small:\n        result, _value = precisely_shrink(\n            combined_strategy, is_interesting=lambda x: type(x) is types[i], seed=seed\n        )\n    else:\n        result, _value = find_random(\n            combined_strategy, lambda x: type(x) is types[i], seed=seed\n        )\n\n    shrunk = shrinks(\n        combined_strategy,\n        result.nodes,\n        allow_sloppy=False,\n        # Arbitrary change so we don't use the same seed for each Random.\n        seed=seed * 17,\n    )\n    shrunk_values = [t for _, t in shrunk]\n\n    for j in range(i):\n        assert any(isinstance(x, types[j]) for x in shrunk_values)\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_pretty_repr.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections import OrderedDict\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.control import reject\nfrom hypothesis.errors import HypothesisDeprecationWarning, InvalidArgument\n\n\ndef foo(x):\n    pass\n\n\ndef bar(x):\n    pass\n\n\ndef baz(x):\n    pass\n\n\nfns = [foo, bar, baz]\n\n\ndef builds_ignoring_invalid(target, *args, **kwargs):\n    def splat(value):\n        try:\n            result = target(*value[0], **value[1])\n            result.validate()\n            return result\n        except (HypothesisDeprecationWarning, InvalidArgument):\n            reject()\n\n    return st.tuples(st.tuples(*args), st.fixed_dictionaries(kwargs)).map(splat)\n\n\nsize_strategies = {\n    \"min_size\": st.integers(min_value=0, max_value=100),\n    \"max_size\": st.integers(min_value=0, max_value=100) | st.none(),\n}\n\nvalues = st.integers() | st.text()\n\n\nStrategies = st.recursive(\n    st.one_of(\n        st.sampled_from(\n            [\n                st.none(),\n                st.booleans(),\n                st.randoms(use_true_random=True),\n                st.complex_numbers(),\n                st.randoms(use_true_random=True),\n                st.fractions(),\n                st.decimals(),\n            ]\n        ),\n        st.builds(st.just, values),\n        st.builds(st.sampled_from, st.lists(values, min_size=1)),\n        builds_ignoring_invalid(st.floats, st.floats(), st.floats()),\n    ),\n    lambda x: st.one_of(\n        builds_ignoring_invalid(st.lists, x, **size_strategies),\n        builds_ignoring_invalid(st.sets, x, **size_strategies),\n        builds_ignoring_invalid(lambda v: st.tuples(*v), st.lists(x)),\n        builds_ignoring_invalid(lambda v: st.one_of(*v), st.lists(x, min_size=1)),\n        builds_ignoring_invalid(\n            st.dictionaries,\n            x,\n            x,\n            dict_class=st.sampled_from([dict, OrderedDict]),\n            **size_strategies,\n        ),\n        st.builds(lambda s, f: s.map(f), x, st.sampled_from(fns)),\n    ),\n)\n\n\nstrategy_globals = {k: getattr(st, k) for k in dir(st)}\n\nstrategy_globals[\"OrderedDict\"] = OrderedDict\nstrategy_globals[\"inf\"] = float(\"inf\")\nstrategy_globals[\"nan\"] = float(\"nan\")\nstrategy_globals[\"foo\"] = foo\nstrategy_globals[\"bar\"] = bar\nstrategy_globals[\"baz\"] = baz\n\n\n@given(Strategies)\ndef test_repr_evals_to_thing_with_same_repr(strategy):\n    r = repr(strategy)\n    via_eval = eval(r, strategy_globals)\n    r2 = repr(via_eval)\n    assert r == r2\n\n\n@pytest.mark.parametrize(\n    \"r\",\n    [\n        \"none().filter(foo).map(bar)\",\n        \"just(1).filter(foo).map(bar)\",\n        \"sampled_from([1, 2, 3]).filter(foo).map(bar)\",\n    ],\n)\ndef test_sampled_transform_reprs(r):\n    assert repr(eval(r, strategy_globals)) == r\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_randomization.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom random import Random\n\nimport pytest\n\nfrom hypothesis import (\n    HealthCheck,\n    Verbosity,\n    core,\n    given,\n    settings,\n    strategies as st,\n)\n\nfrom tests.common.utils import Why, no_shrink, xfail_on_crosshair\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"we do not yet pass backends the global random seed, so they are not deterministic\",\n)\ndef test_seeds_off_internal_random():\n    choices1 = []\n    choices2 = []\n\n    @given(st.integers())\n    def f1(n):\n        choices1.append(n)\n\n    @given(st.integers())\n    def f2(n):\n        choices2.append(n)\n\n    core.threadlocal._hypothesis_global_random = Random(0)\n    state = core.threadlocal._hypothesis_global_random.getstate()\n    f1()\n\n    core.threadlocal._hypothesis_global_random.setstate(state)\n    f2()\n\n    assert choices1 == choices2\n\n\n@xfail_on_crosshair(Why.nested_given)\ndef test_nesting_with_control_passes_health_check():\n    @given(st.integers(0, 100), st.random_module())\n    @settings(\n        max_examples=5,\n        database=None,\n        deadline=None,\n        suppress_health_check=[HealthCheck.nested_given],\n    )\n    def test_blah(x, rnd):\n        @given(st.integers())\n        @settings(\n            max_examples=100, phases=no_shrink, database=None, verbosity=Verbosity.quiet\n        )\n        def test_nest(y):\n            assert y < x\n\n        with pytest.raises(AssertionError):\n            test_nest()\n\n    test_blah()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_recursive.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport sys\nimport threading\n\nimport pytest\n\nfrom hypothesis import HealthCheck, given, settings, strategies as st\n\nfrom tests.common.debug import find_any, minimal\nfrom tests.common.utils import Why, flaky, xfail_if_gil_disabled, xfail_on_crosshair\n\n\ndef test_can_generate_with_large_branching():\n    def flatten(x):\n        if isinstance(x, list):\n            return sum(map(flatten, x), [])\n        else:\n            return [x]\n\n    size = 20\n\n    xs = minimal(\n        st.recursive(\n            st.integers(),\n            lambda x: st.lists(x, min_size=size // 2),\n            max_leaves=size * 2,\n        ),\n        lambda x: isinstance(x, list) and len(flatten(x)) >= size,\n    )\n    assert flatten(xs) == [0] * size\n\n\ndef test_can_generate_some_depth_with_large_branching():\n    def depth(x):\n        if x and isinstance(x, list):\n            return 1 + max(map(depth, x))\n        else:\n            return 1\n\n    xs = minimal(st.recursive(st.integers(), st.lists), lambda x: depth(x) > 1)\n    assert xs in ([0], [[]])\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\", reason=\"takes 2 hours\"\n)\ndef test_can_find_quite_broad_lists():\n    def breadth(x):\n        if isinstance(x, list):\n            return sum(map(breadth, x))\n        else:\n            return 1\n\n    target = 10\n\n    broad = minimal(\n        st.recursive(st.booleans(), lambda x: st.lists(x, max_size=target // 2)),\n        lambda x: breadth(x) >= target,\n        settings=settings(max_examples=10000),\n    )\n    assert breadth(broad) == target\n\n\ndef test_drawing_many_near_boundary():\n    size = 4\n    elems = st.recursive(\n        st.booleans(),\n        lambda x: st.lists(x, min_size=2 * (size - 1), max_size=2 * size).map(tuple),\n        max_leaves=2 * size - 1,\n    )\n    ls = minimal(st.lists(elems), lambda x: len(set(x)) >= size)\n    assert len(ls) == size\n\n\n@xfail_on_crosshair(Why.undiscovered)\ndef test_can_use_recursive_data_in_sets():\n    nested_sets = st.recursive(st.booleans(), st.frozensets, max_leaves=3)\n    find_any(nested_sets, settings=settings(deadline=None))\n\n    def flatten(x):\n        if isinstance(x, bool):\n            return frozenset((x,))\n        else:\n            result = frozenset()\n            for t in x:\n                result |= flatten(t)\n                if len(result) == 2:\n                    break\n            return result\n\n    x = minimal(nested_sets, lambda x: len(flatten(x)) == 2, settings(deadline=None))\n    assert x in (\n        frozenset((False, True)),\n        frozenset((False, frozenset((True,)))),\n        frozenset((frozenset((False, True)),)),\n    )\n\n\n@flaky(max_runs=2, min_passes=1)\ndef test_can_form_sets_of_recursive_data():\n    size = 3\n\n    trees = st.sets(\n        st.recursive(\n            st.booleans(),\n            lambda x: st.lists(x, min_size=size).map(tuple),\n            max_leaves=20,\n        )\n    )\n    xs = minimal(trees, lambda x: len(x) >= size)\n    assert len(xs) == size\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\", reason=\"not threadsafe\"\n)\ndef test_drawing_from_recursive_strategy_is_thread_safe():\n    shared_strategy = st.recursive(\n        st.integers(), lambda s: st.lists(s, max_size=2), max_leaves=20\n    )\n    errors = []\n\n    @settings(\n        database=None, deadline=None, suppress_health_check=[HealthCheck.too_slow]\n    )\n    @given(data=st.data())\n    def test(data):\n        try:\n            data.draw(shared_strategy)\n        except Exception as exc:\n            errors.append(exc)\n\n    original_recursionlimit = sys.getrecursionlimit()\n    threads = []\n    for _ in range(4):\n        threads.append(threading.Thread(target=test))\n\n    for thread in threads:\n        thread.start()\n    for thread in threads:\n        thread.join()\n\n    assert sys.getrecursionlimit() == original_recursionlimit\n    assert not errors\n\n\nSELF_REF = st.recursive(\n    st.deferred(lambda: st.booleans() | SELF_REF),\n    lambda s: st.lists(s, min_size=1),\n)\n\n\n@settings(\n    suppress_health_check=[HealthCheck.too_slow, HealthCheck.filter_too_much],\n    max_examples=5,\n)\n@given(SELF_REF)\ndef test_self_ref_regression(_):\n    # See https://github.com/HypothesisWorks/hypothesis/issues/2794\n    pass\n\n\n@pytest.mark.skipif(sys.version_info >= (3, 14), reason=\"gc changes\")\n@xfail_if_gil_disabled\n@flaky(min_passes=1, max_runs=2)\ndef test_gc_hooks_do_not_cause_unraisable_recursionerror(testdir):\n    # We were concerned in #3979 that we might see bad results from a RecursionError\n    # inside the GC hook, if the stack was already deep and someone (e.g. Pytest)\n    # had installed a sys.unraisablehook which raises that later.\n\n    # This test is potentially flaky, because the stack usage of a function is not\n    # constant. Regardless, if the test passes just once that's sufficient proof that\n    # it's not the GC (or accounting of it) that is at fault. Note, I haven't actually\n    # seen it fail/flake, but I believe it could happen in principle.\n    #\n    # What we *have* seen on CI with xdist is flaky segmentation faults. Hence, the\n    # test is executed in a subprocess.\n    script = \"\"\"\n    import gc\n    import pytest\n\n    from hypothesis import given, strategies as st\n\n    # The number of cycles sufficient to reliably trigger GC, experimentally found\n    # to be a few hundred on CPython. Multiply by 10 for safety margin.\n    NUM_CYCLES = 5_000\n\n    def probe_depth():\n        try:\n            return probe_depth() + 1\n        except RecursionError:\n            return 0\n\n    def at_depth(depth, fn):\n        if depth <= 1:\n            return fn()\n        else:\n            # Recurse towards requested depth\n            return at_depth(depth - 1, fn)\n\n    def gen_cycles():\n        for _ in range(NUM_CYCLES):\n            a = [None]\n            b = [a]\n            a[0] = b\n\n    def gen_cycles_at_depth(depth, *, gc_disable):\n        try:\n            if gc_disable:\n                gc.disable()\n            at_depth(depth, gen_cycles)\n            dead_objects = gc.collect()\n            if dead_objects is not None:  # is None on PyPy\n                if gc_disable:\n                    assert dead_objects >= 2 * NUM_CYCLES\n                else:\n                    # collection was triggered\n                    assert dead_objects < 2 * NUM_CYCLES\n        finally:\n            gc.enable()\n\n    # Warmup to de-flake PyPy (the first run has much lower effective limits)\n    probe_depth()\n\n    @given(st.booleans())\n    def test_gc_hooks_recursive(_):\n        max_depth = probe_depth()\n\n        # Lower the limit to where we can successfully generate cycles\n        # when no gc is performed\n        while True:\n            try:\n                gen_cycles_at_depth(max_depth, gc_disable=True)\n            except RecursionError:\n                max_depth -= 1\n            else:\n                break\n            # Note that PyPy is a bit weird, in that it raises RecursionError at\n            # (maxdepth - n) for small positive n, but not at exactly (maxdepth).\n            # In general, it is really finicky to get the details right in this\n            # test, so be careful.\n\n        # Now check that the limit is unchanged with gc enabled, and also that\n        # leaving a few frames for the callbacks does not fail.\n        if hasattr(gc, \"callbacks\"):  # see comment above\n            for n in range(1, 4):\n                gen_cycles_at_depth(max_depth - n, gc_disable=False)\n        gen_cycles_at_depth(max_depth, gc_disable=False)\n        with pytest.raises(RecursionError):\n            gen_cycles_at_depth(max_depth + 1, gc_disable=False)\n    \"\"\"\n    testdir.makepyfile(script)\n    testdir.runpytest_subprocess().assert_outcomes(passed=1)\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_regex.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\nimport string\nimport sys\nfrom functools import reduce\n\nimport pytest\n\nfrom hypothesis import assume, given, reject, strategies as st\nfrom hypothesis.strategies._internal.regex import (\n    IncompatibleWithAlphabet,\n    base_regex_strategy,\n)\n\n\n@st.composite\ndef charset(draw):\n    negated = draw(st.booleans())\n    chars = draw(st.text(string.ascii_letters + string.digits, min_size=1))\n    if negated:\n        return f\"[^{chars}]\"\n    else:\n        return f\"[{chars}]\"\n\n\nCOMBINED_MATCHER = re.compile(\"[?+*]{2}\")\n\n\n@st.composite\ndef conservative_regex(draw):\n    result = draw(\n        st.one_of(\n            st.just(\".\"),\n            st.sampled_from([re.escape(c) for c in string.printable]),\n            charset(),\n            CONSERVATIVE_REGEX.map(lambda s: f\"({s})\"),\n            CONSERVATIVE_REGEX.map(lambda s: s + \"+\"),\n            CONSERVATIVE_REGEX.map(lambda s: s + \"?\"),\n            CONSERVATIVE_REGEX.map(lambda s: s + \"*\"),\n            st.lists(CONSERVATIVE_REGEX, min_size=1, max_size=3).map(\"|\".join),\n            st.lists(CONSERVATIVE_REGEX, min_size=1, max_size=3).map(\"\".join),\n        )\n    )\n    assume(COMBINED_MATCHER.search(result) is None)\n    control = sum(result.count(c) for c in \"?+*\")\n    assume(control <= 3)\n    assume(I_WITH_DOT not in result)  # known to be weird\n    return result\n\n\nCONSERVATIVE_REGEX = conservative_regex()\nFLAGS = st.sets(\n    st.sampled_from([re.ASCII, re.IGNORECASE, re.MULTILINE, re.DOTALL])\n).map(lambda flag_set: reduce(int.__or__, flag_set, 0))\n\n\n@given(st.data())\ndef test_conservative_regex_are_correct_by_construction(data):\n    pattern = re.compile(data.draw(CONSERVATIVE_REGEX), flags=data.draw(FLAGS))\n    result = data.draw(base_regex_strategy(pattern, alphabet=st.characters()))\n    # We'll skip \"capital I with dot above\" due to awful casefolding behaviour\n    # and \"latin small letter dotless i\" for the same reason.\n    assume({\"ı\", \"İ\"}.isdisjoint(pattern.pattern + result))\n    assert pattern.search(result) is not None\n\n\n@given(st.data())\ndef test_fuzz_stuff(data):\n    pattern = data.draw(\n        st.text(min_size=1, max_size=5)\n        | st.binary(min_size=1, max_size=5)\n        | CONSERVATIVE_REGEX.filter(bool)\n    )\n    flags = data.draw(FLAGS)\n\n    try:\n        regex = re.compile(pattern, flags=flags)\n    except (re.error, FutureWarning):\n        # Possible nested sets, e.g. \"[[\", trigger a FutureWarning\n        reject()\n\n    try:\n        ex = data.draw(st.from_regex(regex))\n    except IncompatibleWithAlphabet:\n        if isinstance(pattern, str) and flags & re.ASCII:\n            with pytest.raises(UnicodeEncodeError):\n                pattern.encode(\"ascii\")\n            regex = re.compile(pattern, flags=flags ^ re.ASCII)\n            ex = data.draw(st.from_regex(regex))\n        else:\n            raise\n\n    assert regex.search(ex)\n\n\n@pytest.mark.skipif(sys.version_info[:2] < (3, 11), reason=\"new syntax\")\n@given(st.data())\ndef test_regex_atomic_group(data):\n    pattern = \"a(?>bc|b)c\"\n    ex = data.draw(st.from_regex(pattern))\n    assert re.search(pattern, ex)\n\n\n@pytest.mark.skipif(sys.version_info[:2] < (3, 11), reason=\"new syntax\")\n@given(st.data())\ndef test_regex_possessive(data):\n    pattern = '\"[^\"]*+\"'\n    ex = data.draw(st.from_regex(pattern))\n    assert re.search(pattern, ex)\n\n\n# Some preliminaries, to establish what's happening:\nI_WITH_DOT = \"\\u0130\"\nassert I_WITH_DOT.swapcase() == \"i\\u0307\"  # note: string of length two!\nassert re.compile(I_WITH_DOT, flags=re.IGNORECASE).match(I_WITH_DOT.swapcase())\n\n\n@given(st.data())\ndef test_case_insensitive_not_literal_never_constructs_multichar_match(data):\n    # So our goal is to confirm that we can never accidentally create a non-matching\n    # string by assembling individually allowed characters.\n    pattern = re.compile(f\"[^{I_WITH_DOT}]+\", flags=re.IGNORECASE)\n    strategy = st.from_regex(pattern, fullmatch=True)\n    for _ in range(5):\n        s = data.draw(strategy)\n        assert pattern.fullmatch(s) is not None\n        # And to be on the safe side, we implement this stronger property:\n        assert set(s).isdisjoint(I_WITH_DOT.swapcase())\n\n\n@given(st.from_regex(re.compile(f\"[^{I_WITH_DOT}_]\", re.IGNORECASE), fullmatch=True))\ndef test_no_error_converting_negated_sets_to_strategy(s):\n    # CharactersBuilder no longer triggers an internal error converting sets\n    # or negated sets to a strategy when multi-char strings are whitelisted.\n    pass\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_regressions.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis._settings import note_deprecation\nfrom hypothesis.errors import HypothesisDeprecationWarning\n\nfrom tests.common.utils import Why, xfail_on_crosshair\n\n\ndef test_note_deprecation_blames_right_code_issue_652():\n    msg = \"this is an arbitrary deprecation warning message\"\n\n    @st.composite\n    def deprecated_strategy(draw):\n        draw(st.none())\n        note_deprecation(msg, since=\"RELEASEDAY\", has_codemod=False)\n\n    @given(deprecated_strategy())\n    def f(x):\n        pass\n\n    with pytest.warns(HypothesisDeprecationWarning) as log:\n        f()\n\n    assert len(log) == 1\n    (record,) = log\n    # We got the warning we expected, from the right file\n    assert isinstance(record.message, HypothesisDeprecationWarning)\n    assert record.message.args == (msg,)\n    assert record.filename == __file__\n\n\n@given(\n    x=st.one_of(st.just(0) | st.just(1)),\n    y=st.one_of(st.just(0) | st.just(1) | st.just(2)),\n)\ndef test_performance_issue_2027(x, y):\n    pass\n\n\n@given(\n    st.lists(\n        st.floats(allow_infinity=False),\n        unique=True,\n    )\n)\ndef test_unique_floats_with_nan_is_not_flaky_3926(ls):\n    pass\n\n\n# this will take a while to find the regression, but will eventually trigger it.\n# min_value=0 is critical to trigger the probing behavior which exhausts our buffer.\n# https://github.com/pschanely/CrossHair/issues/285 for an upstream fix.\n@xfail_on_crosshair(Why.other, strict=False)\n@given(st.integers(min_value=0, max_value=1 << 25_000))\ndef test_overrun_during_datatree_simulation_3874(n):\n    pass\n\n\ndef test_explain_phase_label_assertion_4339():\n    # st.composite causes a re-creation of the SampledFromStrategy each time\n    # (one_of is implemented using sampled_from internally), which previously\n    # had different labels which triggered an assertion in the explain code.\n    @st.composite\n    def g(draw):\n        draw(st.none() | st.booleans())\n\n    @given(g(), st.none() | st.booleans())\n    @settings(database=None)\n    def f(a, b):\n        raise ValueError(\"marker\")\n\n    with pytest.raises(ValueError, match=\"marker\"):\n        f()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_reusable_values.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import example, given, strategies as st\nfrom hypothesis.errors import InvalidArgument\n\n# Be aware that tests in this file pass strategies as arguments to @example.\n# That's normally a mistake, but for these tests it's intended.\n# If one of these tests fails, Hypothesis will complain about the\n# @example/strategy interaction, but it should be safe to ignore that\n# error message and focus on the underlying failure instead.\n\nbase_reusable_strategies = (\n    st.text(),\n    st.binary(),\n    st.dates(),\n    st.times(),\n    st.timedeltas(),\n    st.booleans(),\n    st.complex_numbers(),\n    st.floats(),\n    st.floats(-1.0, 1.0),\n    st.integers(),\n    st.integers(1, 10),\n    st.integers(1),\n    # Note that `just` and `sampled_from` count as \"reusable\" even if their\n    # values are mutable, because the user has implicitly promised that they\n    # don't care about the same mutable value being returned by separate draws.\n    st.just([]),\n    st.sampled_from([[]]),\n    st.tuples(st.integers()),\n)\n\n\n@st.deferred\ndef reusable():\n    \"\"\"Meta-strategy that produces strategies that should have\n    ``.has_reusable_values == True``.\"\"\"\n    return st.one_of(\n        # This looks like it should be `one_of`, but `sampled_from` is correct\n        # because we want this meta-strategy to yield strategies as its values.\n        st.sampled_from(base_reusable_strategies),\n        # This sometimes produces invalid combinations of arguments, which\n        # we filter out further down with an explicit validation check.\n        st.builds(\n            st.floats,\n            min_value=st.none() | st.floats(allow_nan=False),\n            max_value=st.none() | st.floats(allow_nan=False),\n            allow_infinity=st.booleans(),\n            allow_nan=st.booleans(),\n        ),\n        st.builds(st.just, st.builds(list)),\n        st.builds(st.sampled_from, st.lists(st.builds(list), min_size=1)),\n        st.lists(reusable).map(st.one_of),\n        st.lists(reusable).map(lambda ls: st.tuples(*ls)),\n    )\n\n\ndef is_valid(s):\n    try:\n        s.validate()\n        return True\n    except InvalidArgument:\n        return False\n\n\nreusable = reusable.filter(is_valid)\n\nassert not reusable.is_empty\n\n\ndef many_examples(examples):\n    \"\"\"Helper decorator to apply the ``@example`` decorator multiple times,\n    once for each given example.\"\"\"\n\n    def accept(f):\n        for e in examples:\n            f = example(e)(f)\n        return f\n\n    return accept\n\n\n@many_examples(base_reusable_strategies)\n@many_examples(st.tuples(s) for s in base_reusable_strategies)\n@given(reusable)\ndef test_reusable_strategies_are_all_reusable(s):\n    assert s.has_reusable_values\n\n\n@many_examples(base_reusable_strategies)\n@given(reusable)\ndef test_filter_breaks_reusability(s):\n    cond = True\n\n    def nontrivial_filter(x):\n        \"\"\"Non-trivial filtering function, intended to remain opaque even if\n        some strategies introspect their filters.\"\"\"\n        return cond\n\n    assert s.has_reusable_values\n    assert not s.filter(nontrivial_filter).has_reusable_values\n\n\n@many_examples(base_reusable_strategies)\n@given(reusable)\ndef test_map_breaks_reusability(s):\n    cond = True\n\n    def nontrivial_map(x):\n        \"\"\"Non-trivial mapping function, intended to remain opaque even if\n        some strategies introspect their mappings.\"\"\"\n        if cond:\n            return x\n        else:\n            return None\n\n    assert s.has_reusable_values\n    assert not s.map(nontrivial_map).has_reusable_values\n\n\n@many_examples(base_reusable_strategies)\n@given(reusable)\ndef test_flatmap_breaks_reusability(s):\n    cond = True\n\n    def nontrivial_flatmap(x):\n        \"\"\"Non-trivial flat-mapping function, intended to remain opaque even\n        if some strategies introspect their flat-mappings.\"\"\"\n        if cond:\n            return st.just(x)\n        else:\n            return st.none()\n\n    assert s.has_reusable_values\n    assert not s.flatmap(nontrivial_flatmap).has_reusable_values\n\n\n@pytest.mark.parametrize(\n    \"strat\",\n    [\n        st.lists(st.booleans()),\n        st.sets(st.booleans()),\n        st.dictionaries(st.booleans(), st.booleans()),\n    ],\n)\ndef test_mutable_collections_do_not_have_reusable_values(strat):\n    assert not strat.has_reusable_values\n\n\ndef test_recursion_does_not_break_reusability():\n    x = st.deferred(lambda: st.none() | st.tuples(x))\n    assert x.has_reusable_values\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_sampled_from.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport enum\nimport functools\nimport itertools\nimport operator\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.internal.compat import bit_count\nfrom hypothesis.strategies._internal.strategies import SampledFromStrategy\n\nfrom tests.common.debug import find_any, minimal\nfrom tests.common.utils import fails_with\n\n\n@pytest.mark.parametrize(\"size\", [100, 10**5, 10**6, 2**25])\n@given(data=st.data())\ndef test_filter_large_lists(data, size):\n    n_calls = 0\n\n    def cond(x):\n        nonlocal n_calls\n        n_calls += 1\n        return x % 2 != 0\n\n    s = data.draw(st.sampled_from(range(size)).filter(cond))\n\n    assert s % 2 != 0\n    assert n_calls <= SampledFromStrategy._MAX_FILTER_CALLS\n\n\ndef rare_value_strategy(n, target):\n    def forbid(s, forbidden):\n        \"\"\"Helper function to avoid Python variable scoping issues.\"\"\"\n        return s.filter(lambda x: x != forbidden)\n\n    s = st.sampled_from(range(n))\n    for i in range(n):\n        if i != target:\n            s = forbid(s, i)\n\n    return s\n\n\n@given(rare_value_strategy(n=128, target=80))\ndef test_chained_filters_find_rare_value(x):\n    assert x == 80\n\n\n@fails_with(InvalidArgument)\n@given(st.sets(st.sampled_from(range(10)), min_size=11))\ndef test_unsat_sets_of_samples(x):\n    raise AssertionError\n\n\n@given(st.sets(st.sampled_from(range(50)), min_size=50))\ndef test_efficient_sets_of_samples(x):\n    assert x == set(range(50))\n\n\nclass AnEnum(enum.Enum):\n    a = enum.auto()\n    b = enum.auto()\n\n\ndef test_enum_repr_uses_class_not_a_list():\n    # The repr should have enough detail to find the class again\n    # (which is very useful for the ghostwriter logic we're working on)\n    lazy_repr = repr(st.sampled_from(AnEnum))\n    assert lazy_repr == \"sampled_from(tests.nocover.test_sampled_from.AnEnum)\"\n\n\ndef test_repr_truncates_with_many_elements():\n    s = st.sampled_from(list(range(10_000)))\n    repr_limit = 512\n    assert repr(s) == f\"sampled_from([{', '.join(map(str, range(repr_limit)))}, ...])\"\n\n\nclass AFlag(enum.Flag):\n    a = enum.auto()\n    b = enum.auto()\n    c = enum.auto()\n\n\nLargeFlag = enum.Flag(\"LargeFlag\", {f\"bit{i}\": enum.auto() for i in range(64)})\n\n\nclass UnnamedFlag(enum.Flag):\n    # Would fail under EnumCheck.NAMED_FLAGS\n    a = 0\n    b = 7\n\n\ndef test_flag_enum_repr_uses_class_not_a_list():\n    lazy_repr = repr(st.sampled_from(AFlag))\n    assert lazy_repr == \"sampled_from(tests.nocover.test_sampled_from.AFlag)\"\n\n\ndef test_exhaustive_flags():\n    # Generate powerset of flag combinations. There are only 2^3 of them, so\n    # we can reasonably expect that they are all are found.\n    unseen_flags = {\n        functools.reduce(operator.or_, flaglist, AFlag(0))\n        for r in range(len(AFlag) + 1)\n        for flaglist in itertools.combinations(AFlag, r)\n    }\n\n    @given(st.sampled_from(AFlag))\n    def accept(flag):\n        unseen_flags.discard(flag)\n\n    accept()\n\n    assert not unseen_flags\n\n\ndef test_flags_minimize_to_first_named_flag():\n    assert minimal(st.sampled_from(LargeFlag)) == LargeFlag.bit0\n\n\ndef test_flags_minimizes_bit_count():\n    assert (\n        minimal(st.sampled_from(LargeFlag), lambda f: bit_count(f.value) > 1)\n        == LargeFlag.bit0 | LargeFlag.bit1\n    )\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"takes ~10 mins; path tree is too large\",\n)\ndef test_flags_finds_all_bits_set():\n    assert find_any(st.sampled_from(LargeFlag), lambda f: f == ~LargeFlag(0))\n\n\ndef test_sample_unnamed_alias():\n    assert find_any(st.sampled_from(UnnamedFlag), lambda f: f == UnnamedFlag.b)\n\n\ndef test_shrink_to_named_empty():\n    assert minimal(st.sampled_from(UnnamedFlag)) == UnnamedFlag(0)\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_scrutineer.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport json\nimport sys\nimport sysconfig\n\nimport pytest\n\nfrom hypothesis import given, note, settings, strategies as st\nfrom hypothesis.internal.compat import PYPY\nfrom hypothesis.internal.scrutineer import make_report\nfrom hypothesis.vendor import pretty\n\nfrom tests.common.utils import skipif_threading\n\n# We skip tracing for explanations under PyPy, where it has a large performance\n# impact, or if there is already a trace function (e.g. coverage or a debugger)\npytestmark = pytest.mark.skipif(PYPY or sys.gettrace(), reason=\"See comment\")\n\nBUG_MARKER = \"# BUG\"\nDEADLINE_PRELUDE = \"\"\"\nfrom datetime import timedelta\nfrom hypothesis.errors import DeadlineExceeded\n\"\"\"\nPRELUDE = \"\"\"\nfrom hypothesis import Phase, given, settings, strategies as st\n\n@settings(phases=tuple(Phase), derandomize=True)\n\"\"\"\nTRIVIAL = \"\"\"\n@given(st.integers())\ndef test_reports_branch_in_test(x):\n    if x > 10:\n        raise AssertionError  # BUG\n\"\"\"\nMULTIPLE_BUGS = \"\"\"\n@given(st.integers(), st.integers())\ndef test_reports_branch_in_test(x, y):\n    if x > 10:\n        raise (AssertionError if x % 2 else Exception)  # BUG\n\"\"\"\nFRAGMENTS = (\n    pytest.param(TRIVIAL, id=\"trivial\"),\n    pytest.param(MULTIPLE_BUGS, id=\"multiple-bugs\"),\n)\n\n\ndef get_reports(file_contents, *, testdir):\n    # Takes the source code string with \"# BUG\" comments, and returns a list of\n    # multi-line report strings which we expect to see in explain-mode output.\n    # The list length is the number of explainable bugs, usually one.\n    test_file = str(testdir.makepyfile(file_contents))\n    pytest_stdout = str(testdir.runpytest_inprocess(test_file, \"--tb=native\").stdout)\n\n    crash = \"AttributeError: module 'blib2to3.pygram' has no attribute 'python_symbols'\"\n    if crash in pytest_stdout:\n        pytest.xfail(reason=\"upstream error in Black\")\n\n    explanations = {\n        i: {(test_file, i)}\n        for i, line in enumerate(file_contents.splitlines())\n        if line.endswith(BUG_MARKER)\n    }\n    expected = [\n        (\"\\n\".join(r), \"\\n    | \".join(r))  # single, ExceptionGroup\n        for r in make_report(explanations).values()\n    ]\n    return pytest_stdout, expected\n\n\n@skipif_threading  # runpytest_inprocess is not thread safe\n@pytest.mark.parametrize(\"code\", FRAGMENTS)\ndef test_explanations(code, testdir):\n    pytest_stdout, expected = get_reports(PRELUDE + code, testdir=testdir)\n    assert len(expected) == code.count(BUG_MARKER)\n    for single, group in expected:\n        assert single in pytest_stdout or group in pytest_stdout\n\n\n@skipif_threading  # runpytest_inprocess is not thread safe\n@pytest.mark.parametrize(\"code\", FRAGMENTS)\ndef test_no_explanations_if_deadline_exceeded(code, testdir):\n    code = code.replace(\"AssertionError\", \"DeadlineExceeded(timedelta(), timedelta())\")\n    pytest_stdout, _ = get_reports(DEADLINE_PRELUDE + PRELUDE + code, testdir=testdir)\n    assert \"Explanation:\" not in pytest_stdout\n\n\nNO_SHOW_CONTEXTLIB = \"\"\"\nfrom contextlib import contextmanager\nfrom hypothesis import given, strategies as st, Phase, settings\n\n@contextmanager\ndef ctx():\n    yield\n\n@settings(phases=list(Phase))\n@given(st.integers())\ndef test(x):\n    with ctx():\n        assert x < 100\n\"\"\"\n\n\n@skipif_threading  # runpytest_inprocess is not thread safe\n@pytest.mark.skipif(PYPY, reason=\"Tracing is slow under PyPy\")\ndef test_skips_uninformative_locations(testdir):\n    pytest_stdout, _ = get_reports(NO_SHOW_CONTEXTLIB, testdir=testdir)\n    assert \"Explanation:\" not in pytest_stdout\n\n\n@given(st.randoms())\n@settings(max_examples=5)\ndef test_report_sort(random):\n    # show local files first, then site-packages, then stdlib\n\n    lines = [\n        # local\n        (__file__, 10),\n        # site-packages\n        (pytest.__file__, 123),\n        (pytest.__file__, 124),\n        # stdlib\n        (json.__file__, 43),\n        (json.__file__, 42),\n    ]\n    random.shuffle(lines)\n    explanations = {\"origin\": lines}\n    report = make_report(explanations)\n    report_lines = report[\"origin\"][2:]\n    report_lines = [line.strip() for line in report_lines]\n\n    expected_lines = [\n        f\"{__file__}:10\",\n        f\"{pytest.__file__}:123\",\n        f\"{pytest.__file__}:124\",\n        f\"{json.__file__}:42\",\n        f\"{json.__file__}:43\",\n    ]\n\n    note(f\"sysconfig.get_paths(): {pretty.pretty(sysconfig.get_paths())}\")\n    note(f\"actual lines: {pretty.pretty(report_lines)}\")\n    note(f\"expected lines: {pretty.pretty(expected_lines)}\")\n\n    assert report_lines == expected_lines\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_sets.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, settings\nfrom hypothesis.strategies import floats, integers, sets\n\nfrom tests.common.debug import find_any\n\n\ndef test_can_draw_sets_of_hard_to_find_elements():\n    rarebool = floats(0, 1).map(lambda x: x <= 0.05)\n    find_any(sets(rarebool, min_size=2), settings=settings(deadline=None))\n\n\n@given(sets(integers(), max_size=0))\ndef test_empty_sets(x):\n    assert x == set()\n\n\n@given(sets(integers(), max_size=2))\ndef test_bounded_size_sets(x):\n    assert len(x) <= 2\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_sharing.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, strategies as st\n\nfrom tests.common.debug import find_any, minimal\n\nx = st.shared(st.integers())\n\n\n@given(x, x)\ndef test_sharing_is_by_instance_by_default(a, b):\n    assert a == b\n\n\n@given(st.shared(st.integers(), key=\"hi\"), st.shared(st.integers(), key=\"hi\"))\ndef test_different_instances_with_the_same_key_are_shared(a, b):\n    assert a == b\n\n\ndef test_different_instances_are_not_shared():\n    find_any(\n        st.tuples(st.shared(st.integers()), st.shared(st.integers())),\n        lambda x: x[0] != x[1],\n    )\n\n\ndef test_different_keys_are_not_shared():\n    find_any(\n        st.tuples(st.shared(st.integers(), key=1), st.shared(st.integers(), key=2)),\n        lambda x: x[0] != x[1],\n    )\n\n\ndef test_keys_and_default_are_not_shared():\n    find_any(\n        st.tuples(st.shared(st.integers(), key=1), st.shared(st.integers())),\n        lambda x: x[0] != x[1],\n    )\n\n\ndef test_can_simplify_shared_lists():\n    xs = minimal(\n        st.lists(st.shared(st.integers())), lambda x: len(x) >= 10 and x[0] != 0\n    )\n    assert xs == [1] * 10\n\n\ndef test_simplify_shared_linked_to_size():\n    xs = minimal(st.lists(st.shared(st.integers())), lambda t: sum(t) >= 1000)\n    assert sum(xs[:-1]) < 1000\n    assert (xs[0] - 1) * len(xs) < 1000\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_simple_numbers.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nimport sys\n\nimport pytest\n\nfrom hypothesis import given\nfrom hypothesis.strategies import floats, integers, lists\n\nfrom tests.common.debug import minimal\nfrom tests.common.utils import Why, xfail_on_crosshair\n\n\ndef test_minimize_negative_int():\n    assert minimal(integers(), lambda x: x < 0) == -1\n    assert minimal(integers(), lambda x: x < -1) == -2\n\n\ndef test_positive_negative_int():\n    assert minimal(integers(), lambda x: x > 0) == 1\n    assert minimal(integers(), lambda x: x > 1) == 2\n\n\nboundaries = pytest.mark.parametrize(\n    \"boundary\",\n    sorted(\n        [2**i for i in range(10)]\n        + [2**i - 1 for i in range(10)]\n        + [2**i + 1 for i in range(10)]\n        + [10**i for i in range(6)]\n    ),\n)\n\n\n@boundaries\ndef test_minimizes_int_down_to_boundary(boundary):\n    assert minimal(integers(), lambda x: x >= boundary) == boundary\n\n\n@boundaries\ndef test_minimizes_int_up_to_boundary(boundary):\n    assert minimal(integers(), lambda x: x <= -boundary) == -boundary\n\n\n@boundaries\ndef test_minimizes_ints_from_down_to_boundary(boundary):\n    def is_good(x):\n        assert x >= boundary - 10\n        return x >= boundary\n\n    assert minimal(integers(min_value=boundary - 10), is_good) == boundary\n\n    assert minimal(integers(min_value=boundary)) == boundary\n\n\ndef test_minimizes_negative_integer_range_upwards():\n    assert minimal(integers(min_value=-10, max_value=-1)) == -1\n\n\n@boundaries\ndef test_minimizes_integer_range_to_boundary(boundary):\n    assert minimal(integers(boundary, boundary + 100)) == boundary\n\n\ndef test_single_integer_range_is_range():\n    assert minimal(integers(1, 1)) == 1\n\n\ndef test_minimal_small_number_in_large_range():\n    assert minimal(integers((-(2**32)), 2**32), lambda x: x >= 101) == 101\n\n\ndef test_minimal_small_sum_float_list():\n    xs = minimal(lists(floats(), min_size=5), lambda x: sum(x) >= 1.0)\n    assert xs == [0.0, 0.0, 0.0, 0.0, 1.0]\n\n\ndef test_minimals_boundary_floats():\n    def f(x):\n        print(x)\n        return True\n\n    assert minimal(floats(min_value=-1, max_value=1), f) == 0\n\n\ndef test_minimal_non_boundary_float():\n    x = minimal(floats(min_value=1, max_value=9), lambda x: x > 2)\n    assert x == 3  # (the smallest integer > 2)\n\n\ndef test_minimal_float_is_zero():\n    assert minimal(floats()) == 0.0\n\n\ndef test_minimal_asymetric_bounded_float():\n    assert minimal(floats(min_value=1.1, max_value=1.6)) == 1.5\n\n\ndef test_negative_floats_simplify_to_zero():\n    assert minimal(floats(), lambda x: x <= -1.0) == -1.0\n\n\ndef test_minimal_infinite_float_is_positive():\n    assert minimal(floats(), math.isinf) == math.inf\n\n\ndef test_can_minimal_infinite_negative_float():\n    assert minimal(floats(), lambda x: x < -sys.float_info.max)\n\n\n# Flakey under CrossHair; see https://github.com/pschanely/hypothesis-crosshair/issues/28\n@xfail_on_crosshair(Why.undiscovered, strict=False)\ndef test_can_minimal_float_on_boundary_of_representable():\n    minimal(floats(), lambda x: x + 1 == x and not math.isinf(x))\n\n\ndef test_minimize_nan():\n    assert math.isnan(minimal(floats(), math.isnan))\n\n\ndef test_minimize_very_large_float():\n    t = sys.float_info.max / 2\n    assert minimal(floats(), lambda x: x >= t) == t\n\n\ndef is_integral(value):\n    try:\n        return int(value) == value\n    except (OverflowError, ValueError):\n        return False\n\n\ndef test_can_minimal_float_far_from_integral():\n    minimal(floats(), lambda x: math.isfinite(x) and not is_integral(x * (2**32)))\n\n\ndef test_list_of_fractional_float():\n    assert set(\n        minimal(\n            lists(floats(), min_size=5),\n            lambda x: len([t for t in x if t >= 1.5]) >= 5,\n        )\n    ) == {2}\n\n\ndef test_minimal_fractional_float():\n    assert minimal(floats(), lambda x: x >= 1.5) == 2\n\n\n@xfail_on_crosshair(Why.undiscovered)  # Ineffective CrossHair decision heuristics here\ndef test_minimizes_lists_of_negative_ints_up_to_boundary():\n    result = minimal(\n        lists(integers(), min_size=10),\n        lambda x: len([t for t in x if t <= -1]) >= 10,\n    )\n    assert result == [-1] * 10\n\n\n@pytest.mark.parametrize(\n    (\"left\", \"right\"),\n    [(0.0, 5e-324), (-5e-324, 0.0), (-5e-324, 5e-324), (5e-324, 1e-323)],\n)\ndef test_floats_in_constrained_range(left, right):\n    @given(floats(left, right))\n    def test_in_range(r):\n        assert left <= r <= right\n\n    test_in_range()\n\n\ndef test_bounds_are_respected():\n    assert minimal(floats(min_value=1.0)) == 1.0\n    assert minimal(floats(max_value=-1.0)) == -1.0\n\n\n@pytest.mark.parametrize(\"k\", range(10))\ndef test_floats_from_zero_have_reasonable_range(k):\n    n = 10**k\n    assert minimal(floats(min_value=0.0), lambda x: x >= n) == float(n)\n    assert minimal(floats(max_value=0.0), lambda x: x <= -n) == float(-n)\n\n\ndef test_explicit_allow_nan():\n    minimal(floats(allow_nan=True), math.isnan)\n\n\ndef test_one_sided_contains_infinity():\n    minimal(floats(min_value=1.0), math.isinf)\n    minimal(floats(max_value=1.0), math.isinf)\n\n\n@given(floats(min_value=0.0, allow_infinity=False))\ndef test_no_allow_infinity_upper(x):\n    assert not math.isinf(x)\n\n\n@given(floats(max_value=0.0, allow_infinity=False))\ndef test_no_allow_infinity_lower(x):\n    assert not math.isinf(x)\n\n\nclass TestFloatsAreFloats:\n    @given(floats())\n    def test_unbounded(self, arg):\n        assert isinstance(arg, float)\n\n    @given(floats(min_value=0, max_value=float(2**64 - 1)))\n    def test_int_float(self, arg):\n        assert isinstance(arg, float)\n\n    @given(floats(min_value=float(0), max_value=float(2**64 - 1)))\n    def test_float_float(self, arg):\n        assert isinstance(arg, float)\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_simple_strings.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport unicodedata\n\nimport pytest\n\nfrom hypothesis import given, settings\nfrom hypothesis.strategies import text\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"takes ~10 minutes; many-valued realization is slow\",\n)\n@given(text(min_size=1, max_size=1))\n@settings(max_examples=2000)\ndef test_does_not_generate_surrogates(t):\n    assert unicodedata.category(t) != \"Cs\"\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_skipping.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport unittest\n\nimport pytest\nfrom _pytest.outcomes import Skipped\n\nfrom hypothesis import given, settings\nfrom hypothesis.core import skip_exceptions_to_reraise\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.strategies import integers\n\nfrom tests.common.utils import capture_out\n\n\n@pytest.mark.parametrize(\"skip_exception\", skip_exceptions_to_reraise())\ndef test_no_falsifying_example_if_unittest_skip(skip_exception):\n    \"\"\"If a ``SkipTest`` exception is raised during a test, Hypothesis should\n    not continue running the test and shrink process, nor should it print\n    anything about falsifying examples.\"\"\"\n\n    class DemoTest(unittest.TestCase):\n        @given(xs=integers())\n        def test_to_be_skipped(self, xs):\n            if xs == 0:\n                raise skip_exception\n            else:\n                assert xs == 0\n\n    with capture_out() as o:\n        suite = unittest.defaultTestLoader.loadTestsFromTestCase(DemoTest)\n        unittest.TextTestRunner().run(suite)\n\n    assert \"Falsifying example\" not in o.getvalue()\n\n\ndef test_skip_exceptions_save_database_entries():\n    \"\"\"Skip exceptions should save database entries for immediate replay (issue #4484).\"\"\"\n    database = InMemoryExampleDatabase()\n    call_count = 0\n    skip_value = None\n    first_value = None\n\n    @settings(database=database, max_examples=100)\n    @given(integers())\n    def test_func(n):\n        nonlocal call_count, skip_value, first_value\n        call_count += 1\n        if first_value is None:\n            first_value = n\n\n        # Skip on the 5th value in the first run (the choice of 5 is arbitrary)\n        if call_count == 5 and skip_value is None:\n            skip_value = n\n\n        if n == skip_value:\n            pytest.skip()\n\n    # First run should raise a skip exception and save to database\n    with pytest.raises(Skipped):\n        test_func()\n    assert sum(len(v) for v in database.data.values()) == 1\n\n    # Second run should immediately replay the skip value\n    first_value = None\n    call_count = 0\n    with pytest.raises(Skipped):\n        test_func()\n\n    # first call should be the replayed skip value\n    assert first_value == skip_value\n    assert call_count == 1\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_stateful.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport inspect\nfrom collections import namedtuple\n\nimport pytest\n\nfrom hypothesis import Phase, settings as Settings, strategies as st\nfrom hypothesis.stateful import (\n    Bundle,\n    RuleBasedStateMachine,\n    invariant,\n    precondition,\n    rule,\n    run_state_machine_as_test,\n)\n\nfrom tests.common.utils import Why\n\n\ndef run_to_notes(TestClass):\n    TestCase = TestClass.TestCase\n    # don't add explain phase notes to the error\n    TestCase.settings = Settings(phases=set(Phase) - {Phase.explain}, max_examples=500)\n    try:\n        TestCase().runTest()\n    except AssertionError as err:\n        return err.__notes__\n\n    raise RuntimeError(\"Expected an assertion error\")\n\n\ndef assert_runs_to_output(TestClass, output):\n    # remove the first line, which is always \"Falsfying example:\"\n    actual = \"\\n\".join(run_to_notes(TestClass)[1:])\n    assert actual == inspect.cleandoc(output.strip())\n\n\nLeaf = namedtuple(\"Leaf\", (\"label\",))\nSplit = namedtuple(\"Split\", (\"left\", \"right\"))\n\n\nclass BalancedTrees(RuleBasedStateMachine):\n    trees = Bundle(\"BinaryTree\")\n\n    @rule(target=trees, x=st.booleans())\n    def leaf(self, x):\n        return Leaf(x)\n\n    @rule(target=trees, left=trees, right=trees)\n    def split(self, left, right):\n        return Split(left, right)\n\n    @rule(tree=trees)\n    def test_is_balanced(self, tree):\n        if isinstance(tree, Leaf):\n            return\n\n        assert abs(self.size(tree.left) - self.size(tree.right)) <= 1\n        self.test_is_balanced(tree.left)\n        self.test_is_balanced(tree.right)\n\n    def size(self, tree):\n        if isinstance(tree, Leaf):\n            return 1\n        else:\n            return 1 + self.size(tree.left) + self.size(tree.right)\n\n\nclass DepthCharge:\n    def __init__(self, value):\n        if value is None:\n            self.depth = 0\n        else:\n            self.depth = value.depth + 1\n\n\nclass DepthMachine(RuleBasedStateMachine):\n    charges = Bundle(\"charges\")\n\n    @rule(targets=(charges,), child=charges)\n    def charge(self, child):\n        return DepthCharge(child)\n\n    @rule(targets=(charges,))\n    def none_charge(self):\n        return DepthCharge(None)\n\n    @rule(check=charges)\n    def is_not_too_deep(self, check):\n        assert check.depth < 3\n\n\nclass RoseTreeStateMachine(RuleBasedStateMachine):\n    nodes = Bundle(\"nodes\")\n\n    @rule(target=nodes, source=st.lists(nodes))\n    def bunch(self, source):\n        return source\n\n    @rule(source=nodes)\n    def shallow(self, source):\n        def depth(ls):\n            return 0 if not ls else 1 + max(map(depth, ls))\n\n        assert depth(source) <= 5\n\n\nclass NotTheLastMachine(RuleBasedStateMachine):\n    stuff = Bundle(\"stuff\")\n\n    def __init__(self):\n        super().__init__()\n        self.last = None\n        self.bye_called = False\n\n    @rule(target=stuff)\n    def hi(self):\n        result = object()\n        self.last = result\n        return result\n\n    @precondition(lambda self: not self.bye_called)\n    @rule(v=stuff)\n    def bye(self, v):\n        assert v == self.last\n        self.bye_called = True\n\n\nclass PopulateMultipleTargets(RuleBasedStateMachine):\n    b1 = Bundle(\"b1\")\n    b2 = Bundle(\"b2\")\n\n    @rule(targets=(b1, b2))\n    def populate(self):\n        return 1\n\n    @rule(x=b1, y=b2)\n    def fail(self, x, y):\n        raise AssertionError\n\n\nclass CanSwarm(RuleBasedStateMachine):\n    \"\"\"This test will essentially never pass if you choose rules uniformly at\n    random, because every time the snake rule fires we return to the beginning,\n    so we will tend to undo progress well before we make enough progress for\n    the test to fail.\n\n    This tests our swarm testing functionality in stateful testing by ensuring\n    that we can sometimes generate long runs of steps which exclude a\n    particular rule.\n    \"\"\"\n\n    def __init__(self):\n        super().__init__()\n        self.seen = set()\n\n    @rule(move=st.integers())\n    def ladder(self, move):\n        self.seen.add(move)\n        assert len(self.seen) <= 15\n\n    @rule()\n    def snake(self):\n        self.seen.clear()\n\n\nbad_machines = (\n    BalancedTrees,\n    DepthMachine,\n    RoseTreeStateMachine,\n    NotTheLastMachine,\n    PopulateMultipleTargets,\n    CanSwarm,\n)\n\nfor m in bad_machines:\n    m.TestCase.settings = Settings(\n        m.TestCase.settings,\n        max_examples=1000,\n        database=None,\n        phases=set(Phase) - {Phase.shrink},\n    )\n\n\n@pytest.mark.parametrize(\n    \"machine\", bad_machines, ids=[t.__name__ for t in bad_machines]\n)\ndef test_bad_machines_fail(machine):\n    if (\n        machine in [CanSwarm, RoseTreeStateMachine]\n        and Settings.get_current_profile_name() == \"crosshair\"\n    ):\n        # and also takes 10/6 minutes respectively, on top of not finding the failure\n        pytest.xfail(reason=str(Why.undiscovered))\n\n    with pytest.raises(AssertionError):\n        machine.TestCase().runTest()\n\n\nclass MyStatefulMachine(RuleBasedStateMachine):\n    def __init__(self):\n        self.n_steps = 0\n        super().__init__()\n\n    @rule()\n    def step(self):\n        self.n_steps += 1\n        assert self.n_steps <= 10\n\n\nclass TestMyStatefulMachine(MyStatefulMachine.TestCase):\n    settings = Settings(derandomize=True, stateful_step_count=5)\n\n\ndef test_multiple_precondition_bug():\n    # See https://github.com/HypothesisWorks/hypothesis/issues/2861\n    class MultiplePreconditionMachine(RuleBasedStateMachine):\n        @rule(x=st.integers())\n        def good_method(self, x):\n            pass\n\n        @precondition(lambda self: True)\n        @precondition(lambda self: False)\n        @rule(x=st.integers())\n        def bad_method_a(self, x):\n            raise AssertionError(\"This rule runs, even though it shouldn't.\")\n\n        @precondition(lambda self: False)\n        @precondition(lambda self: True)\n        @rule(x=st.integers())\n        def bad_method_b(self, x):\n            raise AssertionError(\"This rule might be skipped for the wrong reason.\")\n\n        @precondition(lambda self: True)\n        @rule(x=st.integers())\n        @precondition(lambda self: False)\n        def bad_method_c(self, x):\n            raise AssertionError(\"This rule runs, even though it shouldn't.\")\n\n        @rule(x=st.integers())\n        @precondition(lambda self: True)\n        @precondition(lambda self: False)\n        def bad_method_d(self, x):\n            raise AssertionError(\"This rule runs, even though it shouldn't.\")\n\n        @precondition(lambda self: True)\n        @precondition(lambda self: False)\n        @invariant()\n        def bad_invariant_a(self):\n            raise AssertionError(\"This invariant runs, even though it shouldn't.\")\n\n        @precondition(lambda self: False)\n        @precondition(lambda self: True)\n        @invariant()\n        def bad_invariant_b(self):\n            raise AssertionError(\"This invariant runs, even though it shouldn't.\")\n\n        @precondition(lambda self: True)\n        @invariant()\n        @precondition(lambda self: False)\n        def bad_invariant_c(self):\n            raise AssertionError(\"This invariant runs, even though it shouldn't.\")\n\n        @invariant()\n        @precondition(lambda self: True)\n        @precondition(lambda self: False)\n        def bad_invariant_d(self):\n            raise AssertionError(\"This invariant runs, even though it shouldn't.\")\n\n    run_state_machine_as_test(MultiplePreconditionMachine)\n\n\nclass UnrelatedCall(RuleBasedStateMachine):\n    a = Bundle(\"a\")\n\n    def __init__(self):\n        super().__init__()\n        self.calls = set()\n\n    @rule(target=a, a=st.integers())\n    def add_a(self, a):\n        self.calls.add(\"add\")\n        return a\n\n    @rule(v=a)\n    def f(self, v):\n        self.calls.add(\"f\")\n\n    @precondition(lambda self: \"add\" in self.calls)\n    @rule(value=st.integers())\n    def unrelated(self, value):\n        self.calls.add(\"unrelated\")\n\n    @rule()\n    def invariant(self):\n        # force all three calls to be made in a particular order (with the\n        # `unrelated` precondition) so we always shrink to a particular counterexample.\n        assert len(self.calls) != 3\n\n\ndef test_unrelated_rule_does_not_use_var_reference_repr():\n    # we are specifically looking for state.unrelated(value=0) not being replaced\n    # with state.unrelated(value=a_0). The `unrelated` rule is drawing from\n    # st.integers, not a bundle, so the values should not be conflated even if\n    # they're both 0.\n    assert_runs_to_output(\n        UnrelatedCall,\n        \"\"\"\n        state = UnrelatedCall()\n        a_0 = state.add_a(a=0)\n        state.f(v=a_0)\n        state.unrelated(value=0)\n        state.invariant()\n        state.teardown()\n        \"\"\",\n    )\n\n\nclass SourceSameAsTarget(RuleBasedStateMachine):\n    values = Bundle(\"values\")\n\n    @rule(target=values, value=st.lists(values))\n    def f(self, value):\n        assert len(value) == 0\n        return value\n\n\nclass SourceSameAsTargetUnclearOrigin(RuleBasedStateMachine):\n    values = Bundle(\"values\")\n\n    def __init__(self):\n        super().__init__()\n        self.called = False\n\n    @rule(target=values, value=st.just([]) | st.lists(values))\n    def f(self, value):\n        assert not self.called\n        # ensure we get two calls to f before failing. In the minimal failing\n        # example, both will be from st.just([]).\n        self.called = True\n        return value\n\n\ndef test_replaces_when_same_id():\n    assert_runs_to_output(\n        SourceSameAsTarget,\n        f\"\"\"\n        state = {SourceSameAsTarget.__name__}()\n        values_0 = state.f(value=[])\n        state.f(value=[values_0])\n        state.teardown()\n        \"\"\",\n    )\n\n\ndef test_doesnt_replace_when_different_id():\n    assert_runs_to_output(\n        SourceSameAsTargetUnclearOrigin,\n        f\"\"\"\n        state = {SourceSameAsTargetUnclearOrigin.__name__}()\n        values_0 = state.f(value=[])\n        state.f(value=[])\n        state.teardown()\n        \"\"\",\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_strategy_state.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport hashlib\nimport math\nfrom random import Random\n\nfrom hypothesis import Verbosity, assume, settings\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.internal.compat import PYPY\nfrom hypothesis.internal.floats import clamp, float_to_int, int_to_float, is_negative\nfrom hypothesis.stateful import Bundle, RuleBasedStateMachine, rule\nfrom hypothesis.strategies import (\n    binary,\n    booleans,\n    complex_numbers,\n    data,\n    decimals,\n    floats,\n    fractions,\n    integers,\n    just,\n    lists,\n    none,\n    sampled_from,\n    text,\n    tuples,\n)\n\n\nclass HypothesisSpec(RuleBasedStateMachine):\n    def __init__(self):\n        super().__init__()\n        self.database = None\n\n    strategies = Bundle(\"strategy\")\n    strategy_tuples = Bundle(\"tuples\")\n    objects = Bundle(\"objects\")\n    basic_data = Bundle(\"basic\")\n    varied_floats = Bundle(\"varied_floats\")\n\n    def teardown(self):\n        self.clear_database()\n\n    @rule()\n    def clear_database(self):\n        if self.database is not None:\n            self.database = None\n\n    @rule()\n    def set_database(self):\n        self.teardown()\n        self.database = InMemoryExampleDatabase()\n\n    @rule(\n        target=strategies,\n        spec=sampled_from(\n            (\n                integers(),\n                booleans(),\n                floats(),\n                complex_numbers(),\n                fractions(),\n                decimals(),\n                text(),\n                binary(),\n                none(),\n                tuples(),\n            )\n        ),\n    )\n    def strategy(self, spec):\n        return spec\n\n    @rule(target=strategies, values=lists(integers() | text(), min_size=1))\n    def sampled_from_strategy(self, values):\n        return sampled_from(values)\n\n    @rule(target=strategies, spec=strategy_tuples)\n    def strategy_for_tupes(self, spec):\n        return tuples(*spec)\n\n    @rule(target=strategies, source=strategies, level=integers(1, 10), mixer=text())\n    def filtered_strategy(self, source, level, mixer):\n        def is_good(x):\n            seed = hashlib.sha384((mixer + repr(x)).encode()).digest()\n            return bool(Random(seed).randint(0, level))\n\n        return source.filter(is_good)\n\n    @rule(target=strategies, elements=strategies)\n    def list_strategy(self, elements):\n        return lists(elements)\n\n    @rule(target=strategies, left=strategies, right=strategies)\n    def or_strategy(self, left, right):\n        return left | right\n\n    @rule(target=varied_floats, source=floats())\n    def float(self, source):\n        return source\n\n    @rule(target=varied_floats, source=varied_floats, offset=integers(-100, 100))\n    def adjust_float(self, source, offset):\n        return int_to_float(clamp(0, float_to_int(source) + offset, 2**64 - 1))\n\n    @rule(target=strategies, left=varied_floats, right=varied_floats)\n    def float_range(self, left, right):\n        assume(math.isfinite(left) and math.isfinite(right))\n        left, right = sorted((left, right))\n        assert left <= right\n        # exclude deprecated case where left = 0.0 and right = -0.0\n        assume(left or right or not (is_negative(right) and not is_negative(left)))\n        return floats(left, right)\n\n    @rule(\n        target=strategies,\n        source=strategies,\n        result1=strategies,\n        result2=strategies,\n        mixer=text(),\n        p=floats(0, 1),\n    )\n    def flatmapped_strategy(self, source, result1, result2, mixer, p):\n        assume(result1 is not result2)\n\n        def do_map(value):\n            rep = repr(value)\n            random = Random(hashlib.sha384((mixer + rep).encode()).digest())\n            if random.random() <= p:\n                return result1\n            else:\n                return result2\n\n        return source.flatmap(do_map)\n\n    @rule(target=strategies, value=objects)\n    def just_strategy(self, value):\n        return just(value)\n\n    @rule(target=strategy_tuples, source=strategies)\n    def single_tuple(self, source):\n        return (source,)\n\n    @rule(target=strategy_tuples, left=strategy_tuples, right=strategy_tuples)\n    def cat_tuples(self, left, right):\n        return left + right\n\n    @rule(target=objects, strat=strategies, data=data())\n    def get_example(self, strat, data):\n        data.draw(strat)\n\n    @rule(target=strategies, left=integers(), right=integers())\n    def integer_range(self, left, right):\n        left, right = sorted((left, right))\n        return integers(left, right)\n\n    @rule(strat=strategies)\n    def repr_is_good(self, strat):\n        assert \" at 0x\" not in repr(strat)\n\n\nMAIN = __name__ == \"__main__\"\n\nTestHypothesis = HypothesisSpec.TestCase\n\nTestHypothesis.settings = settings(\n    TestHypothesis.settings,\n    stateful_step_count=10 if PYPY else 50,\n    verbosity=max(TestHypothesis.settings.verbosity, Verbosity.verbose),\n    max_examples=10000 if MAIN else 200,\n)\n\nif MAIN:\n    TestHypothesis().runTest()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_subnormal_floats.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\nfrom sys import float_info\n\nimport pytest\n\nfrom hypothesis.internal.floats import width_smallest_normals\nfrom hypothesis.strategies import floats\n\nfrom tests.common.debug import assert_all_examples, find_any\nfrom tests.common.utils import PYTHON_FTZ\n\n\ndef test_python_compiled_with_sane_math_options():\n    \"\"\"Python does not flush-to-zero, which violates IEEE-754\n\n    The other tests that rely on subnormals are skipped when Python is FTZ\n    (otherwise pytest will be very noisy), so this meta test ensures CI jobs\n    still fail as we currently don't care to support such builds of Python.\n    \"\"\"\n    assert not PYTHON_FTZ\n\n\nskipif_ftz = pytest.mark.skipif(PYTHON_FTZ, reason=\"broken by unsafe compiler flags\")\n\n\n@skipif_ftz\ndef test_can_generate_subnormals():\n    find_any(floats().filter(lambda x: x > 0), lambda x: x < float_info.min)\n    find_any(floats().filter(lambda x: x < 0), lambda x: x > -float_info.min)\n\n\n@skipif_ftz\n@pytest.mark.parametrize(\n    \"min_value, max_value\", [(None, None), (-1, 0), (0, 1), (-1, 1)]\n)\n@pytest.mark.parametrize(\"width\", [16, 32, 64])\ndef test_does_not_generate_subnormals_when_disallowed(width, min_value, max_value):\n    strat = floats(\n        min_value=min_value,\n        max_value=max_value,\n        allow_subnormal=False,\n        width=width,\n    )\n    strat = strat.filter(lambda x: x != 0.0 and math.isfinite(x))\n    smallest_normal = width_smallest_normals[width]\n    assert_all_examples(strat, lambda x: x <= -smallest_normal or x >= smallest_normal)\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_targeting.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import Phase, given, seed, settings, strategies as st, target\n\nfrom tests.common.utils import Why, xfail_on_crosshair\n\npytest_plugins = \"pytester\"\n\nTESTSUITE = \"\"\"\nfrom hypothesis import given, strategies as st, target\n\n@given(st.integers(min_value=0))\ndef test_threshold_problem(x):\n    target(float(x))\n    {0}target(float(x * 2), label=\"double\")\n    {0}assert x <= 100000\n    assert x <= 100\n\"\"\"\n\n\n@pytest.mark.parametrize(\"multiple\", [False, True])\ndef test_reports_target_results(testdir, multiple):\n    script = testdir.makepyfile(TESTSUITE.format(\"\" if multiple else \"# \"))\n    result = testdir.runpytest(script, \"--tb=native\", \"-rN\")\n    out = \"\\n\".join(result.stdout.lines)\n    assert \"Falsifying example\" in out\n    assert \"x=101\" in out, out\n    assert out.count(\"Highest target score\") == 1\n    assert result.ret != 0\n\n\ndef test_targeting_increases_max_length():\n    strat = st.lists(st.booleans())\n\n    @settings(database=None, max_examples=200, phases=[Phase.generate, Phase.target])\n    @given(strat)\n    def test_with_targeting(ls):\n        target(float(len(ls)))\n        assert len(ls) <= 80\n\n    with pytest.raises(AssertionError):\n        test_with_targeting()\n\n\n@given(st.integers(), st.integers())\ndef test_target_returns_value(a, b):\n    difference = target(abs(a - b))\n    assert difference == abs(a - b)\n    assert isinstance(difference, int)\n\n\n@xfail_on_crosshair(Why.symbolic_outside_context)\ndef test_targeting_can_be_disabled():\n    strat = st.lists(st.integers(0, 255))\n\n    def score(enabled):\n        result = 0\n        phases = [Phase.generate]\n        if enabled:\n            phases.append(Phase.target)\n\n        @seed(0)\n        @settings(database=None, max_examples=100, phases=phases)\n        @given(strat)\n        def test(ls):\n            nonlocal result\n            # cap the score to avoid long test times by unbounded driving of list\n            # length upwards\n            score = min(sum(ls), 10_000)\n            result = max(result, score)\n            target(score)\n\n        test()\n        return result\n\n    assert score(enabled=True) > score(enabled=False)\n\n\n@pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"takes ~15 minutes, mostly just unrolling the rejection sampling loop\",\n)\ndef test_issue_2395_regression():\n    @given(d=st.floats().filter(lambda x: abs(x) < 1000))\n    @settings(max_examples=1000, database=None)\n    @seed(93962505385993024185959759429298090872)\n    def test_targeting_square_loss(d):\n        target(-((d - 42.5) ** 2.0))\n\n    test_targeting_square_loss()\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_testdecorators.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\n\nimport pytest\n\nfrom hypothesis import HealthCheck, given, reject, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument, Unsatisfiable\n\n\ndef test_contains_the_test_function_name_in_the_exception_string():\n    look_for_one = settings(max_examples=1, suppress_health_check=list(HealthCheck))\n\n    @given(st.integers())\n    @look_for_one\n    def this_has_a_totally_unique_name(x):\n        reject()\n\n    with pytest.raises(\n        Unsatisfiable, match=re.escape(this_has_a_totally_unique_name.__name__)\n    ):\n        this_has_a_totally_unique_name()\n\n    class Foo:\n        @given(st.integers())\n        @look_for_one\n        def this_has_a_unique_name_and_lives_on_a_class(self, x):\n            reject()\n\n    with pytest.raises(\n        Unsatisfiable,\n        match=re.escape(Foo.this_has_a_unique_name_and_lives_on_a_class.__name__),\n    ):\n        Foo().this_has_a_unique_name_and_lives_on_a_class()\n\n\ndef test_signature_mismatch_error_message():\n    # Regression test for issue #1978\n\n    @settings(max_examples=2)\n    @given(x=st.integers())\n    def bad_test():\n        pass\n\n    with pytest.raises(\n        InvalidArgument,\n        match=r\"bad_test\\(\\) got an unexpected keyword argument 'x', \"\n        r\"from `x=integers\\(\\)` in @given\",\n    ):\n        bad_test()\n\n\n@given(data=st.data(), keys=st.lists(st.integers(), unique=True))\ndef test_fixed_dict_preserves_iteration_order(data, keys):\n    d = data.draw(st.fixed_dictionaries({k: st.none() for k in keys}))\n    assert all(a == b for a, b in zip(keys, d, strict=True)), f\"{keys=}, {d.keys()=}\"\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_threading.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport sys\nimport time\nfrom threading import Barrier, Thread\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis.errors import DeadlineExceeded, InvalidArgument\nfrom hypothesis.internal.conjecture.junkdrawer import ensure_free_stackframes\nfrom hypothesis.stateful import RuleBasedStateMachine, invariant, rule\nfrom hypothesis.strategies import SearchStrategy\n\nfrom tests.common.debug import check_can_generate_examples\nfrom tests.common.utils import run_concurrently\n\npytestmark = pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"crosshair is not thread safe\",\n)\n\n\ndef test_can_run_given_in_thread():\n    has_run_successfully = False\n\n    @given(st.integers())\n    def test(n):\n        nonlocal has_run_successfully\n        has_run_successfully = True\n\n    t = Thread(target=test)\n    t.start()\n    t.join()\n    assert has_run_successfully\n\n\ndef test_run_stateful_test_concurrently():\n    class MyStateMachine(RuleBasedStateMachine):\n        def __init__(self):\n            super().__init__()\n\n        @rule(n=st.integers())\n        def my_rule(self, n):\n            pass\n\n        @invariant()\n        def my_invariant(self):\n            pass\n\n    TestMyStateful = MyStateMachine.TestCase().runTest\n    run_concurrently(TestMyStateful, n=2)\n\n\ndef do_work(*, multiplier=1):\n    # arbitrary moderately-expensive work\n    for x in range(500 * multiplier):\n        _y = x**x\n\n\ndef test_run_different_tests_in_threads():\n    @given(st.integers())\n    def test1(n):\n        do_work()\n\n    @given(st.integers())\n    def test2(n):\n        do_work()\n\n    thread1 = Thread(target=test1)\n    thread2 = Thread(target=test2)\n\n    thread1.start()\n    thread2.start()\n    thread1.join()\n    thread2.join()\n\n\ndef test_run_given_concurrently():\n    @given(st.data(), st.integers(-5, 5).map(lambda x: 10**x))\n    def test(data, magnitude):\n        assert magnitude != 0\n        data.draw(st.complex_numbers(max_magnitude=magnitude))\n\n    run_concurrently(test, n=2)\n\n\ndef test_stackframes_restores_original_recursion_limit():\n    original_recursionlimit = sys.getrecursionlimit()\n\n    def test():\n        with ensure_free_stackframes():\n            do_work()\n\n            # also mix in a hypothesis test; why not.\n            @given(st.integers())\n            @settings(max_examples=10)\n            def test(n):\n                pass\n\n            test()\n\n    threads = []\n    for _ in range(4):\n        threads.append(Thread(target=test))\n    for thread in threads:\n        thread.start()\n    for thread in threads:\n        thread.join(timeout=10)\n\n    assert sys.getrecursionlimit() == original_recursionlimit\n\n\n@pytest.mark.parametrize(\n    \"strategy\",\n    [\n        st.recursive(st.none(), st.lists, max_leaves=-1),\n        st.recursive(st.none(), st.lists, max_leaves=0),\n        st.recursive(st.none(), st.lists, max_leaves=1.0),\n    ],\n)\ndef test_handles_invalid_args_cleanly(strategy):\n    # we previously had a race in SearchStrategy.validate, where one thread would\n    # set `validate_called = True` (which it has to do first for recursive\n    # strategies), then another thread would try to generate before the validation\n    # finished and errored, and would get into weird technically-valid states\n    # like interpreting 1.0 as 1. I saw FlakyStrategyDefinition here because the\n    # validating + errored thread drew zero choices, but the other thread drew\n    # 1 choice, for the same shared strategy.\n\n    def check():\n        with pytest.raises(InvalidArgument):\n            check_can_generate_examples(strategy)\n\n    run_concurrently(check, n=4)\n\n\ndef test_single_thread_can_raise_deadline_exceeded():\n    # a slow test running inside a thread, but not concurrently, should still\n    # be able to raise DeadlineExceeded.\n    @given(st.integers())\n    @settings(max_examples=5)\n    def slow_test(n):\n        do_work()\n        time.sleep(0.4)\n\n    def target():\n        with pytest.raises(DeadlineExceeded):\n            slow_test()\n\n    thread = Thread(target=target)\n    thread.start()\n    thread.join(timeout=10)\n\n\ndef test_deadline_exceeded_not_raised_under_concurrent_threads():\n    # it's still possible for multithreaded calls to a slow function to raise\n    # DeadlineExceeded, if the first thread completes its entire test before\n    # any other thread starts. For this test, prevent this scenario with a barrier,\n    # forcing the threads to run in parallel.\n    n_threads = 8\n    barrier = Barrier(n_threads)\n\n    @given(st.integers())\n    @settings(max_examples=5)\n    def slow_test(n):\n        do_work()\n        time.sleep(0.4)\n        barrier.wait()\n\n    run_concurrently(slow_test, n=n_threads)\n\n\ndef test_deadline_exceeded_can_be_raised_after_threads():\n    # if we had concurrent threads before, but they've finished now, we should\n    # still be able to raise DeadlineExceeded normally. Importantly, we test this\n    # for the same test as was running before, since concurrent thread use is\n    # tracked per-@given.\n\n    @given(st.integers())\n    @settings(max_examples=5)\n    def slow_test(n):\n        do_work()\n        if should_sleep:\n            time.sleep(0.4)\n\n    should_sleep = False\n    run_concurrently(slow_test, n=8)\n\n    should_sleep = True\n    with pytest.raises(DeadlineExceeded):\n        slow_test()\n\n\ndef test_one_of_branches_lock():\n    class SlowBranchesStrategy(SearchStrategy):\n        @property\n        def branches(self):\n            # multiplier=2 reproduces more consistently than multiplier=1 for me\n            do_work(multiplier=2)\n            return [st.integers(), st.text()]\n\n    branch_counts = set()\n    s = st.one_of(SlowBranchesStrategy(), SlowBranchesStrategy())\n\n    def test():\n        branches = len(s.branches)\n        branch_counts.add(branches)\n\n    run_concurrently(test, n=10)\n    assert len(branch_counts) == 1\n    # there are 4 independent strategies, but only 2 distinct ones -\n    # st.integers(), and st.text().\n    assert branch_counts == {2}\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_type_lookup.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections.abc import Callable, Collection, Sequence\nfrom typing import Concatenate, ParamSpec\n\nimport pytest\n\nfrom hypothesis import strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.strategies._internal.types import NON_RUNTIME_TYPES\n\nfrom tests.common.debug import (\n    assert_simple_property,\n    check_can_generate_examples,\n    find_any,\n)\n\ntry:\n    from typing import TypeGuard  # new in 3.10\nexcept ImportError:\n    TypeGuard = None\n\ntry:\n    from typing import TypeIs  # new in 3.13\nexcept ImportError:\n    TypeIs = None\n\n\n@pytest.mark.parametrize(\"non_runtime_type\", NON_RUNTIME_TYPES)\ndef test_non_runtime_type_cannot_be_resolved(non_runtime_type):\n    strategy = st.from_type(non_runtime_type)\n    with pytest.raises(\n        InvalidArgument, match=\"there is no such thing as a runtime instance\"\n    ):\n        check_can_generate_examples(strategy)\n\n\n@pytest.mark.parametrize(\"non_runtime_type\", NON_RUNTIME_TYPES)\ndef test_non_runtime_type_cannot_be_registered(non_runtime_type):\n    with pytest.raises(\n        InvalidArgument, match=\"there is no such thing as a runtime instance\"\n    ):\n        st.register_type_strategy(non_runtime_type, st.none())\n\n\n@pytest.mark.skipif(Concatenate is None, reason=\"requires python3.10 or higher\")\ndef test_callable_with_concatenate():\n    P = ParamSpec(\"P\")\n    func_type = Callable[Concatenate[int, P], None]\n    strategy = st.from_type(func_type)\n    with pytest.raises(\n        InvalidArgument,\n        match=\"Hypothesis can't yet construct a strategy for instances of a Callable type\",\n    ):\n        check_can_generate_examples(strategy)\n\n    with pytest.raises(InvalidArgument, match=\"Cannot register generic type\"):\n        st.register_type_strategy(func_type, st.none())\n\n\n@pytest.mark.skipif(ParamSpec is None, reason=\"requires python3.10 or higher\")\ndef test_callable_with_paramspec():\n    P = ParamSpec(\"P\")\n    func_type = Callable[P, None]\n    strategy = st.from_type(func_type)\n    with pytest.raises(\n        InvalidArgument,\n        match=\"Hypothesis can't yet construct a strategy for instances of a Callable type\",\n    ):\n        check_can_generate_examples(strategy)\n\n    with pytest.raises(InvalidArgument, match=\"Cannot register generic type\"):\n        st.register_type_strategy(func_type, st.none())\n\n\n@pytest.mark.parametrize(\"typ\", [TypeGuard, TypeIs])\ndef test_callable_return_typegard_type(typ):\n    if typ is None:\n        pytest.skip(\"Requires modern typing\")\n\n    strategy = st.from_type(Callable[[], typ[int]])\n    with pytest.raises(\n        InvalidArgument,\n        match=\"Hypothesis cannot yet construct a strategy for callables \"\n        \"which are PEP-647 TypeGuards or PEP-742 TypeIs\",\n    ):\n        check_can_generate_examples(strategy)\n\n    with pytest.raises(InvalidArgument, match=\"Cannot register generic type\"):\n        st.register_type_strategy(Callable[[], typ[int]], st.none())\n\n\ndef test_binary_type_resolution():\n    # we have special logic for this, see\n    # https://github.com/HypothesisWorks/hypothesis/pull/4490\n    find_any(st.from_type(Collection[int]), lambda v: isinstance(v, bytes))\n    find_any(st.from_type(Sequence[object]), lambda v: isinstance(v, bytes))\n    find_any(st.from_type(Sequence[int]), lambda v: isinstance(v, bytes))\n\n    assert_simple_property(st.from_type(type[int]), lambda v: not isinstance(v, bytes))\n    assert_simple_property(st.from_type(set[int]), lambda v: not isinstance(v, bytes))\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_type_lookup_forward_ref.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom typing import Dict as _Dict, ForwardRef, Union\n\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis.errors import ResolutionFailed\n\nfrom tests.common import utils\nfrom tests.common.utils import skipif_threading\n\n# error only occurs with typing variants\n# ruff: noqa: UP006, UP035, UP007\n\n# Mutually-recursive types\n# See https://github.com/HypothesisWorks/hypothesis/issues/2722\n\npytestmark = pytest.mark.skipif(\n    settings.get_current_profile_name() == \"crosshair\",\n    reason=\"slow with recursive strustures: https://github.com/pschanely/hypothesis-crosshair/issues/27\",\n)\n\n\n@skipif_threading  # weird errors around b_strategy scope?\n@given(st.data())\ndef test_mutually_recursive_types_with_typevar(data):\n    # The previously-failing example from the issue\n    A = _Dict[bool, \"B\"]\n    B = Union[list[bool], A]\n\n    with pytest.raises(ResolutionFailed, match=r\"Could not resolve ForwardRef\\('B'\\)\"):\n        data.draw(st.from_type(A))\n\n    with utils.temp_registered(\n        ForwardRef(\"B\"),\n        lambda _: st.deferred(lambda: b_strategy),\n    ):\n        b_strategy = st.from_type(B)\n        data.draw(b_strategy)\n        data.draw(st.from_type(A))\n        data.draw(st.from_type(B))\n\n\n@skipif_threading  # weird errors around d_strategy scope?\n@given(st.data())\ndef test_mutually_recursive_types_with_typevar_alternate(data):\n    # It's not particularly clear why this version passed when the previous\n    # test failed, but different behaviour means we add both to the suite.\n    C = Union[list[bool], \"D\"]\n    D = dict[bool, C]\n\n    with pytest.raises(ResolutionFailed, match=r\"Could not resolve ForwardRef\\('D'\\)\"):\n        data.draw(st.from_type(C))\n\n    with utils.temp_registered(\n        ForwardRef(\"D\"),\n        lambda _: st.deferred(lambda: d_strategy),\n    ):\n        d_strategy = st.from_type(D)\n        data.draw(d_strategy)\n        data.draw(st.from_type(C))\n        data.draw(st.from_type(D))\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_type_lookup_future_annotations.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom __future__ import annotations\n\nfrom typing import TypedDict\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import InvalidArgument\n\nfrom tests.common.debug import check_can_generate_examples\n\nalias = int | str\n\n\nclass A(TypedDict):\n    a: int\n\n\nclass B(TypedDict):\n    a: A\n    b: alias\n\n\n@given(st.from_type(B))\ndef test_complex_forward_ref_in_typed_dict(d):\n    assert isinstance(d[\"a\"], dict)\n    assert isinstance(d[\"a\"][\"a\"], int)\n    assert isinstance(d[\"b\"], (int, str))\n\n\ndef test_complex_forward_ref_in_typed_dict_local():\n    local_alias = int | str\n\n    class C(TypedDict):\n        a: A\n        b: local_alias\n\n    c_strategy = st.from_type(C)\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(c_strategy)\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_unusual_settings_configs.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import HealthCheck, Verbosity, assume, given, settings, strategies as st\n\n\n@settings(max_examples=1, database=None)\n@given(st.integers())\ndef test_single_example(n):\n    pass\n\n\n@settings(\n    max_examples=1,\n    database=None,\n    suppress_health_check=[HealthCheck.filter_too_much, HealthCheck.too_slow],\n    verbosity=Verbosity.debug,\n)\n@given(st.integers())\ndef test_hard_to_find_single_example(n):\n    # Numbers are arbitrary, just deliberately unlikely to hit this too soon.\n    assume(n % 50 == 11)\n"
  },
  {
    "path": "hypothesis-python/tests/nocover/test_uuids.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\n\nfrom tests.common.debug import minimal\n\n\n@given(st.lists(st.uuids()))\ndef test_are_unique(ls):\n    assert len(set(ls)) == len(ls)\n\n\ndef test_retains_uniqueness_in_simplify():\n    ts = minimal(st.lists(st.uuids()), lambda x: len(x) >= 5)\n    assert len(ts) == len(set(ts)) == 5\n\n\n@pytest.mark.parametrize(\"version\", (1, 2, 3, 4, 5))\ndef test_can_generate_specified_version(version):\n    @given(st.uuids(version=version))\n    def inner(uuid):\n        assert version == uuid.version\n\n    inner()\n"
  },
  {
    "path": "hypothesis-python/tests/numpy/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\ntry:\n    EncodingWarning\nexcept NameError:\n    pass\nelse:\n    # Work around https://github.com/numpy/numpy/issues/24115\n    import warnings\n\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", EncodingWarning)\n        import numpy.testing  # noqa\n"
  },
  {
    "path": "hypothesis-python/tests/numpy/test_argument_validation.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport numpy\nimport pytest\n\nfrom hypothesis import strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra import numpy as nps\n\nfrom tests.common.debug import check_can_generate_examples\nfrom tests.common.utils import checks_deprecated_behaviour\n\n\ndef e(a, **kwargs):\n    kw = \", \".join(f\"{k}={v!r}\" for k, v in kwargs.items())\n    return pytest.param(a, kwargs, id=f\"{a.__name__}({kw})\")\n\n\n@pytest.mark.parametrize(\n    (\"function\", \"kwargs\"),\n    [\n        e(nps.array_dtypes, min_size=2, max_size=1),\n        e(nps.array_dtypes, min_size=-1),\n        e(nps.array_shapes, min_side=2, max_side=1),\n        e(nps.array_shapes, min_dims=3, max_dims=2),\n        e(nps.array_shapes, min_dims=-1),\n        e(nps.array_shapes, min_side=-1),\n        e(nps.array_shapes, min_side=\"not an int\"),\n        e(nps.array_shapes, max_side=\"not an int\"),\n        e(nps.array_shapes, min_dims=\"not an int\"),\n        e(nps.array_shapes, max_dims=\"not an int\"),\n        e(nps.array_shapes, min_dims=33),\n        e(nps.array_shapes, max_dims=33),\n        e(nps.arrays, dtype=float, shape=(0.5,)),\n        e(nps.arrays, dtype=numpy.void, shape=1),\n        e(nps.arrays, dtype=float, shape=1, fill=3),\n        e(nps.arrays, dtype=\"U\", shape=1, elements=st.just(\"abc\\0\\0\")),\n        e(nps.arrays, dtype=int, shape=1, elements=\"not a strategy\"),\n        e(nps.byte_string_dtypes, min_len=-1),\n        e(nps.byte_string_dtypes, min_len=2, max_len=1),\n        e(nps.byte_string_dtypes, min_len=0, max_len=0),\n        e(nps.datetime64_dtypes, max_period=11),\n        e(nps.datetime64_dtypes, min_period=11),\n        e(nps.datetime64_dtypes, min_period=\"Y\", max_period=\"M\"),\n        e(nps.timedelta64_dtypes, max_period=11),\n        e(nps.timedelta64_dtypes, min_period=11),\n        e(nps.timedelta64_dtypes, min_period=\"Y\", max_period=\"M\"),\n        e(nps.unicode_string_dtypes, min_len=-1),\n        e(nps.unicode_string_dtypes, min_len=2, max_len=1),\n        e(nps.unicode_string_dtypes, min_len=0, max_len=0),\n        e(nps.unsigned_integer_dtypes, endianness=3),\n        e(nps.unsigned_integer_dtypes, sizes=()),\n        e(nps.unsigned_integer_dtypes, sizes=(3,)),\n        e(nps.from_dtype, dtype=\"float64\"),\n        e(nps.from_dtype, dtype=float),\n        e(nps.from_dtype, dtype=numpy.int8),\n        e(nps.from_dtype, dtype=1),\n        e(nps.from_dtype, dtype=numpy.dtype(\"uint8\"), min_value=-999),\n        e(nps.from_dtype, dtype=numpy.dtype(\"uint8\"), max_value=999),\n        e(nps.from_dtype, dtype=numpy.dtype(\"int8\"), min_value=-999),\n        e(nps.from_dtype, dtype=numpy.dtype(\"int8\"), max_value=999),\n        e(nps.from_dtype, dtype=numpy.dtype(\"S4\"), max_size=5),\n        e(nps.from_dtype, dtype=numpy.dtype(\"U4\"), max_size=5),\n        e(nps.valid_tuple_axes, ndim=-1),\n        e(nps.valid_tuple_axes, ndim=2, min_size=-1),\n        e(nps.valid_tuple_axes, ndim=2, min_size=3, max_size=10),\n        e(nps.valid_tuple_axes, ndim=2, min_size=2, max_size=1),\n        e(nps.valid_tuple_axes, ndim=2.0, min_size=2, max_size=1),\n        e(nps.valid_tuple_axes, ndim=2, min_size=1.0, max_size=2),\n        e(nps.valid_tuple_axes, ndim=2, min_size=1, max_size=2.0),\n        e(nps.valid_tuple_axes, ndim=2, min_size=1, max_size=3),\n        e(nps.broadcastable_shapes, shape=\"a\"),\n        e(nps.broadcastable_shapes, shape=(2, 2), min_side=\"a\"),\n        e(nps.broadcastable_shapes, shape=(2, 2), min_dims=\"a\"),\n        e(nps.broadcastable_shapes, shape=(2, 2), max_side=\"a\"),\n        e(nps.broadcastable_shapes, shape=(2, 2), max_dims=\"a\"),\n        e(nps.broadcastable_shapes, shape=(2, 2), min_side=-1),\n        e(nps.broadcastable_shapes, shape=(2, 2), min_dims=-1),\n        e(nps.broadcastable_shapes, shape=(2, 2), min_dims=33, max_dims=None),\n        e(nps.broadcastable_shapes, shape=(2, 2), min_dims=1, max_dims=33),\n        e(nps.broadcastable_shapes, shape=(2, 2), min_side=1, max_side=0),\n        e(nps.broadcastable_shapes, shape=(2, 2), min_dims=1, max_dims=0),\n        e(\n            nps.broadcastable_shapes,  # max_side too small\n            shape=(5, 1),\n            min_dims=2,\n            max_dims=4,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\n            nps.broadcastable_shapes,  # min_side too large\n            shape=(0, 1),\n            min_dims=2,\n            max_dims=4,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\n            nps.broadcastable_shapes,  # default max_dims unsatisfiable\n            shape=(5, 3, 2, 1),\n            min_dims=3,\n            max_dims=None,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\n            nps.broadcastable_shapes,  # default max_dims unsatisfiable\n            shape=(0, 3, 2, 1),\n            min_dims=3,\n            max_dims=None,\n            min_side=2,\n            max_side=3,\n        ),\n        e(nps.mutually_broadcastable_shapes),\n        e(nps.mutually_broadcastable_shapes, num_shapes=0),\n        e(nps.mutually_broadcastable_shapes, num_shapes=\"a\"),\n        e(nps.mutually_broadcastable_shapes, num_shapes=2, base_shape=\"a\"),\n        e(\n            nps.mutually_broadcastable_shapes,  # min_side is invalid type\n            num_shapes=2,\n            min_side=\"a\",\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # min_dims is invalid type\n            num_shapes=2,\n            min_dims=\"a\",\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # max_side is invalid type\n            num_shapes=2,\n            max_side=\"a\",\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # max_side is invalid type\n            num_shapes=2,\n            max_dims=\"a\",\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # min_side is out of domain\n            num_shapes=2,\n            min_side=-1,\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # min_dims is out of domain\n            num_shapes=2,\n            min_dims=-1,\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # min_dims is out of domain\n            num_shapes=2,\n            min_dims=33,\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # max_dims is out of domain\n            num_shapes=2,\n            max_dims=33,\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # max_side < min_side\n            num_shapes=2,\n            min_side=1,\n            max_side=0,\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # max_dims < min_dims\n            num_shapes=2,\n            min_dims=1,\n            max_dims=0,\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # max_side too small\n            num_shapes=2,\n            base_shape=(5, 1),\n            min_dims=2,\n            max_dims=4,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # min_side too large\n            num_shapes=2,\n            base_shape=(0, 1),\n            min_dims=2,\n            max_dims=4,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # user-specified max_dims unsatisfiable\n            num_shapes=1,\n            base_shape=(5, 3, 2, 1),\n            min_dims=3,\n            max_dims=4,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # user-specified max_dims unsatisfiable\n            num_shapes=2,\n            base_shape=(0, 3, 2, 1),\n            min_dims=3,\n            max_dims=4,\n            min_side=2,\n            max_side=3,\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # valid to pass num_shapes xor gufunc\n            num_shapes=2,\n            signature=\"()->()\",\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # element-wise ufunc has signature=None\n            signature=numpy.add.signature,\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # multiple outputs not yet supported\n            signature=\"()->(),()\",\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # output has dimension not in inputs\n            signature=\"()->(i)\",\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # frozen-optional is ambiguous & banned\n            signature=\"(2?)->()\",\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # signature must be in string format\n            signature=([(), ()], [()]),\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # string must match signature regex\n            signature=\"this string isn't a valid signature\",\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # shape with too many dimensions\n            signature=\"(\" + \",\".join(f\"d{n}\" for n in range(33)) + \")->()\",\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # max_dims too large given ufunc\n            signature=numpy.matmul.signature,\n            max_dims=32,\n        ),\n        e(\n            nps.mutually_broadcastable_shapes,  # least valid max_dims is < min_dims\n            signature=numpy.matmul.signature,\n            min_dims=32,\n        ),\n        e(nps.basic_indices, shape=0),\n        e(nps.basic_indices, shape=(\"1\", \"2\")),\n        e(nps.basic_indices, shape=(0, -1)),\n        e(nps.basic_indices, shape=(0, 0), allow_newaxis=None),\n        e(nps.basic_indices, shape=(0, 0), allow_ellipsis=None),\n        e(nps.basic_indices, shape=(0, 0), min_dims=-1),\n        e(nps.basic_indices, shape=(0, 0), min_dims=1.0),\n        e(nps.basic_indices, shape=(0, 0), max_dims=-1),\n        e(nps.basic_indices, shape=(0, 0), max_dims=1.0),\n        e(nps.basic_indices, shape=(0, 0), min_dims=2, max_dims=1),\n        e(nps.basic_indices, shape=(3, 3, 3), max_dims=\"not an int\"),\n        e(nps.integer_array_indices, shape=()),\n        e(nps.integer_array_indices, shape=(2, 0)),\n        e(nps.integer_array_indices, shape=\"a\"),\n        e(nps.integer_array_indices, shape=(2,), result_shape=(2, 2)),\n        e(nps.integer_array_indices, shape=(2,), dtype=float),\n    ],\n)\ndef test_raise_invalid_argument(function, kwargs):\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(function(**kwargs))\n\n\n@pytest.mark.parametrize(\n    (\"function\", \"kwargs\"),\n    [\n        e(nps.basic_indices, shape=(0, 0), min_dims=50),\n        e(nps.basic_indices, shape=(0, 0), max_dims=50),\n    ],\n)\n@checks_deprecated_behaviour\ndef test_raise_invalid_argument_deprecated(function, kwargs):\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(function(**kwargs))\n"
  },
  {
    "path": "hypothesis-python/tests/numpy/test_deprecation.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom warnings import catch_warnings\n\nimport pytest\n\nfrom hypothesis.errors import HypothesisDeprecationWarning, InvalidArgument\nfrom hypothesis.extra import numpy as nps\n\nfrom tests.common.debug import check_can_generate_examples\n\n\ndef test_basic_indices_bad_min_dims_warns():\n    with pytest.warns(HypothesisDeprecationWarning), pytest.raises(InvalidArgument):\n        check_can_generate_examples(nps.basic_indices((3, 3, 3), min_dims=4))\n\n\ndef test_basic_indices_bad_max_dims_warns():\n    with pytest.warns(HypothesisDeprecationWarning):\n        check_can_generate_examples(nps.basic_indices((3, 3, 3), max_dims=4))\n\n\ndef test_basic_indices_default_max_dims_does_not_warn():\n    with catch_warnings(record=True) as record:\n        check_can_generate_examples(nps.basic_indices((3, 3, 3)))\n        check_can_generate_examples(nps.basic_indices((3, 3, 3), allow_newaxis=True))\n        assert len(record) == 0\n"
  },
  {
    "path": "hypothesis-python/tests/numpy/test_fill_values.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.extra.numpy import arrays\n\nfrom tests.common.debug import find_any, minimal\n\n\n@given(arrays(object, 100, elements=st.builds(list)))\ndef test_generated_lists_are_distinct(ls):\n    assert len(set(map(id, ls))) == len(ls)\n\n\n@st.composite\ndef distinct_integers(draw):\n    used = draw(st.shared(st.builds(set), key=\"distinct_integers.used\"))\n    i = draw(st.integers(0, 2**64 - 1).filter(lambda x: x not in used))\n    used.add(i)\n    return i\n\n\n@given(arrays(\"uint64\", 10, elements=distinct_integers()))\ndef test_does_not_reuse_distinct_integers(arr):\n    assert len(set(arr)) == len(arr)\n\n\ndef test_may_reuse_distinct_integers_if_asked():\n    find_any(\n        arrays(\"uint64\", 10, elements=distinct_integers(), fill=distinct_integers()),\n        lambda x: len(set(x)) < len(x),\n    )\n\n\ndef test_minimizes_to_fill():\n    result = minimal(arrays(float, 10, fill=st.just(3.0)))\n    assert (result == 3.0).all()\n\n\n@given(\n    arrays(\n        dtype=float,\n        elements=st.floats(allow_nan=False).filter(bool),\n        shape=(3, 3, 3),\n        fill=st.just(1.0),\n    )\n)\ndef test_fills_everything(x):\n    assert x.all()\n"
  },
  {
    "path": "hypothesis-python/tests/numpy/test_floor_ceil.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport math\n\nimport numpy as np\nimport pytest\n\nfrom hypothesis.internal.compat import ceil, floor\n\n\n@pytest.mark.parametrize(\n    \"value\",\n    [\n        # These are strings so that the test names are easier to read.\n        \"2**64+1\",\n        \"2**64-1\",\n        \"2**63+1\",\n        \"2**53+1\",\n        \"-2**53-1\",\n        \"-2**63+1\",\n        \"-2**63-1\",\n        \"-2**64+1\",\n        \"-2**64-1\",\n    ],\n)\ndef test_our_floor_and_ceil_avoid_numpy_rounding(value):\n    a = np.array(eval(value))\n    f = floor(a)\n    c = ceil(a)\n\n    # Check *exact* type - we don't want to allow a subclass of int here\n    assert type(f) == int\n    assert type(c) == int\n\n    # Using math.floor or math.ceil for these values would give an incorrect result.\n    assert (math.floor(a) > a) or (math.ceil(a) < a)\n\n    assert f <= a <= c\n    assert f + 1 > a > c - 1\n"
  },
  {
    "path": "hypothesis-python/tests/numpy/test_from_dtype.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport sys\n\nimport numpy as np\nimport pytest\n\nfrom hypothesis import assume, given, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra import numpy as nps\nfrom hypothesis.internal.floats import width_smallest_normals\nfrom hypothesis.strategies._internal import SearchStrategy\n\nfrom tests.common.debug import assert_no_examples, check_can_generate_examples, find_any\n\nnp_version = tuple(int(x) for x in np.__version__.split(\".\")[:2])\n\nSTANDARD_TYPES = [\n    np.dtype(t)\n    for t in (\n        \"int8\",\n        \"int16\",\n        \"int32\",\n        \"int64\",\n        \"uint8\",\n        \"uint16\",\n        \"uint32\",\n        \"uint64\",\n        \"float\",\n        \"float16\",\n        \"float32\",\n        \"float64\",\n        \"complex64\",\n        \"complex128\",\n        \"datetime64\",\n        \"timedelta64\",\n        bool,\n        str,\n        bytes,\n    )\n]\nfor nonstandard_typecode in [\"g\", \"G\", \"S1\", \"q\", \"Q\"]:\n    try:\n        STANDARD_TYPES.append(np.dtype(nonstandard_typecode))\n    except Exception:\n        pass\n\n\n@given(nps.nested_dtypes())\ndef test_strategies_for_standard_dtypes_have_reusable_values(dtype):\n    assert nps.from_dtype(dtype).has_reusable_values\n\n\n@pytest.mark.parametrize(\"t\", STANDARD_TYPES)\ndef test_produces_instances(t):\n    @given(nps.from_dtype(t))\n    def test_is_t(x):\n        assert isinstance(x, t.type)\n        assert x.dtype.kind == t.kind\n\n    test_is_t()\n\n\n@settings(max_examples=100, deadline=None)\n@given(nps.nested_dtypes(max_itemsize=400), st.data())\ndef test_infer_strategy_from_dtype(dtype, data):\n    # Given a dtype\n    assert isinstance(dtype, np.dtype)\n    # We can infer a strategy\n    strat = nps.from_dtype(dtype)\n    assert isinstance(strat, SearchStrategy)\n    # And use it to fill an array of that dtype\n    data.draw(nps.arrays(dtype, 10, elements=strat))\n\n\n@given(st.data())\ndef test_can_cast_for_scalars(data):\n    # Note: this only passes with castable datatypes, certain dtype\n    # combinations will result in an error if numpy is not able to cast them.\n    dt_elements = np.dtype(data.draw(st.sampled_from([\"bool\", \"<i2\", \">i2\"])))\n    dt_desired = np.dtype(\n        data.draw(st.sampled_from([\"<i2\", \">i2\", \"float32\", \"float64\"]))\n    )\n    result = data.draw(\n        nps.arrays(dtype=dt_desired, elements=nps.from_dtype(dt_elements), shape=())\n    )\n    assert isinstance(result, np.ndarray)\n    assert result.dtype == dt_desired\n\n\n@given(st.data())\ndef test_unicode_string_dtypes_generate_unicode_strings(data):\n    dt = data.draw(nps.unicode_string_dtypes())\n    result = data.draw(nps.from_dtype(dt))\n    assert isinstance(result, str)\n\n\n@given(nps.arrays(dtype=\"U99\", shape=(10,)))\ndef test_can_unicode_strings_without_decode_error(arr):\n    # See https://github.com/numpy/numpy/issues/15363\n    pass\n\n\n@pytest.mark.skipif(not nps.NP_FIXED_UNICODE, reason=\"workaround for old bug\")\ndef test_unicode_string_dtypes_need_not_be_utf8():\n    def cannot_encode(string):\n        try:\n            string.encode()\n            return False\n        except UnicodeEncodeError:\n            return True\n\n    find_any(nps.from_dtype(np.dtype(\"U\")), cannot_encode, settings(max_examples=5000))\n\n\n@given(st.data())\ndef test_byte_string_dtypes_generate_unicode_strings(data):\n    dt = data.draw(nps.byte_string_dtypes())\n    result = data.draw(nps.from_dtype(dt))\n    assert isinstance(result, bytes)\n\n\nskipif_np2 = pytest.mark.skipif(np_version >= (2, 0), reason=\"removed in new version\")\n\n\n@pytest.mark.parametrize(\n    \"dtype\",\n    [\"U\", \"S\", pytest.param(\"a\", marks=skipif_np2)],\n)\ndef test_unsized_strings_length_gt_one(dtype):\n    # See https://github.com/HypothesisWorks/hypothesis/issues/2229\n    find_any(nps.arrays(dtype=dtype, shape=1), lambda arr: len(arr[0]) >= 2)\n\n\n@given(\n    st.data(),\n    st.builds(\n        \"{}[{}]\".format,\n        st.sampled_from((\"datetime64\", \"timedelta64\")),\n        st.sampled_from(nps.TIME_RESOLUTIONS),\n    ).map(np.dtype),\n)\ndef test_inferring_from_time_dtypes_gives_same_dtype(data, dtype):\n    ex = data.draw(nps.from_dtype(dtype))\n    assert dtype == ex.dtype\n\n\n@given(st.data(), nps.byte_string_dtypes() | nps.unicode_string_dtypes())\ndef test_inferred_string_strategies_roundtrip(data, dtype):\n    # Check that we never generate too-long or nul-terminated strings, which\n    # cannot be read back out of an array.\n    arr = np.zeros(shape=1, dtype=dtype)\n    ex = data.draw(nps.from_dtype(arr.dtype))\n    arr[0] = ex\n    assert arr[0] == ex\n\n\n@given(st.data(), nps.scalar_dtypes())\ndef test_all_inferred_scalar_strategies_roundtrip(data, dtype):\n    # We only check scalars here, because record/compound/nested dtypes always\n    # give an array of np.void objects.  We're interested in whether scalar\n    # values are safe, not known type coercion.\n    arr = np.zeros(shape=1, dtype=dtype)\n    ex = data.draw(nps.from_dtype(arr.dtype))\n    assume(ex == ex)  # If not, the roundtrip test *should* fail!  (eg NaN)\n    arr[0] = ex\n    assert arr[0] == ex\n\n\n@pytest.mark.parametrize(\"dtype_str\", [\"m8\", \"M8\"])\n@given(data=st.data())\ndef test_from_dtype_works_without_time_unit(data, dtype_str):\n    arr = data.draw(nps.from_dtype(np.dtype(dtype_str)))\n    assert (dtype_str + \"[\") in arr.dtype.str\n\n\n@pytest.mark.parametrize(\"dtype_str\", [\"m8\", \"M8\"])\n@given(data=st.data())\ndef test_arrays_selects_consistent_time_unit(data, dtype_str):\n    arr = data.draw(nps.arrays(dtype_str, 10))\n    assert (dtype_str + \"[\") in arr.dtype.str\n\n\n@pytest.mark.parametrize(\"dtype\", [\"m8\", \"M8\"])\ndef test_from_dtype_can_include_or_exclude_nat(dtype):\n    find_any(nps.from_dtype(np.dtype(dtype), allow_nan=None), np.isnat)\n    find_any(nps.from_dtype(np.dtype(dtype), allow_nan=True), np.isnat)\n    assert_no_examples(nps.from_dtype(np.dtype(dtype), allow_nan=False), np.isnat)\n\n\ndef test_arrays_gives_useful_error_on_inconsistent_time_unit():\n    with pytest.raises(InvalidArgument, match=\"mismatch of time units in dtypes\"):\n        check_can_generate_examples(\n            nps.arrays(\"m8[Y]\", 10, elements=nps.from_dtype(np.dtype(\"m8[D]\")))\n        )\n\n\n@pytest.mark.parametrize(\n    \"dtype, kwargs, pred\",\n    [\n        # Floating point: bounds, exclusive bounds, and excluding nonfinites\n        (float, {\"min_value\": 1, \"max_value\": 2}, lambda x: 1 <= x <= 2),\n        (\n            float,\n            {\"min_value\": 1, \"max_value\": 2, \"exclude_min\": True, \"exclude_max\": True},\n            lambda x: 1 < x < 2,\n        ),\n        (float, {\"allow_nan\": False}, lambda x: not np.isnan(x)),\n        (float, {\"allow_infinity\": False}, lambda x: not np.isinf(x)),\n        (float, {\"allow_nan\": False, \"allow_infinity\": False}, np.isfinite),\n        # Complex numbers: bounds and excluding nonfinites\n        (complex, {\"allow_nan\": False}, lambda x: not np.isnan(x)),\n        (complex, {\"allow_infinity\": False}, lambda x: not np.isinf(x)),\n        (complex, {\"allow_nan\": False, \"allow_infinity\": False}, np.isfinite),\n        # Note we accept epsilon errors here as internally sqrt is used to draw\n        # complex numbers. sqrt on some platforms gets epsilon errors, which is\n        # too tricky to filter out and so - for now - we just accept them.\n        (\n            complex,\n            {\"min_magnitude\": 1e3},\n            lambda x: abs(x) >= 1e3 * (1 - sys.float_info.epsilon),\n        ),\n        (\n            complex,\n            {\"max_magnitude\": 1e2},\n            lambda x: abs(x) <= 1e2 * (1 + sys.float_info.epsilon),\n        ),\n        (\n            complex,\n            {\"min_magnitude\": 1, \"max_magnitude\": 1e6},\n            lambda x: (\n                (1 - sys.float_info.epsilon)\n                <= abs(x)\n                <= 1e6 * (1 + sys.float_info.epsilon)\n            ),\n        ),\n        # Integer bounds, limited to the representable range\n        (\"int8\", {\"min_value\": -1, \"max_value\": 1}, lambda x: -1 <= x <= 1),\n        (\"uint8\", {\"min_value\": 1, \"max_value\": 2}, lambda x: 1 <= x <= 2),\n        # String arguments, bounding size and unicode alphabet\n        (\"S\", {\"min_size\": 1, \"max_size\": 2}, lambda x: 1 <= len(x) <= 2),\n        (\"S4\", {\"min_size\": 1, \"max_size\": 2}, lambda x: 1 <= len(x) <= 2),\n        (\"U\", {\"min_size\": 1, \"max_size\": 2}, lambda x: 1 <= len(x) <= 2),\n        (\"U4\", {\"min_size\": 1, \"max_size\": 2}, lambda x: 1 <= len(x) <= 2),\n        (\"U\", {\"alphabet\": \"abc\"}, lambda x: set(x).issubset(\"abc\")),\n    ],\n)\n@given(data=st.data())\ndef test_from_dtype_with_kwargs(data, dtype, kwargs, pred):\n    value = data.draw(nps.from_dtype(np.dtype(dtype), **kwargs))\n    assert pred(value)\n\n\n@given(nps.from_dtype(np.dtype(\"U20,uint8,float32\"), min_size=1, allow_nan=False))\ndef test_customize_structured_dtypes(x):\n    name, age, score = x\n    assert len(name) >= 1\n    assert 0 <= age <= 255\n    assert not np.isnan(score)\n\n\n@pytest.mark.parametrize(\"allow_subnormal\", [False, True])\n@pytest.mark.parametrize(\"width\", [32, 64])\ndef test_float_subnormal_generation(allow_subnormal, width):\n    dtype = np.dtype(f\"float{width}\")\n    strat = nps.from_dtype(dtype, allow_subnormal=allow_subnormal).filter(\n        lambda n: n != 0\n    )\n    smallest_normal = width_smallest_normals[width]\n    if allow_subnormal:\n        find_any(strat, lambda n: -smallest_normal < n < smallest_normal)\n    else:\n        assert_no_examples(strat, lambda n: -smallest_normal < n < smallest_normal)\n\n\n@pytest.mark.parametrize(\"allow_subnormal\", [False, True])\n@pytest.mark.parametrize(\"width\", [64, 128])\ndef test_complex_subnormal_generation(allow_subnormal, width):\n    dtype = np.dtype(f\"complex{width}\")\n    strat = nps.from_dtype(dtype, allow_subnormal=allow_subnormal).filter(\n        lambda n: n.real != 0 and n.imag != 0\n    )\n    smallest_normal = width_smallest_normals[width / 2]\n\n    def condition(n):\n        return (\n            -smallest_normal < n.real < smallest_normal\n            or -smallest_normal < n.imag < smallest_normal\n        )\n\n    if allow_subnormal:\n        find_any(strat, condition)\n    else:\n        assert_no_examples(strat, condition)\n"
  },
  {
    "path": "hypothesis-python/tests/numpy/test_from_type.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport typing\nimport warnings\n\nimport numpy as np\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import SmallSearchSpaceWarning\nfrom hypothesis.extra.numpy import ArrayLike, NDArray, _NestedSequence, _SupportsArray\n\nfrom .test_from_dtype import STANDARD_TYPES\nfrom tests.common.debug import assert_simple_property, find_any\n\nSTANDARD_TYPES_TYPE = [dtype.type for dtype in STANDARD_TYPES]\n\nneeds_np_typing = {\"reason\": \"numpy.typing is not available\"}\nneeds_np_private_typing = {\"reason\": \"numpy._typing is not available\"}\n\n\n@given(dtype=st.from_type(np.dtype))\ndef test_resolves_dtype_type(dtype):\n    assert isinstance(dtype, np.dtype)\n\n\ndef test_does_not_resolve_nonscalar_types():\n    # this was previously a parametrized test over np.object_ and np.void which\n    # used the same repr code path for the test. But then numpy changed their types\n    # such that we defer evaluation for st.from_type and are no longer identical\n    # to st.builds, but rather something morally equivalent to it. So we have\n    # these slightly more complicated checks.\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", SmallSearchSpaceWarning)\n        assert_simple_property(st.from_type(np.object_), lambda value: value is None)\n\n    with pytest.raises(TypeError):\n        # np.void() requires an argument, and so throws when instantiated\n        assert_simple_property(st.from_type(np.void))\n\n\n@pytest.mark.parametrize(\"typ\", STANDARD_TYPES_TYPE)\ndef test_resolves_and_varies_numpy_scalar_type(typ):\n    # Check that we find an instance that is not equal to the default\n    x = find_any(st.from_type(typ), lambda x: x != type(x)())\n    assert isinstance(x, typ)\n\n\n@pytest.mark.parametrize(\"atype\", [np.ndarray, NDArray])\ndef test_resolves_unspecified_array_type(atype):\n    if atype is not None:\n        assert_simple_property(st.from_type(atype), lambda v: isinstance(v, np.ndarray))\n\n\ndef workaround(dtype):\n    # Total hack to work around https://github.com/numpy/numpy/issues/24043\n    if np.__version__ == \"1.25.0\" and dtype == np.dtype(\"bytes\").type:\n        return pytest.param(dtype, marks=[pytest.mark.xfail(strict=False)])\n    return dtype\n\n\n# https://numpy.org/devdocs/release/1.22.0-notes.html#ndarray-dtype-and-number-are-now-runtime-subscriptable\n@pytest.mark.skipif(\n    tuple(int(x) for x in np.__version__.split(\".\")[:2]) < (1, 22), reason=\"see comment\"\n)\n@pytest.mark.parametrize(\"typ\", [workaround(t) for t in STANDARD_TYPES_TYPE])\ndef test_resolves_specified_ndarray_type(typ):\n    assert_simple_property(\n        st.from_type(np.ndarray[typ]),\n        lambda arr: isinstance(arr, np.ndarray) and arr.dtype.type == typ,\n    )\n\n    assert_simple_property(\n        st.from_type(np.ndarray[typing.Any, typ]),\n        lambda arr: isinstance(arr, np.ndarray) and arr.dtype.type == typ,\n    )\n\n\n@pytest.mark.skipif(NDArray is None, **needs_np_typing)\n@pytest.mark.parametrize(\"typ\", [workaround(t) for t in STANDARD_TYPES_TYPE])\ndef test_resolves_specified_NDArray_type(typ):\n    assert_simple_property(\n        st.from_type(NDArray[typ]),\n        lambda arr: isinstance(arr, np.ndarray) and arr.dtype.type == typ,\n    )\n\n\n@pytest.mark.skipif(NDArray is None, **needs_np_typing)\ndef test_resolves_NDArray_with_dtype_union():\n    strat = st.from_type(NDArray[np.float64 | np.complex128])\n    find_any(strat, lambda arr: arr.dtype == np.dtype(\"float64\"))\n    find_any(strat, lambda arr: arr.dtype == np.dtype(\"complex128\"))\n\n\n@pytest.mark.skipif(ArrayLike is None, **needs_np_typing)\n@given(arr_like=st.from_type(ArrayLike))\ndef test_resolves_ArrayLike_type(arr_like):\n    arr = np.array(arr_like)\n    assert isinstance(arr, np.ndarray)\n    # The variation is too large to assert anything else about arr, but the\n    # ArrayLike contract just says that it can be coerced into an array (which\n    # we just did).\n\n\n@pytest.mark.skipif(_NestedSequence is None, **needs_np_private_typing)\ndef test_resolves_specified_NestedSequence():\n    @given(seq=st.from_type(_NestedSequence[int]))\n    def test(seq):\n        assert hasattr(seq, \"__iter__\")\n\n        def flatten(lst):\n            for el in lst:\n                try:\n                    yield from flatten(el)\n                except TypeError:\n                    yield el\n\n        assert all(isinstance(i, int) for i in flatten(seq))\n\n    test()\n\n\n@pytest.mark.skipif(_NestedSequence is None, **needs_np_private_typing)\n@given(seq=st.from_type(_NestedSequence))\ndef test_resolves_unspecified_NestedSequence(seq):\n    assert hasattr(seq, \"__iter__\")\n\n\n@pytest.mark.skipif(_SupportsArray is None, **needs_np_private_typing)\n@given(arr=st.from_type(_SupportsArray))\ndef test_resolves_unspecified_SupportsArray(arr):\n    assert hasattr(arr, \"__array__\")\n\n\n@pytest.mark.skipif(_SupportsArray is None, **needs_np_private_typing)\ndef test_resolves_SupportsArray():\n    @given(arr=st.from_type(_SupportsArray[int]))\n    def test(arr):\n        assert hasattr(arr, \"__array__\")\n        assert np.asarray(arr).dtype.kind == \"i\"\n\n    test()\n\n\n@pytest.mark.skipif(\n    _NestedSequence is None or _SupportsArray is None, **needs_np_private_typing\n)\ndef test_resolve_ArrayLike_equivalent():\n    # This is the current (1.24.3) definition of ArrayLike,\n    # with problematic parts commented out.\n    ArrayLike_like = (\n        _SupportsArray\n        # | _NestedSequence[_SupportsArray],\n        | bool\n        | int\n        | float\n        | complex\n        | str\n        | bytes\n        | _NestedSequence[\n            bool | int | float | complex | str,\n            # | bytes,\n        ]\n    )\n\n    @given(arr_like=st.from_type(ArrayLike_like))\n    def test(arr_like):\n        arr = np.array(arr_like)\n        assert isinstance(arr, np.ndarray)\n\n    test()\n"
  },
  {
    "path": "hypothesis-python/tests/numpy/test_gen_data.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport sys\nfrom functools import reduce\nfrom itertools import zip_longest\n\nimport numpy as np\nimport pytest\n\nfrom hypothesis import (\n    HealthCheck,\n    Phase,\n    assume,\n    given,\n    note,\n    settings,\n    strategies as st,\n    target,\n)\nfrom hypothesis.errors import InvalidArgument, UnsatisfiedAssumption\nfrom hypothesis.extra import numpy as nps\nfrom hypothesis.strategies._internal.lazy import unwrap_strategies\n\nfrom tests.common.debug import (\n    assert_all_examples,\n    check_can_generate_examples,\n    find_any,\n    minimal,\n)\nfrom tests.common.utils import fails_with, flaky\n\nANY_SHAPE = nps.array_shapes(min_dims=0, max_dims=32, min_side=0, max_side=32)\nANY_NONZERO_SHAPE = nps.array_shapes(min_dims=0, max_dims=32, min_side=1, max_side=32)\n\n\n@given(nps.arrays(float, ()))\ndef test_empty_dimensions_are_arrays(x):\n    assert isinstance(x, np.ndarray)\n    assert x.dtype.kind == \"f\"\n\n\n@given(nps.arrays(float, (1, 0, 1)))\ndef test_can_handle_zero_dimensions(x):\n    assert x.shape == (1, 0, 1)\n\n\n@given(nps.arrays(\"uint32\", (5, 5)))\ndef test_generates_unsigned_ints(x):\n    assert (x >= 0).all()\n\n\n@given(nps.arrays(int, (1,)))\ndef test_assert_fits_in_machine_size(x):\n    pass\n\n\ndef test_generates_and_minimizes():\n    assert (minimal(nps.arrays(float, (2, 2))) == np.zeros(shape=(2, 2))).all()\n\n\ndef test_can_minimize_large_arrays():\n    x = minimal(nps.arrays(\"uint32\", 100), lambda x: np.any(x) and not np.all(x))\n    assert np.logical_or(x == 0, x == 1).all()\n    assert np.count_nonzero(x) in (1, len(x) - 1)\n\n\n@flaky(max_runs=50, min_passes=1)\ndef test_can_minimize_float_arrays():\n    with np.errstate(over=\"ignore\", invalid=\"ignore\"):\n        x = minimal(nps.arrays(float, 50), lambda t: np.nansum(t) >= 1.0)\n        assert x.sum() in (1, 50)\n\n\nclass Foo:\n    pass\n\n\nfoos = st.tuples().map(lambda _: Foo())\n\n\ndef test_can_create_arrays_of_composite_types():\n    arr = minimal(nps.arrays(object, 100, elements=foos))\n    for x in arr:\n        assert isinstance(x, Foo)\n\n\n@given(st.lists(st.integers()), st.data())\ndef test_can_create_zero_dim_arrays_of_lists(x, data):\n    arr = data.draw(nps.arrays(object, (), elements=st.just(x)))\n    assert arr.shape == ()\n    assert arr.dtype == np.dtype(object)\n    assert arr.item() == x\n\n\ndef test_can_create_arrays_of_tuples():\n    arr = minimal(\n        nps.arrays(object, 10, elements=st.tuples(st.integers(), st.integers())),\n        lambda x: all(t0 != t1 for t0, t1 in x),\n    )\n    assert all(a in ((1, 0), (0, 1)) for a in arr)\n\n\n@given(nps.arrays(object, (2, 2), elements=st.tuples(st.integers())))\ndef test_does_not_flatten_arrays_of_tuples(arr):\n    assert isinstance(arr[0][0], tuple)\n\n\n@given(\n    nps.arrays(object, (2, 2), elements=st.lists(st.integers(), min_size=1, max_size=1))\n)\ndef test_does_not_flatten_arrays_of_lists(arr):\n    assert isinstance(arr[0][0], list)\n\n\n@given(nps.array_shapes())\ndef test_can_generate_array_shapes(shape):\n    assert isinstance(shape, tuple)\n    assert all(isinstance(i, int) for i in shape)\n\n\n@settings(\n    deadline=None, max_examples=10, suppress_health_check=[HealthCheck.nested_given]\n)\n@given(st.integers(0, 10), st.integers(0, 9), st.integers(0), st.integers(0))\ndef test_minimise_array_shapes(min_dims, dim_range, min_side, side_range):\n    smallest = minimal(\n        nps.array_shapes(\n            min_dims=min_dims,\n            max_dims=min_dims + dim_range,\n            min_side=min_side,\n            max_side=min_side + side_range,\n        )\n    )\n    assert len(smallest) == min_dims\n    assert all(k == min_side for k in smallest)\n\n\n@pytest.mark.parametrize(\n    \"kwargs\", [{\"min_side\": 100}, {\"min_dims\": 15}, {\"min_dims\": 32}]\n)\ndef test_interesting_array_shapes_argument(kwargs):\n    check_can_generate_examples(nps.array_shapes(**kwargs))\n\n\n@given(nps.scalar_dtypes())\ndef test_can_generate_scalar_dtypes(dtype):\n    assert isinstance(dtype, np.dtype)\n\n\n@settings(max_examples=100)\n@given(\n    nps.nested_dtypes(\n        subtype_strategy=st.one_of(\n            nps.scalar_dtypes(), nps.byte_string_dtypes(), nps.unicode_string_dtypes()\n        )\n    )\n)\ndef test_can_generate_compound_dtypes(dtype):\n    assert isinstance(dtype, np.dtype)\n\n\n@settings(max_examples=100)\n@given(\n    nps.nested_dtypes(\n        subtype_strategy=st.one_of(\n            nps.scalar_dtypes(), nps.byte_string_dtypes(), nps.unicode_string_dtypes()\n        )\n    ).flatmap(lambda dt: nps.arrays(dtype=dt, shape=1))\n)\ndef test_can_generate_data_compound_dtypes(arr):\n    # This is meant to catch the class of errors which prompted PR #2085\n    assert isinstance(arr, np.ndarray)\n\n\n@given(nps.nested_dtypes())\ndef test_np_dtype_is_idempotent(dtype):\n    assert dtype == np.dtype(dtype)\n\n\ndef test_minimise_scalar_dtypes():\n    assert minimal(nps.scalar_dtypes()) == np.dtype(\"bool\")\n\n\ndef test_minimise_nested_types():\n    assert minimal(nps.nested_dtypes()) == np.dtype(\"bool\")\n\n\ndef test_minimise_array_strategy():\n    smallest = minimal(\n        nps.arrays(\n            nps.nested_dtypes(max_itemsize=200),\n            nps.array_shapes(max_dims=3, max_side=3),\n        )\n    )\n    assert smallest.dtype == np.dtype(\"bool\")\n    assert not smallest.any()\n\n\n@given(nps.array_dtypes(allow_subarrays=False))\ndef test_can_turn_off_subarrays(dt):\n    for name in dt.names:\n        assert dt.fields[name][0].shape == ()\n\n\ndef test_array_dtypes_may_have_field_titles():\n    find_any(nps.array_dtypes(), lambda dt: len(dt.fields) > len(dt.names))\n\n\n@pytest.mark.parametrize(\"byteorder\", [\"<\", \">\"])\n@given(data=st.data())\ndef test_can_restrict_endianness(data, byteorder):\n    dtype = data.draw(nps.integer_dtypes(endianness=byteorder, sizes=(16, 32, 64)))\n    if byteorder == (\"<\" if sys.byteorder == \"little\" else \">\"):\n        assert dtype.byteorder == \"=\"\n    else:\n        assert dtype.byteorder == byteorder\n\n\n@given(nps.integer_dtypes(sizes=8))\ndef test_can_specify_size_as_an_int(dt):\n    assert dt.itemsize == 1\n\n\n@given(st.data())\ndef test_can_draw_arrays_from_scalars(data):\n    dt = data.draw(nps.scalar_dtypes())\n    result = data.draw(nps.arrays(dtype=dt, shape=()))\n    assert isinstance(result, np.ndarray)\n    assert result.dtype == dt\n\n\n@given(st.data())\ndef test_can_cast_for_arrays(data):\n    # Note: this only passes with castable datatypes, certain dtype\n    # combinations will result in an error if numpy is not able to cast them.\n    dt_elements = np.dtype(data.draw(st.sampled_from([\"bool\", \"<i2\", \">i2\"])))\n    dt_desired = np.dtype(\n        data.draw(st.sampled_from([\"<i2\", \">i2\", \"float32\", \"float64\"]))\n    )\n    result = data.draw(\n        nps.arrays(\n            dtype=dt_desired, elements=nps.from_dtype(dt_elements), shape=(1, 2, 3)\n        )\n    )\n    assert isinstance(result, np.ndarray)\n    assert result.dtype == dt_desired\n\n\n@given(nps.arrays(dtype=\"int8\", shape=st.integers(0, 20), unique=True))\ndef test_array_values_are_unique(arr):\n    assert len(set(arr)) == len(arr)\n\n\ndef test_cannot_generate_unique_array_of_too_many_elements():\n    strat = nps.arrays(dtype=int, elements=st.integers(0, 5), shape=10, unique=True)\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(strat)\n\n\n@given(\n    nps.arrays(\n        elements=st.just(0.0),\n        dtype=float,\n        fill=st.just(np.nan),\n        shape=st.integers(0, 20),\n        unique=True,\n    )\n)\ndef test_array_values_are_unique_high_collision(arr):\n    assert (arr == 0.0).sum() <= 1\n\n\n@given(nps.arrays(dtype=\"int8\", shape=(4,), elements=st.integers(0, 3), unique=True))\ndef test_generates_all_values_for_unique_array(arr):\n    # Ensures that the \"reject already-seen element\" branch is covered\n    assert len(set(arr)) == len(arr)\n\n\n@given(nps.arrays(dtype=\"int8\", shape=255, unique=True))\ndef test_efficiently_generates_all_unique_array(arr):\n    # Avoids the birthday paradox with UniqueSampledListStrategy\n    assert len(set(arr)) == len(arr)\n\n\n@given(st.data(), st.integers(-100, 100), st.integers(1, 100))\ndef test_array_element_rewriting(data, start, size):\n    arr = nps.arrays(\n        dtype=np.dtype(\"int64\"),\n        shape=size,\n        elements=st.integers(start, start + size - 1),\n        unique=True,\n    )\n    assert set(data.draw(arr)) == set(range(start, start + size))\n\n\ndef test_may_fill_with_nan_when_unique_is_set():\n    find_any(\n        nps.arrays(\n            dtype=float,\n            elements=st.floats(allow_nan=False),\n            shape=10,\n            unique=True,\n            fill=st.just(np.nan),\n        ),\n        lambda x: np.isnan(x).any(),\n    )\n\n\n@given(\n    nps.arrays(\n        dtype=float,\n        elements=st.floats(allow_nan=False),\n        shape=10,\n        unique=True,\n        fill=st.just(np.nan),\n    )\n)\ndef test_is_still_unique_with_nan_fill(xs):\n    assert len(set(xs)) == len(xs)\n\n\n@fails_with(InvalidArgument)\n@given(\n    nps.arrays(\n        dtype=float,\n        elements=st.floats(allow_nan=False),\n        shape=10,\n        unique=True,\n        fill=st.just(0.0),\n    )\n)\ndef test_may_not_fill_with_non_nan_when_unique_is_set(arr):\n    pass\n\n\n@fails_with(InvalidArgument)\n@given(nps.arrays(dtype=\"U\", shape=10, unique=True, fill=st.just(\"\")))\ndef test_may_not_fill_with_non_nan_when_unique_is_set_and_type_is_not_number(arr):\n    pass\n\n\nnp_version = tuple(int(x) for x in np.__version__.split(\".\")[:2])\n\n\n@pytest.mark.parametrize(\"fill\", [False, True])\n# Overflowing elements deprecated upstream in Numpy 1.24 :-)\n@fails_with(\n    InvalidArgument\n    if np_version < (1, 24)\n    else (DeprecationWarning if np_version < (2, 0) else OverflowError)\n)\n@given(st.data())\ndef test_overflowing_integers_are_deprecated(fill, data):\n    kw = {\"elements\": st.just(300)}\n    if fill:\n        kw = {\"elements\": st.nothing(), \"fill\": kw[\"elements\"]}\n    arr = data.draw(nps.arrays(dtype=\"int8\", shape=(1,), **kw))\n    assert arr[0] == (300 % 256)\n\n\n@pytest.mark.parametrize(\"fill\", [False, True])\n@pytest.mark.parametrize(\n    \"dtype,strat\",\n    [\n        (\"float16\", st.floats(min_value=65520, allow_infinity=False)),\n        (\"float32\", st.floats(min_value=10**40, allow_infinity=False)),\n        (\n            \"complex64\",\n            st.complex_numbers(min_magnitude=10**300, allow_infinity=False),\n        ),\n        (\"U1\", st.text(min_size=2, max_size=2)),\n        (\"S1\", st.binary(min_size=2, max_size=2)),\n    ],\n)\n@fails_with(InvalidArgument)\n@given(data=st.data())\ndef test_unrepresentable_elements_are_deprecated(fill, dtype, strat, data):\n    if fill:\n        kw = {\"elements\": st.nothing(), \"fill\": strat}\n    else:\n        kw = {\"elements\": strat}\n    try:\n        arr = data.draw(nps.arrays(dtype=dtype, shape=(1,), **kw))\n    except RuntimeWarning:\n        assert np_version >= (1, 24), \"New overflow-on-cast detection\"\n        raise InvalidArgument(\"so the test passes\") from None\n\n    try:\n        # This is a float or complex number, and has overflowed to infinity,\n        # triggering our deprecation for overflow.\n        assert np.isinf(arr[0])\n    except TypeError:\n        # We tried to call isinf on a string.  The string was generated at\n        # length two, then truncated by the dtype of size 1 - deprecation\n        # again.  If the first character was \\0 it is now the empty string.\n        assert len(arr[0]) <= 1\n\n\n@given(nps.arrays(dtype=\"float16\", shape=(1,)))\ndef test_inferred_floats_do_not_overflow(arr):\n    pass\n\n\n@given(nps.arrays(dtype=\"float16\", shape=10, elements={\"min_value\": 0, \"max_value\": 1}))\ndef test_inferred_floats_can_be_constrained_at_low_width(arr):\n    assert (arr >= 0).all()\n    assert (arr <= 1).all()\n\n\n@given(\n    nps.arrays(\n        dtype=\"float16\",\n        shape=10,\n        elements={\n            \"min_value\": 0,\n            \"max_value\": 1,\n            \"exclude_min\": True,\n            \"exclude_max\": True,\n        },\n    )\n)\ndef test_inferred_floats_can_be_constrained_at_low_width_excluding_endpoints(arr):\n    assert (arr > 0).all()\n    assert (arr < 1).all()\n\n\n@given(\n    nps.arrays(\n        dtype=\"float16\",\n        shape=10,\n        unique=True,\n        elements=st.integers(1, 9),\n        fill=st.just(np.nan),\n    )\n)\ndef test_unique_array_with_fill_can_use_all_elements(arr):\n    assume(len(set(arr)) == arr.size)\n\n\n@given(nps.arrays(dtype=\"uint8\", shape=25, unique=True, fill=st.nothing()))\ndef test_unique_array_without_fill(arr):\n    # This test covers the collision-related branches for fully dense unique arrays.\n    # Choosing 25 of 256 possible elements means we're almost certain to see collisions\n    # thanks to the 'birthday paradox', but finding unique elemennts is still easy.\n    assume(len(set(arr)) == arr.size)\n\n\n@given(ndim=st.integers(0, 5), data=st.data())\ndef test_mapped_positive_axes_are_unique(ndim, data):\n    min_size = data.draw(st.integers(0, ndim), label=\"min_size\")\n    max_size = data.draw(st.integers(min_size, ndim), label=\"max_size\")\n    axes = data.draw(\n        nps.valid_tuple_axes(ndim, min_size=min_size, max_size=max_size), label=\"axes\"\n    )\n    assert len(set(axes)) == len({i if 0 < i else ndim + i for i in axes})\n\n\n@given(ndim=st.integers(0, 5), data=st.data())\ndef test_length_bounds_are_satisfied(ndim, data):\n    min_size = data.draw(st.integers(0, ndim), label=\"min_size\")\n    max_size = data.draw(st.integers(min_size, ndim), label=\"max_size\")\n    axes = data.draw(\n        nps.valid_tuple_axes(ndim, min_size=min_size, max_size=max_size), label=\"axes\"\n    )\n    assert min_size <= len(axes) <= max_size\n\n\n@given(shape=nps.array_shapes(), data=st.data())\ndef test_axes_are_valid_inputs_to_sum(shape, data):\n    x = np.zeros(shape, dtype=\"uint8\")\n    axes = data.draw(nps.valid_tuple_axes(ndim=len(shape)), label=\"axes\")\n    np.sum(x, axes)\n\n\n@settings(\n    deadline=None, max_examples=10, suppress_health_check=[HealthCheck.nested_given]\n)\n@given(ndim=st.integers(0, 3), data=st.data())\ndef test_minimize_tuple_axes(ndim, data):\n    min_size = data.draw(st.integers(0, ndim), label=\"min_size\")\n    max_size = data.draw(st.integers(min_size, ndim), label=\"max_size\")\n    smallest = minimal(nps.valid_tuple_axes(ndim, min_size=min_size, max_size=max_size))\n    assert len(smallest) == min_size\n    assert all(k > -1 for k in smallest)\n\n\n@settings(\n    deadline=None, max_examples=10, suppress_health_check=[HealthCheck.nested_given]\n)\n@given(ndim=st.integers(0, 3), data=st.data())\ndef test_minimize_negative_tuple_axes(ndim, data):\n    min_size = data.draw(st.integers(0, ndim), label=\"min_size\")\n    max_size = data.draw(st.integers(min_size, ndim), label=\"max_size\")\n    smallest = minimal(\n        nps.valid_tuple_axes(ndim, min_size=min_size, max_size=max_size),\n        lambda x: all(i < 0 for i in x),\n    )\n    assert len(smallest) == min_size\n\n\n@given(nps.broadcastable_shapes((), min_side=0, max_side=0, min_dims=0, max_dims=0))\ndef test_broadcastable_empty_shape(shape):\n    assert shape == ()\n\n\n@settings(deadline=None, suppress_health_check=[HealthCheck.too_slow])\n@given(shape=ANY_SHAPE, data=st.data())\ndef test_broadcastable_shape_bounds_are_satisfied(shape, data):\n    min_dims = data.draw(st.integers(0, 32), label=\"min_dims\")\n    max_dims = data.draw(st.none() | st.integers(min_dims, 32), label=\"max_dims\")\n    min_side = data.draw(st.integers(0, 3), label=\"min_side\")\n    max_side = data.draw(st.none() | st.integers(min_side, 6), label=\"max_side\")\n    try:\n        bshape = data.draw(\n            nps.broadcastable_shapes(\n                shape,\n                min_side=min_side,\n                max_side=max_side,\n                min_dims=min_dims,\n                max_dims=max_dims,\n            ),\n            label=\"bshape\",\n        )\n    except InvalidArgument:\n        raise UnsatisfiedAssumption from None\n\n    if max_dims is None:\n        max_dims = max(len(shape), min_dims) + 2\n\n    if max_side is None:\n        max_side = max((*shape[::-1][:max_dims], min_side)) + 2\n\n    assert isinstance(bshape, tuple)\n    assert all(isinstance(s, int) for s in bshape)\n    assert min_dims <= len(bshape) <= max_dims\n    assert all(min_side <= s <= max_side for s in bshape)\n\n\n@settings(deadline=None)\n@given(num_shapes=st.integers(1, 4), base_shape=ANY_SHAPE, data=st.data())\ndef test_mutually_broadcastable_shape_bounds_are_satisfied(\n    num_shapes, base_shape, data\n):\n    min_dims = data.draw(st.integers(0, 32), label=\"min_dims\")\n    max_dims = data.draw(\n        st.one_of(st.none(), st.integers(min_dims, 32)), label=\"max_dims\"\n    )\n    min_side = data.draw(st.integers(0, 3), label=\"min_side\")\n    max_side = data.draw(\n        st.one_of(st.none(), st.integers(min_side, 6)), label=\"max_side\"\n    )\n    try:\n        shapes, result = data.draw(\n            nps.mutually_broadcastable_shapes(\n                num_shapes=num_shapes,\n                base_shape=base_shape,\n                min_side=min_side,\n                max_side=max_side,\n                min_dims=min_dims,\n                max_dims=max_dims,\n            ),\n            label=\"shapes, result\",\n        )\n    except InvalidArgument:\n        raise UnsatisfiedAssumption from None\n\n    if max_dims is None:\n        max_dims = max(len(base_shape), min_dims) + 2\n\n    if max_side is None:\n        max_side = max((*base_shape[::-1][:max_dims], min_side)) + 2\n\n    assert isinstance(shapes, tuple)\n    assert isinstance(result, tuple)\n    assert all(isinstance(s, int) for s in result)\n\n    for bshape in shapes:\n        assert isinstance(bshape, tuple)\n        assert all(isinstance(s, int) for s in bshape)\n        assert min_dims <= len(bshape) <= max_dims\n        assert all(min_side <= s <= max_side for s in bshape)\n\n\ndef _draw_valid_bounds(data, shape, max_dims, *, permit_none=True):\n    if max_dims == 0 or not shape:\n        return 0, None\n\n    smallest_side = min(shape[::-1][:max_dims])\n    min_strat = (\n        st.sampled_from([1, smallest_side])\n        if smallest_side > 1\n        else st.just(smallest_side)\n    )\n    min_side = data.draw(min_strat, label=\"min_side\")\n    largest_side = max(max(shape[::-1][:max_dims]), min_side)\n    if permit_none:\n        max_strat = st.one_of(st.none(), st.integers(largest_side, largest_side + 2))\n    else:\n        max_strat = st.integers(largest_side, largest_side + 2)\n    max_side = data.draw(max_strat, label=\"max_side\")\n    return min_side, max_side\n\n\ndef _broadcast_two_shapes(shape_a: nps.Shape, shape_b: nps.Shape) -> nps.Shape:\n    result = []\n    for a, b in zip_longest(reversed(shape_a), reversed(shape_b), fillvalue=1):\n        if a != b and (a != 1) and (b != 1):\n            raise ValueError(\n                f\"shapes {shape_a!r} and {shape_b!r} are not broadcast-compatible\"\n            )\n        result.append(a if a != 1 else b)\n    return tuple(reversed(result))\n\n\ndef _broadcast_shapes(*shapes):\n    \"\"\"Returns the shape resulting from broadcasting the\n    input shapes together.\n\n    Raises ValueError if the shapes are not broadcast-compatible\"\"\"\n    assert shapes, \"Must pass >=1 shapes to broadcast\"\n    return reduce(_broadcast_two_shapes, shapes, ())\n\n\n@settings(deadline=None, max_examples=500)\n@given(\n    shapes=st.lists(\n        nps.array_shapes(min_dims=0, min_side=0, max_dims=4, max_side=4), min_size=1\n    )\n)\ndef test_broadcastable_shape_util(shapes):\n    \"\"\"Ensures that `_broadcast_shapes` raises when fed incompatible shapes,\n    and ensures that it produces the true broadcasted shape\"\"\"\n    if len(shapes) == 1:\n        assert _broadcast_shapes(*shapes) == shapes[0]\n        return\n\n    arrs = [np.zeros(s, dtype=np.uint8) for s in shapes]\n\n    try:\n        broadcast_out = np.broadcast_arrays(*arrs)\n    except ValueError:\n        with pytest.raises(ValueError):\n            _broadcast_shapes(*shapes)\n        return\n    broadcasted_shape = _broadcast_shapes(*shapes)\n\n    assert broadcast_out[0].shape == broadcasted_shape\n\n\n@settings(deadline=None, max_examples=200)\n@given(shape=ANY_NONZERO_SHAPE, data=st.data())\ndef test_broadcastable_shape_has_good_default_values(shape, data):\n    # This test ensures that default parameters can always produce broadcast-compatible shapes\n    broadcastable_shape = data.draw(\n        nps.broadcastable_shapes(shape), label=\"broadcastable_shapes\"\n    )\n    # error if drawn shape for b is not broadcast-compatible\n    _broadcast_shapes(shape, broadcastable_shape)\n\n\n@settings(deadline=None, max_examples=200)\n@given(base_shape=ANY_SHAPE, num_shapes=st.integers(1, 10), data=st.data())\ndef test_mutually_broadcastableshapes_has_good_default_values(\n    num_shapes, base_shape, data\n):\n    # This test ensures that default parameters can always produce broadcast-compatible shapes\n    shapes, result = data.draw(\n        nps.mutually_broadcastable_shapes(num_shapes=num_shapes, base_shape=base_shape),\n        label=\"shapes, result\",\n    )\n    assert len(shapes) == num_shapes\n    # raises if shapes are not mutually-compatible\n    assert result == _broadcast_shapes(base_shape, *shapes)\n\n\n@settings(deadline=None)\n@given(min_dims=st.integers(0, 32), shape=ANY_SHAPE, data=st.data())\ndef test_broadcastable_shape_can_broadcast(min_dims, shape, data):\n    max_dims = data.draw(st.none() | st.integers(min_dims, 32), label=\"max_dims\")\n    min_side, max_side = _draw_valid_bounds(data, shape, max_dims)\n    broadcastable_shape = data.draw(\n        nps.broadcastable_shapes(\n            shape,\n            min_side=min_side,\n            max_side=max_side,\n            min_dims=min_dims,\n            max_dims=max_dims,\n        ),\n        label=\"broadcastable_shapes\",\n    )\n    # error if drawn shape for b is not broadcast-compatible\n    _broadcast_shapes(shape, broadcastable_shape)\n\n\n@settings(deadline=None)\n@given(\n    num_shapes=st.integers(1, 10),\n    min_dims=st.integers(0, 32),\n    base_shape=ANY_SHAPE,\n    data=st.data(),\n)\ndef test_mutually_broadcastable_shape_can_broadcast(\n    num_shapes, min_dims, base_shape, data\n):\n    max_dims = data.draw(st.none() | st.integers(min_dims, 32), label=\"max_dims\")\n    min_side, max_side = _draw_valid_bounds(data, base_shape, max_dims)\n    shapes, result = data.draw(\n        nps.mutually_broadcastable_shapes(\n            num_shapes=num_shapes,\n            base_shape=base_shape,\n            min_side=min_side,\n            max_side=max_side,\n            min_dims=min_dims,\n            max_dims=max_dims,\n        ),\n        label=\"shapes, result\",\n    )\n\n    # error if drawn shapes are not mutually broadcast-compatible\n    assert result == _broadcast_shapes(base_shape, *shapes)\n\n\n@settings(\n    deadline=None, max_examples=50, suppress_health_check=[HealthCheck.nested_given]\n)\n@given(\n    num_shapes=st.integers(1, 3),\n    min_dims=st.integers(0, 5),\n    base_shape=nps.array_shapes(min_dims=0, max_dims=3, min_side=0, max_side=5),\n    data=st.data(),\n)\ndef test_minimize_mutually_broadcastable_shape(num_shapes, min_dims, base_shape, data):\n    # Ensure aligned dimensions of broadcastable shape minimizes to `(1,) * min_dims`\n    max_dims = data.draw(st.none() | st.integers(min_dims, 5), label=\"max_dims\")\n    min_side, max_side = _draw_valid_bounds(\n        data, base_shape, max_dims, permit_none=False\n    )\n\n    if num_shapes > 1:\n        # shrinking gets a little bit hairy when we have empty axes\n        # and multiple num_shapes\n        assume(min_side > 0)\n\n    smallest_shapes, result = minimal(\n        nps.mutually_broadcastable_shapes(\n            num_shapes=num_shapes,\n            base_shape=base_shape,\n            min_side=min_side,\n            max_side=max_side,\n            min_dims=min_dims,\n            max_dims=max_dims,\n        )\n    )\n    note(f\"smallest_shapes: {smallest_shapes}\")\n    note(f\"result: {result}\")\n    assert len(smallest_shapes) == num_shapes\n    assert result == _broadcast_shapes(base_shape, *smallest_shapes)\n    for smallest in smallest_shapes:\n        n_leading = max(len(smallest) - len(base_shape), 0)\n        n_aligned = max(len(smallest) - n_leading, 0)\n        note(f\"n_leading: {n_leading}\")\n        note(f\"n_aligned: {n_aligned} {base_shape[-n_aligned:]}\")\n        expected = [min_side] * n_leading + [\n            (min(1, i) if i != 1 else min_side) if min_side <= 1 <= max_side else i\n            for i in (base_shape[-n_aligned:] if n_aligned else ())\n        ]\n        assert tuple(expected) == smallest\n\n\n@settings(deadline=None)\n@given(max_dims=st.integers(4, 6), data=st.data())\ndef test_broadcastable_shape_adjusts_max_dim_with_explicit_bounds(max_dims, data):\n    # Ensures that `broadcastable_shapes` limits itself to satisfiable dimensions\n    # Broadcastable values can only be drawn for dims 0-3 for these shapes\n    shape = data.draw(st.sampled_from([(5, 3, 2, 1), (0, 3, 2, 1)]), label=\"shape\")\n    broadcastable_shape = data.draw(\n        nps.broadcastable_shapes(\n            shape, min_side=2, max_side=3, min_dims=3, max_dims=max_dims\n        ),\n        label=\"broadcastable_shapes\",\n    )\n    assert len(broadcastable_shape) == 3\n    # error if drawn shape for b is not broadcast-compatible\n    _broadcast_shapes(shape, broadcastable_shape)\n\n\n@settings(deadline=None)\n@given(\n    max_side=st.sampled_from([3, None]),\n    min_dims=st.integers(0, 4),\n    num_shapes=st.integers(1, 3),\n    data=st.data(),\n)\ndef test_mutually_broadcastable_shape_adjusts_max_dim_with_default_bounds(\n    max_side, min_dims, num_shapes, data\n):\n    # Ensures that `mutually_broadcastable_shapes` limits itself to satisfiable dimensions\n    # when a default `max_dims` is derived.\n    base_shape = data.draw(\n        st.sampled_from([(5, 3, 2, 1), (0, 3, 2, 1)]), label=\"base_shape\"\n    )\n\n    try:\n        shapes, result = data.draw(\n            nps.mutually_broadcastable_shapes(\n                num_shapes=num_shapes,\n                base_shape=base_shape,\n                min_side=2,\n                max_side=max_side,\n                min_dims=min_dims,\n            ),\n            label=\"shapes, result\",\n        )\n    except InvalidArgument:\n        # There is no satisfiable `max_dims` for us to tune\n        assert min_dims == 4\n        assert max_side == 3 or base_shape[0] == 0\n        return\n\n    if max_side == 3 or base_shape[0] == 0:\n        assert all(len(s) <= 3 for s in shapes)\n    elif min_dims == 4:\n        assert all(4 <= len(s) for s in shapes)\n\n    # error if drawn shape for b is not broadcast-compatible\n    assert len(shapes) == num_shapes\n    assert result == _broadcast_shapes(base_shape, *shapes)\n\n\n@settings(\n    deadline=None, max_examples=10, suppress_health_check=[HealthCheck.nested_given]\n)\n@given(min_dims=st.integers(0, 32), min_side=st.integers(2, 3), data=st.data())\ndef test_broadcastable_shape_shrinking_with_singleton_out_of_bounds(\n    min_dims, min_side, data\n):\n    max_dims = data.draw(st.none() | st.integers(min_dims, 32), label=\"max_dims\")\n    max_side = data.draw(st.none() | st.integers(min_side, 6), label=\"max_side\")\n    shape = data.draw(st.integers(1, 4).map(lambda n: n * (1,)), label=\"shape\")\n    smallest = minimal(\n        nps.broadcastable_shapes(\n            shape,\n            min_side=min_side,\n            max_side=max_side,\n            min_dims=min_dims,\n            max_dims=max_dims,\n        )\n    )\n    assert smallest == (min_side,) * min_dims\n\n\n@settings(\n    deadline=None, max_examples=50, suppress_health_check=[HealthCheck.nested_given]\n)\n@given(\n    num_shapes=st.integers(1, 4),\n    min_dims=st.integers(0, 4),\n    min_side=st.integers(2, 3),\n    data=st.data(),\n)\ndef test_mutually_broadcastable_shapes_shrinking_with_singleton_out_of_bounds(\n    num_shapes, min_dims, min_side, data\n):\n    \"\"\"Ensures that shapes minimize to `(min_side,) * min_dims` when singleton dimensions\n    are disallowed.\"\"\"\n    max_dims = data.draw(st.none() | st.integers(min_dims, 4), label=\"max_dims\")\n    max_side = data.draw(\n        st.one_of(st.none(), st.integers(min_side, 6)), label=\"max_side\"\n    )\n    ndims = data.draw(st.integers(1, 4), label=\"ndim\")\n    base_shape = (1,) * ndims\n    smallest_shapes, result = minimal(\n        nps.mutually_broadcastable_shapes(\n            num_shapes=num_shapes,\n            base_shape=base_shape,\n            min_side=min_side,\n            max_side=max_side,\n            min_dims=min_dims,\n            max_dims=max_dims,\n        )\n    )\n    note(f\"(smallest_shapes, result): {(smallest_shapes, result)}\")\n    assert len(smallest_shapes) == num_shapes\n    assert result == _broadcast_shapes(base_shape, *smallest_shapes)\n    for smallest in smallest_shapes:\n        assert smallest == (min_side,) * min_dims\n\n\n@settings(suppress_health_check=[HealthCheck.too_slow])\n@given(\n    num_shapes=st.integers(1, 4),\n    min_dims=st.integers(1, 32),\n    max_side=st.integers(1, 6),\n    data=st.data(),\n)\ndef test_mutually_broadcastable_shapes_only_singleton_is_valid(\n    num_shapes, min_dims, max_side, data\n):\n    \"\"\"Ensures that, when all aligned base-shape dim sizes are larger\n    than ``max_side``, only singletons can be drawn\"\"\"\n    max_dims = data.draw(st.integers(min_dims, 32), label=\"max_dims\")\n    base_shape = data.draw(\n        nps.array_shapes(min_side=max_side + 1, min_dims=1), label=\"base_shape\"\n    )\n    input_shapes, result = data.draw(\n        nps.mutually_broadcastable_shapes(\n            num_shapes=num_shapes,\n            base_shape=base_shape,\n            min_side=1,\n            max_side=max_side,\n            min_dims=min_dims,\n            max_dims=max_dims,\n        ),\n        label=\"input_shapes, result\",\n    )\n\n    assert len(input_shapes) == num_shapes\n    assert result == _broadcast_shapes(base_shape, *input_shapes)\n    for shape in input_shapes:\n        assert all(i == 1 for i in shape[-len(base_shape) :])\n\n\n@settings(deadline=None, suppress_health_check=[HealthCheck.too_slow])\n@given(\n    shape=nps.array_shapes(min_dims=0, max_dims=3, min_side=0, max_side=5),\n    max_dims=st.integers(0, 6),\n    data=st.data(),\n)\ndef test_broadcastable_shape_can_generate_arbitrary_ndims(shape, max_dims, data):\n    # ensures that generates shapes can possess any length in [min_dims, max_dims]\n    desired_ndim = data.draw(st.integers(0, max_dims), label=\"desired_ndim\")\n    min_dims = data.draw(\n        st.one_of(st.none(), st.integers(0, desired_ndim)), label=\"min_dims\"\n    )\n    # check default arg behavior too\n    kwargs = {\"min_dims\": min_dims} if min_dims is not None else {}\n    find_any(\n        nps.broadcastable_shapes(shape, min_side=0, max_dims=max_dims, **kwargs),\n        lambda x: len(x) == desired_ndim,\n        settings(max_examples=10**6),\n    )\n\n\n@settings(deadline=None)\n@given(\n    num_shapes=st.integers(1, 3),\n    base_shape=nps.array_shapes(min_dims=0, max_dims=3, min_side=0, max_side=5),\n    max_dims=st.integers(0, 4),\n    data=st.data(),\n)\ndef test_mutually_broadcastable_shapes_can_generate_arbitrary_ndims(\n    num_shapes, base_shape, max_dims, data\n):\n    # ensures that each generated shape can possess any length in [min_dims, max_dims]\n    desired_ndims = data.draw(\n        st.lists(st.integers(0, max_dims), min_size=num_shapes, max_size=num_shapes),\n        label=\"desired_ndims\",\n    )\n    min_dims = data.draw(\n        st.one_of(st.none(), st.integers(0, min(desired_ndims))), label=\"min_dims\"\n    )\n    # check default arg behavior too\n    kwargs = {\"min_dims\": min_dims} if min_dims is not None else {}\n    find_any(\n        nps.mutually_broadcastable_shapes(\n            num_shapes=num_shapes,\n            base_shape=base_shape,\n            min_side=0,\n            max_dims=max_dims,\n            **kwargs,\n        ),\n        lambda x: {len(s) for s in x.input_shapes} == set(desired_ndims),\n        settings(max_examples=10**6),\n    )\n\n\n@settings(deadline=None, suppress_health_check=list(HealthCheck))\n@given(\n    base_shape=nps.array_shapes(min_dims=0, max_dims=3, min_side=0, max_side=2),\n    max_dims=st.integers(1, 4),\n)\ndef test_mutually_broadcastable_shapes_can_generate_interesting_singletons(\n    base_shape, max_dims\n):\n    find_any(\n        nps.mutually_broadcastable_shapes(\n            num_shapes=2,\n            base_shape=base_shape,\n            min_side=0,\n            max_dims=max_dims,\n        ),\n        lambda x: any(a != b for a, b in zip(*(s[::-1] for s in x.input_shapes), strict=False)),  # type: ignore\n    )\n\n\n@pytest.mark.parametrize(\"base_shape\", [(), (0,), (1,), (2,), (1, 2), (2, 1), (2, 2)])\ndef test_mutually_broadcastable_shapes_can_generate_mirrored_singletons(base_shape):\n    def f(shapes: nps.BroadcastableShapes):\n        x, y = shapes.input_shapes\n        return x.count(1) == 1 and y.count(1) == 1 and x[::-1] == y\n\n    find_any(\n        nps.mutually_broadcastable_shapes(\n            num_shapes=2,\n            base_shape=base_shape,\n            min_side=0,\n            max_side=3,\n            min_dims=2,\n            max_dims=2,\n        ),\n        f,\n    )\n\n\n@settings(deadline=None)\n@given(\n    shape=nps.array_shapes(min_dims=1, min_side=1),\n    dtype=st.one_of(nps.unsigned_integer_dtypes(), nps.integer_dtypes()),\n    data=st.data(),\n)\ndef test_advanced_integer_index_is_valid_with_default_result_shape(shape, dtype, data):\n    index = data.draw(nps.integer_array_indices(shape, dtype=dtype))\n    x = np.zeros(shape)\n    out = x[index]  # raises if the index is invalid\n    assert not np.shares_memory(x, out)  # advanced indexing should not return a view\n    assert all(dtype == x.dtype for x in index)\n\n\n@settings(deadline=None)\n@given(\n    shape=nps.array_shapes(min_dims=1, min_side=1),\n    min_dims=st.integers(0, 3),\n    min_side=st.integers(0, 3),\n    dtype=st.one_of(nps.unsigned_integer_dtypes(), nps.integer_dtypes()),\n    data=st.data(),\n)\ndef test_advanced_integer_index_is_valid_and_satisfies_bounds(\n    shape, min_dims, min_side, dtype, data\n):\n    max_side = data.draw(st.integers(min_side, min_side + 2), label=\"max_side\")\n    max_dims = data.draw(st.integers(min_dims, min_dims + 2), label=\"max_dims\")\n    index = data.draw(\n        nps.integer_array_indices(\n            shape,\n            result_shape=nps.array_shapes(\n                min_dims=min_dims,\n                max_dims=max_dims,\n                min_side=min_side,\n                max_side=max_side,\n            ),\n            dtype=dtype,\n        )\n    )\n    x = np.zeros(shape)\n    out = x[index]  # raises if the index is invalid\n    assert all(min_side <= s <= max_side for s in out.shape)\n    assert min_dims <= out.ndim <= max_dims\n    assert not np.shares_memory(x, out)  # advanced indexing should not return a view\n    assert all(dtype == x.dtype for x in index)\n\n\n@settings(deadline=None, suppress_health_check=[HealthCheck.nested_given])\n@given(\n    shape=nps.array_shapes(min_dims=1, min_side=1),\n    min_dims=st.integers(0, 3),\n    min_side=st.integers(0, 3),\n    dtype=st.sampled_from([\"uint8\", \"int8\"]),\n    data=st.data(),\n)\ndef test_advanced_integer_index_minimizes_as_documented(\n    shape, min_dims, min_side, dtype, data\n):\n    max_side = data.draw(st.integers(min_side, min_side + 2), label=\"max_side\")\n    max_dims = data.draw(st.integers(min_dims, min_dims + 2), label=\"max_dims\")\n    result_shape = nps.array_shapes(\n        min_dims=min_dims, max_dims=max_dims, min_side=min_side, max_side=max_side\n    )\n    smallest = minimal(\n        nps.integer_array_indices(shape, result_shape=result_shape, dtype=dtype)\n    )\n    desired = len(shape) * (np.zeros(min_dims * [min_side]),)\n    assert len(smallest) == len(desired)\n    for s, d in zip(smallest, desired, strict=True):\n        np.testing.assert_array_equal(s, d)\n\n\n@settings(\n    deadline=None, max_examples=10, suppress_health_check=[HealthCheck.nested_given]\n)\n@given(\n    shape=nps.array_shapes(min_dims=1, max_dims=2, min_side=1, max_side=3),\n    data=st.data(),\n)\ndef test_advanced_integer_index_can_generate_any_pattern(shape, data):\n    # ensures that generated index-arrays can be used to yield any pattern of elements from an array\n    x = np.arange(np.prod(shape)).reshape(shape)\n\n    target_array = data.draw(\n        nps.arrays(\n            shape=nps.array_shapes(min_dims=1, max_dims=2, min_side=1, max_side=2),\n            elements=st.sampled_from(x.flatten()),\n            dtype=x.dtype,\n        ),\n        label=\"target\",\n    )\n\n    def index_selects_values_in_order(index):\n        selected = x[index]\n        target(len(set(selected.flatten())), label=\"unique indices\")\n        target(float(np.sum(target_array == selected)), label=\"elements correct\")\n        return np.all(target_array == selected)\n\n    minimal(\n        nps.integer_array_indices(shape, result_shape=st.just(target_array.shape)),\n        index_selects_values_in_order,\n        settings(max_examples=10**6, phases=[Phase.generate, Phase.target]),\n    )\n\n\n@pytest.mark.parametrize(\n    \"condition\",\n    [\n        lambda ix: isinstance(ix, tuple) and Ellipsis in ix,\n        lambda ix: isinstance(ix, tuple) and Ellipsis not in ix,\n        lambda ix: isinstance(ix, tuple) and np.newaxis in ix,\n        lambda ix: isinstance(ix, tuple) and np.newaxis not in ix,\n        lambda ix: ix is Ellipsis,\n        lambda ix: ix == np.newaxis,\n    ],\n)\ndef test_basic_indices_options(condition):\n    indexers = nps.array_shapes(min_dims=0, max_dims=32).flatmap(\n        lambda shape: nps.basic_indices(shape, allow_newaxis=True)\n    )\n    find_any(indexers, condition)\n\n\ndef test_basic_indices_can_generate_empty_tuple():\n    find_any(nps.basic_indices(shape=(0, 0), allow_ellipsis=True), lambda ix: ix == ())\n\n\ndef test_basic_indices_can_generate_non_tuples():\n    find_any(\n        nps.basic_indices(shape=(0, 0), allow_ellipsis=True),\n        lambda ix: not isinstance(ix, tuple),\n    )\n\n\ndef test_basic_indices_can_generate_long_ellipsis():\n    # Runs of slice(None) - such as [0,:,:,:,0] - can be replaced by e.g. [0,...,0]\n    find_any(\n        nps.basic_indices(shape=(1, 0, 0, 0, 1), allow_ellipsis=True),\n        lambda ix: len(ix) == 3 and ix[1] == Ellipsis,\n    )\n\n\n@given(\n    nps.basic_indices(shape=(0, 0, 0, 0, 0)).filter(\n        lambda idx: isinstance(idx, tuple) and Ellipsis in idx\n    )\n)\ndef test_basic_indices_replaces_whole_axis_slices_with_ellipsis(idx):\n    # `slice(None)` (aka `:`) is the only valid index for an axis of size\n    # zero, so if all dimensions are 0 then a `...` will replace all the\n    # slices because we generate `...` for entire contiguous runs of `:`\n    assert slice(None) not in idx\n\n\ndef test_basic_indices_can_generate_indices_not_covering_all_dims():\n    # These \"flat indices\" are skippable in the underlying BasicIndexStrategy,\n    # so we ensure we're definitely generating them for nps.basic_indices().\n    find_any(\n        nps.basic_indices(shape=(3, 3, 3)),\n        lambda ix: (\n            (not isinstance(ix, tuple) and ix != Ellipsis)\n            or (isinstance(ix, tuple) and Ellipsis not in ix and len(ix) < 3)\n        ),\n        settings=settings(max_examples=5_000),\n    )\n\n\n@given(\n    shape=nps.array_shapes(min_dims=0, max_side=4)\n    | nps.array_shapes(min_dims=0, min_side=0, max_side=10),\n    allow_newaxis=st.booleans(),\n    allow_ellipsis=st.booleans(),\n    data=st.data(),\n)\ndef test_basic_indices_generate_valid_indexers(\n    shape, allow_newaxis, allow_ellipsis, data\n):\n    min_dims = data.draw(\n        st.integers(0, 5 if allow_newaxis else len(shape)), label=\"min_dims\"\n    )\n    max_dims = data.draw(\n        st.none() | st.integers(min_dims, 32 if allow_newaxis else len(shape)),\n        label=\"max_dims\",\n    )\n    indexer = data.draw(\n        nps.basic_indices(\n            shape,\n            min_dims=min_dims,\n            max_dims=max_dims,\n            allow_ellipsis=allow_ellipsis,\n            allow_newaxis=allow_newaxis,\n        ),\n        label=\"indexer\",\n    )\n\n    # Check that disallowed things are indeed absent\n    if not allow_newaxis:\n        if isinstance(indexer, tuple):\n            assert 0 <= len(indexer) <= len(shape) + int(allow_ellipsis)\n        else:\n            assert 1 <= len(shape) + int(allow_ellipsis)\n        assert np.newaxis not in shape\n    if not allow_ellipsis:\n        assert Ellipsis not in shape\n\n    if 0 in shape:\n        # If there's a zero in the shape, the array will have no elements.\n        array = np.zeros(shape)\n        assert array.size == 0\n    elif np.prod(shape) <= 10**5:\n        # If it's small enough to instantiate, do so with distinct elements.\n        array = np.arange(np.prod(shape)).reshape(shape)\n    else:\n        # We can't cheat on this one, so just try another.\n        assume(False)\n    view = array[indexer]\n    if not np.isscalar(view):\n        assert min_dims <= view.ndim <= (32 if max_dims is None else max_dims)\n        if view.size:\n            assert np.shares_memory(view, array)\n\n\n# addresses https://github.com/HypothesisWorks/hypothesis/issues/2582\n@given(\n    nps.arrays(\n        shape=nps.array_shapes(min_dims=0, min_side=0), dtype=nps.floating_dtypes()\n    )\n)\ndef test_array_owns_memory(x: np.ndarray):\n    assert x.base is None\n    assert x[...].base is x\n\n\n@given(st.data())\ndef test_no_recursion_in_multi_line_reprs_issue_3560(data):\n    data.draw(nps.arrays(shape=(2,), dtype=float).map(lambda x: x))\n    data.draw(\n        nps.arrays(\n            shape=(2,),\n            dtype=float,\n        ).map(lambda x: x)\n    )\n\n\ndef test_infers_elements_and_fill():\n    # Regression test for https://github.com/HypothesisWorks/hypothesis/issues/3900\n    # We only infer a fill strategy if the elements_strategy has reusable values,\n    # and the interaction of two performance fixes broke this.  Oops...\n    s = unwrap_strategies(nps.arrays(dtype=np.uint32, shape=1))\n    assert isinstance(s, nps.ArrayStrategy)\n    assert repr(s.element_strategy) == f\"integers(0, {2**32-1})\"\n    assert repr(s.fill) == f\"integers(0, {2**32-1})\"\n\n    # But we _don't_ infer a fill if the elements strategy is non-reusable\n    elems = st.builds(lambda x: x * 2, st.integers(1, 10)).map(np.uint32)\n    assert not elems.has_reusable_values\n    s = unwrap_strategies(nps.arrays(dtype=np.uint32, shape=1, elements=elems))\n    assert s.fill.is_empty\n\n\n@given(nps.arrays(np.dtype(\"O\"), shape=nps.array_shapes()))\ndef test_object_arrays_are_of_type_object(obj_array):\n    assert obj_array.dtype == np.dtype(\"O\")\n\n\ndef test_class_instances_not_allowed_in_scalar_array():\n    class A:\n        pass\n\n    s = nps.arrays(\n        nps.scalar_dtypes(),\n        shape=nps.array_shapes(),\n        elements=st.just(A()),\n    )\n\n    # can raise ValueError during generation. For example if scalar_dtype is\n    # corresponds to a datetime, numpy will raise \"cannot convert A to a datetime\".\n    with pytest.raises((InvalidArgument, ValueError)):\n        check_can_generate_examples(s)\n\n\ndef test_object_arrays_with_mixed_elements_has_object_dtype():\n    class A:\n        pass\n\n    s = nps.arrays(\n        np.dtype(\"O\"),\n        shape=nps.array_shapes(),\n        elements=st.just(A()) | st.integers(),\n    )\n\n    assert_all_examples(s, lambda arr: arr.dtype == np.dtype(\"O\"))\n    find_any(s, lambda arr: len({type(x) for x in arr.ravel()}) > 1)\n\n\n@given(st.data())\ndef test_object_array_can_hold_arbitrary_class_instances(data):\n    instance = data.draw(st.from_type(type).flatmap(st.from_type))\n    s = nps.arrays(np.dtype(\"O\"), nps.array_shapes(), elements=st.just(instance))\n    arr = data.draw(s)\n\n    assert all(v is instance for v in arr.ravel())\n\n\ndef test_object_array_can_hold_incomparable_elements():\n    class Incomparable:\n        def __eq__(self, other):\n            raise TypeError\n\n    check_can_generate_examples(\n        nps.arrays(\n            np.dtype(\"O\"),\n            nps.array_shapes(),\n            elements=st.just(Incomparable()),\n        )\n    )\n\n\ndef test_can_generate_nested_object_arrays():\n    int_arrays = nps.arrays(np.dtype(\"int\"), nps.array_shapes())\n    s = nps.arrays(np.dtype(\"O\"), nps.array_shapes(), elements=int_arrays)\n    check_can_generate_examples(s)\n"
  },
  {
    "path": "hypothesis-python/tests/numpy/test_gufunc.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport numpy as np\nimport pytest\nfrom pytest import param\n\nfrom hypothesis import HealthCheck, example, given, note, settings, strategies as st\nfrom hypothesis.extra import numpy as nps\nfrom hypothesis.extra._array_helpers import _hypothesis_parse_gufunc_signature\n\nfrom tests.common.debug import find_any, minimal\n\n\ndef use_signature_examples(func):\n    for sig in [\n        \"(),()->()\",\n        \"(i)->()\",\n        \"(i),(i)->()\",\n        \"(m,n),(n,p)->(m,p)\",\n        \"(n),(n,p)->(p)\",\n        \"(m,n),(n)->(m)\",\n        \"(m?,n),(n,p?)->(m?,p?)\",\n        \"(3),(3)->(3)\",\n    ]:\n        func = example(sig)(func)\n    return func\n\n\ndef hy_sig_2_np_sig(hy_sig):\n    return (\n        [tuple(d.strip(\"?\") for d in shape) for shape in hy_sig.input_shapes],\n        [tuple(d.strip(\"?\") for d in hy_sig.result_shape)],\n    )\n\n\ndef test_frozen_dims_signature():\n    _hypothesis_parse_gufunc_signature(\"(2),(3)->(4)\")\n\n\n@st.composite\ndef gufunc_arrays(draw, shape_strat, **kwargs):\n    \"\"\"An example user strategy built on top of mutually_broadcastable_shapes.\"\"\"\n    input_shapes, result_shape = draw(shape_strat)\n    arrays_strat = st.tuples(*(nps.arrays(shape=s, **kwargs) for s in input_shapes))\n    return draw(arrays_strat), result_shape\n\n\n@given(\n    gufunc_arrays(\n        nps.mutually_broadcastable_shapes(signature=np.matmul.signature),\n        dtype=\"float64\",\n        elements=st.floats(0, 1000),\n    )\n)\ndef test_matmul_gufunc_shapes(everything):\n    arrays, result_shape = everything\n    out = np.matmul(*arrays)\n    assert out.shape == result_shape\n\n\n@settings(deadline=None, max_examples=10, suppress_health_check=list(HealthCheck))\n@pytest.mark.parametrize(\n    \"target_sig\",\n    (\"(i),(i)->()\", \"(m,n),(n,p)->(m,p)\", \"(n),(n,p)->(p)\", \"(m,n),(n)->(m)\"),\n)\n@given(data=st.data())\ndef test_matmul_signature_can_exercise_all_combination_of_optional_dims(\n    target_sig, data\n):\n    target_shapes = data.draw(\n        nps.mutually_broadcastable_shapes(signature=target_sig, max_dims=0)\n    )\n    find_any(\n        nps.mutually_broadcastable_shapes(\n            signature=\"(m?,n),(n,p?)->(m?,p?)\", max_dims=0\n        ),\n        lambda shapes: shapes == target_shapes,\n    )\n\n\n@settings(\n    deadline=None, max_examples=50, suppress_health_check=[HealthCheck.nested_given]\n)\n@given(\n    min_dims=st.integers(0, 4),\n    min_side=st.integers(2, 3),\n    n_fixed=st.booleans(),\n    data=st.data(),\n)\ndef test_matmul_sig_shrinks_as_documented(min_dims, min_side, n_fixed, data):\n    sig = \"(m?,n),(n,p?)->(m?,p?)\"\n    if n_fixed:\n        n_value = data.draw(st.integers(0, 4))\n        sig = sig.replace(\"n\", str(n_value))\n    else:\n        n_value = min_side\n\n    note(f\"signature: {sig}\")\n    max_dims = data.draw(st.none() | st.integers(min_dims, 4), label=\"max_dims\")\n    max_side = data.draw(st.none() | st.integers(min_side, 6), label=\"max_side\")\n\n    smallest_shapes, result = minimal(\n        nps.mutually_broadcastable_shapes(\n            signature=sig,\n            min_side=min_side,\n            max_side=max_side,\n            min_dims=min_dims,\n            max_dims=max_dims,\n        )\n    )\n    note(f\"(smallest_shapes, result): {(smallest_shapes, result)}\")\n\n    # if min_dims >= 1 then core dims are never excluded\n    # otherwise, should shrink towards excluding all optional dims\n    expected_input_0 = (\n        (n_value,) if min_dims == 0 else (min_side,) * min_dims + (min_side, n_value)\n    )\n    assert expected_input_0 == smallest_shapes[0]\n\n    expected_input_1 = (\n        (n_value,) if min_dims == 0 else (min_side,) * min_dims + (n_value, min_side)\n    )\n    assert expected_input_1 == smallest_shapes[1]\n\n\ndef gufunc_sig_to_einsum_sig(gufunc_sig):\n    \"\"\"E.g. (i,j),(j,k)->(i,k) becomes ...ij,...jk->...ik\"\"\"\n\n    def einlabels(labels):\n        assert \"x\" not in labels, \"we reserve x for fixed-dimensions\"\n        return \"...\" + \"\".join(i if not i.isdigit() else \"x\" for i in labels)\n\n    gufunc_sig = _hypothesis_parse_gufunc_signature(gufunc_sig)\n    input_sig = \",\".join(map(einlabels, gufunc_sig.input_shapes))\n    return input_sig + \"->\" + einlabels(gufunc_sig.result_shape)\n\n\n@pytest.mark.parametrize(\n    \"gufunc_sig\",\n    [\n        param(\"()->()\", id=\"unary sum\"),\n        param(\"(),()->()\", id=\"binary sum\"),\n        param(\"(),(),()->()\", id=\"trinary sum\"),\n        param(\"(i)->()\", id=\"sum1d\"),\n        param(\"(i,j)->(j)\", id=\"sum rows\"),\n        param(\"(i),(i)->()\", id=\"inner1d\"),\n        param(\"(i),(i),(i)->()\", id=\"trinary inner1d\"),\n        param(\"(m,n),(n,p)->(m,p)\", id=\"matmat\"),\n        param(\"(n),(n,p)->(p)\", id=\"vecmat\"),\n        param(\"(i,t),(j,t)->(i,j)\", id=\"outer-inner\"),\n        param(\"(3),(3)->(3)\", id=\"cross1d\"),\n        param(\"(i,j)->(j,i)\", id=\"transpose\"),\n        param(\"(i),(j)->(i,j)\", id=\"outer\"),\n        param(\"(i,3),(3,k)->(3,i,k)\", id=\"fixed dim outer product\"),\n        param(\"(i),(j),(k)->(i,j,k)\", id=\"trinary outer\"),\n        param(\"(i,i)->(i)\", id=\"trace\"),\n        param(\"(j,i,i,j)->(i,j)\", id=\"bigger trace\"),\n        param(\"(k),(j,i,k,i,j),(j,i)->(i,j)\", id=\"trace product\"),\n    ],\n)\n@given(data=st.data())\ndef test_einsum_gufunc_shapes(gufunc_sig, data):\n    arrays, result_shape = data.draw(\n        gufunc_arrays(\n            nps.mutually_broadcastable_shapes(signature=gufunc_sig),\n            dtype=\"float64\",\n            elements=st.floats(0, 1000),\n        ),\n        label=\"arrays, result_shape\",\n    )\n    out = np.einsum(gufunc_sig_to_einsum_sig(gufunc_sig), *arrays)\n    assert out.shape == result_shape\n"
  },
  {
    "path": "hypothesis-python/tests/numpy/test_import.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nSHOULD_NOT_IMPORT_NUMPY = \"\"\"\nimport sys\nfrom hypothesis import given, strategies as st\n\n@given(st.integers() | st.floats() | st.sampled_from([\"a\", \"b\"]))\ndef test_no_numpy_import(x):\n    assert \"numpy\" not in sys.modules\n\"\"\"\n\n\ndef test_hypothesis_is_not_the_first_to_import_numpy(testdir):\n    # We only import numpy if the user did so first.\n    result = testdir.runpytest(testdir.makepyfile(SHOULD_NOT_IMPORT_NUMPY))\n    result.assert_outcomes(passed=1, failed=0)\n\n\n# We check the wildcard import works on the module level because that's the only\n# place Python actually allows us to use them.\ntry:\n    from hypothesis.extra.numpy import *  # noqa: F403\n\n    star_import_works = True\nexcept AttributeError:\n    star_import_works = False\n\n\ndef test_wildcard_import():\n    assert star_import_works\n"
  },
  {
    "path": "hypothesis-python/tests/numpy/test_narrow_floats.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport numpy as np\nimport pytest\n\nfrom hypothesis import given\nfrom hypothesis.extra.numpy import arrays, from_dtype, integer_dtypes\nfrom hypothesis.strategies import data, floats, integers\n\n\n@pytest.mark.parametrize(\"dtype\", [np.float16, np.float32, np.float64])\n@pytest.mark.parametrize(\"low\", [-2.0, -1.0, 0.0, 1.0])\n@given(data())\ndef test_bad_float_exclude_min_in_array(dtype, low, data):\n    elements = floats(\n        low, low + 1, exclude_min=True, width=np.dtype(dtype).itemsize * 8\n    )\n    x = data.draw(arrays(dtype, shape=(1,), elements=elements), label=\"x\")\n    assert np.all(low < x)\n\n\n@given(floats(width=32))\ndef test_float32_exactly_representable(x):\n    clipped = np.dtype(\"float32\").type(x)\n    if np.isnan(x):\n        assert np.isnan(clipped)\n    else:\n        assert x == float(clipped)\n\n\n@given(floats(width=16))\ndef test_float16_exactly_representable(x):\n    clipped = np.dtype(\"float16\").type(x)\n    if np.isnan(x):\n        assert np.isnan(clipped)\n    else:\n        assert x == float(clipped)\n\n\n@given(data=data(), dtype=integer_dtypes())\ndef test_floor_ceil_lossless(data, dtype):\n    # Regression test for issue #1667; ceil converting numpy integers\n    # to float and back to int with loss of exact value.\n    x = data.draw(from_dtype(dtype))\n    assert data.draw(integers(x, x)) == x\n"
  },
  {
    "path": "hypothesis-python/tests/numpy/test_randomness.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport numpy as np\n\nfrom hypothesis import given\nfrom hypothesis.strategies import none\n\n\ndef test_numpy_prng_is_seeded():\n    first = []\n    prng_state = np.random.get_state()\n\n    @given(none())\n    def inner(_):\n        val = np.random.bytes(10)\n        if not first:\n            first.append(val)\n        assert val == first[0], \"Numpy random module should be reproducible\"\n\n    inner()\n\n    np.testing.assert_array_equal(\n        np.random.get_state()[1], prng_state[1], \"State was not restored.\"\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/numpy/test_sampled_from.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra import numpy as npst\nfrom hypothesis.strategies import data, sampled_from\n\nfrom tests.common.utils import fails_with\n\n\n@given(\n    data(), npst.arrays(dtype=npst.scalar_dtypes(), shape=npst.array_shapes(max_dims=1))\n)\ndef test_can_sample_1D_numpy_array_without_warning(data, arr):\n    data.draw(sampled_from(arr))\n\n\n@fails_with(InvalidArgument)\n@given(\n    data(),\n    npst.arrays(\n        dtype=npst.scalar_dtypes(), shape=npst.array_shapes(min_dims=2, max_dims=5)\n    ),\n)\ndef test_sampling_multi_dimensional_arrays_is_deprecated(data, arr):\n    data.draw(sampled_from(arr))\n"
  },
  {
    "path": "hypothesis-python/tests/pandas/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/pandas/helpers.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport numpy as np\n\nPANDAS_TIME_DTYPES = tuple(map(np.dtype, [\"<M8[ns]\", \"<m8[ns]\", \">M8[ns]\", \">m8[ns]\"]))\n\n\ndef supported_by_pandas(dtype):\n    \"\"\"Checks whether the dtype is one that can be correctly handled by\n    Pandas.\"\"\"\n    # Pandas does not support non-native byte orders and things go amusingly\n    # wrong in weird places if you try to use them. See\n    # https://pandas.pydata.org/pandas-docs/stable/gotchas.html#byte-ordering-issues\n    if dtype.byteorder not in (\"|\", \"=\"):\n        return False\n\n    # Pandas only supports a limited range of timedelta and datetime dtypes\n    # compared to the full range that numpy supports and will convert\n    # everything to those types (possibly increasing precision in the course of\n    # doing so, which can cause problems if this results in something which\n    # does not fit into the desired word type. As a result we want to filter\n    # out any timedelta or datetime dtypes that are not of the desired types.\n    if dtype.kind in (\"m\", \"M\"):\n        return dtype in PANDAS_TIME_DTYPES\n    return True\n"
  },
  {
    "path": "hypothesis-python/tests/pandas/test_argument_validation.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\nfrom datetime import datetime, timedelta\n\nimport pandas as pd\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra import pandas as pdst\nfrom hypothesis.extra.pandas.impl import IntegerDtype\n\nfrom tests.common.arguments import argument_validation_test, e\nfrom tests.common.debug import check_can_generate_examples, find_any\nfrom tests.common.utils import checks_deprecated_behaviour\n\nBAD_ARGS = [\n    e(pdst.data_frames),\n    e(pdst.data_frames, pdst.columns(1, dtype=\"not a dtype\")),\n    e(pdst.data_frames, pdst.columns(1, elements=\"not a strategy\")),\n    e(pdst.data_frames, pdst.columns([[]])),\n    e(pdst.data_frames, [], index=[]),\n    e(pdst.data_frames, [], rows=st.fixed_dictionaries({\"A\": st.just(1)})),\n    e(pdst.data_frames, pdst.columns(1)),\n    e(pdst.data_frames, pdst.columns(1, dtype=float, fill=1)),\n    e(pdst.data_frames, pdst.columns(1, dtype=float, elements=1)),\n    e(pdst.data_frames, pdst.columns(1, fill=1, dtype=float)),\n    e(pdst.data_frames, pdst.columns([\"A\", \"A\"], dtype=float)),\n    pytest.param(\n        *e(pdst.data_frames, pdst.columns(1, elements=st.none(), dtype=int)),\n        marks=pytest.mark.skipif(IntegerDtype, reason=\"works with integer NA\"),\n    ),\n    e(pdst.data_frames, pdst.columns(1, elements=st.text(), dtype=int)),\n    e(pdst.data_frames, 1),\n    e(pdst.data_frames, [1]),\n    e(pdst.data_frames, pdst.columns(1, dtype=\"category\")),\n    e(\n        pdst.data_frames,\n        pdst.columns([\"A\"], dtype=bool),\n        rows=st.tuples(st.booleans(), st.booleans()),\n    ),\n    e(\n        pdst.data_frames,\n        pdst.columns(1, elements=st.booleans()),\n        rows=st.tuples(st.booleans()),\n    ),\n    e(pdst.data_frames, rows=st.integers(), index=pdst.range_indexes(0, 0)),\n    e(pdst.data_frames, rows=st.integers(), index=pdst.range_indexes(1, 1)),\n    e(pdst.data_frames, pdst.columns(1, dtype=int), rows=st.integers()),\n    e(\n        pdst.data_frames,\n        columns=pdst.columns([\"a\", \"b\"], dtype=str, elements=st.text()),\n        rows=st.just({\"a\": \"x\"}),\n        index=pdst.indexes(dtype=int, min_size=1),\n    ),\n    e(\n        pdst.data_frames,\n        columns=pdst.columns([\"a\", \"b\"], dtype=str, elements=st.text()),\n        rows=st.just([\"x\"]),\n        index=pdst.indexes(dtype=int, min_size=1),\n    ),\n    e(pdst.indexes),\n    e(pdst.indexes, dtype=\"category\"),\n    e(pdst.indexes, dtype=\"not a dtype\"),\n    e(pdst.indexes, elements=\"not a strategy\"),\n    e(pdst.indexes, elements=st.text(), dtype=float),\n    pytest.param(\n        *e(pdst.indexes, elements=st.none(), dtype=int),\n        marks=pytest.mark.skipif(IntegerDtype, reason=\"works with integer NA\"),\n    ),\n    e(pdst.indexes, elements=st.text(), dtype=int),\n    e(pdst.indexes, elements=st.just(\"9\" * 30), dtype=int),  # OverflowError handling\n    e(pdst.indexes, elements=st.integers(0, 10), dtype=st.sampled_from([int, float])),\n    e(pdst.indexes, dtype=int, max_size=0, min_size=1),\n    e(pdst.indexes, dtype=int, unique=\"true\"),\n    e(pdst.indexes, dtype=int, min_size=\"0\"),\n    e(pdst.indexes, dtype=int, max_size=\"1\"),\n    e(pdst.range_indexes, 1, 0),\n    e(pdst.range_indexes, min_size=\"0\"),\n    e(pdst.range_indexes, max_size=\"1\"),\n    e(pdst.range_indexes, name=\"\"),\n    e(pdst.series),\n    e(pdst.series, dtype=\"not a dtype\"),\n    e(pdst.series, elements=\"not a strategy\"),\n    pytest.param(\n        *e(pdst.series, elements=st.none(), dtype=int),\n        marks=pytest.mark.skipif(IntegerDtype, reason=\"works with integer NA\"),\n    ),\n    e(pdst.series, elements=st.text(), dtype=int),\n    e(pdst.series, dtype=\"category\"),\n    e(pdst.series, index=\"not a strategy\"),\n]\n\n\ntest_raise_invalid_argument = argument_validation_test(BAD_ARGS)\n\nlo, hi = pd.Timestamp(2017, 1, 1), pd.Timestamp(2084, 12, 21)\n\n\n@given(st.datetimes(min_value=lo, max_value=hi))\ndef test_timestamp_as_datetime_bounds(dt):\n    # Would have caught https://github.com/HypothesisWorks/hypothesis/issues/2406\n    assert isinstance(dt, datetime)\n    assert lo <= dt <= hi\n    assert not isinstance(dt, pd.Timestamp)\n\n\n@checks_deprecated_behaviour\ndef test_confusing_object_dtype_aliases():\n    check_can_generate_examples(\n        pdst.series(elements=st.tuples(st.integers()), dtype=tuple)\n    )\n\n\n@pytest.mark.skipif(\n    not IntegerDtype, reason=\"Nullable types not available in this version of Pandas\"\n)\ndef test_pandas_nullable_types_class():\n    st = pdst.series(dtype=pd.core.arrays.integer.Int8Dtype)\n    with pytest.raises(\n        InvalidArgument, match=\"Otherwise it would be treated as dtype=object\"\n    ):\n        find_any(st, lambda s: s.isna().any())\n\n\n@pytest.mark.parametrize(\n    \"dtype_,expected_unit\",\n    [\n        (datetime, \"datetime64[ns]\"),\n        (pd.Timestamp, \"datetime64[ns]\"),\n        (timedelta, \"timedelta64[ns]\"),\n        (pd.Timedelta, \"timedelta64[ns]\"),\n    ],\n)\ndef test_invalid_datetime_or_timedelta_dtype_raises_error(dtype_, expected_unit):\n    with pytest.raises(InvalidArgument, match=re.escape(expected_unit)):\n        check_can_generate_examples(pdst.series(dtype=dtype_))\n"
  },
  {
    "path": "hypothesis-python/tests/pandas/test_data_frame.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport numpy as np\nimport pandas as pd\nimport pytest\n\nfrom hypothesis import HealthCheck, given, reject, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra import numpy as npst, pandas as pdst\nfrom hypothesis.extra.pandas.impl import IntegerDtype\n\nfrom tests.common.debug import (\n    assert_all_examples,\n    check_can_generate_examples,\n    find_any,\n)\nfrom tests.pandas.helpers import supported_by_pandas\n\n\n@given(pdst.data_frames([pdst.column(\"a\", dtype=int), pdst.column(\"b\", dtype=float)]))\ndef test_can_have_columns_of_distinct_types(df):\n    assert df[\"a\"].dtype == np.dtype(int)\n    assert df[\"b\"].dtype == np.dtype(float)\n\n\n@given(\n    pdst.data_frames(\n        [pdst.column(dtype=int)], index=pdst.range_indexes(min_size=1, max_size=5)\n    )\n)\ndef test_respects_size_bounds(df):\n    assert 1 <= len(df) <= 5\n\n\n@given(pdst.data_frames(pdst.columns([\"A\", \"B\"], dtype=float)))\ndef test_can_specify_just_column_names(df):\n    df[\"A\"]\n    df[\"B\"]\n\n\n@given(pdst.data_frames(pdst.columns(2, dtype=float)))\ndef test_can_specify_just_column_count(df):\n    df[0]\n    df[1]\n\n\n@given(\n    pdst.data_frames(\n        rows=st.fixed_dictionaries({\"A\": st.integers(1, 10), \"B\": st.floats()})\n    )\n)\ndef test_gets_the_correct_data_shape_for_just_rows(table):\n    assert table[\"A\"].dtype == np.dtype(\"int64\")\n    assert table[\"B\"].dtype == np.dtype(float)\n\n\n@given(\n    pdst.data_frames(\n        columns=pdst.columns([\"A\", \"B\"], dtype=int),\n        rows=st.lists(st.integers(0, 1000), min_size=2, max_size=2).map(sorted),\n    )\n)\ndef test_can_specify_both_rows_and_columns_list(d):\n    assert d[\"A\"].dtype == np.dtype(int)\n    assert d[\"B\"].dtype == np.dtype(int)\n    for _, r in d.iterrows():\n        assert r[\"A\"] <= r[\"B\"]\n\n\n@given(\n    pdst.data_frames(\n        columns=pdst.columns([\"A\", \"B\"], dtype=int),\n        rows=st.lists(st.integers(0, 1000), min_size=2, max_size=2)\n        .map(sorted)\n        .map(tuple),\n    )\n)\ndef test_can_specify_both_rows_and_columns_tuple(d):\n    assert d[\"A\"].dtype == np.dtype(int)\n    assert d[\"B\"].dtype == np.dtype(int)\n    for _, r in d.iterrows():\n        assert r[\"A\"] <= r[\"B\"]\n\n\n@given(\n    pdst.data_frames(\n        columns=pdst.columns([\"A\", \"B\"], dtype=int),\n        rows=st.lists(st.integers(0, 1000), min_size=2, max_size=2).map(\n            lambda x: {\"A\": min(x), \"B\": max(x)}\n        ),\n    )\n)\ndef test_can_specify_both_rows_and_columns_dict(d):\n    assert d[\"A\"].dtype == np.dtype(int)\n    assert d[\"B\"].dtype == np.dtype(int)\n    for _, r in d.iterrows():\n        assert r[\"A\"] <= r[\"B\"]\n\n\n@given(\n    pdst.data_frames(\n        [\n            pdst.column(\n                \"A\",\n                fill=st.just(np.nan),\n                dtype=float,\n                elements=st.floats(allow_nan=False),\n            )\n        ],\n        rows=st.builds(dict),\n    )\n)\ndef test_can_fill_in_missing_elements_from_dict(df):\n    assert np.isnan(df[\"A\"]).all()\n\n\n@st.composite\ndef column_strategy(draw):\n    name = draw(st.none() | st.text())\n    dtype = draw(npst.scalar_dtypes().filter(supported_by_pandas))\n    pass_dtype = not draw(st.booleans())\n    if pass_dtype:\n        pass_elements = not draw(st.booleans())\n    else:\n        pass_elements = True\n    if pass_elements:\n        elements = npst.from_dtype(dtype)\n    else:\n        elements = None\n\n    unique = draw(st.booleans())\n    fill = st.nothing() if draw(st.booleans()) else None\n\n    return pdst.column(\n        name=name, dtype=dtype, unique=unique, fill=fill, elements=elements\n    )\n\n\n@given(pdst.data_frames(pdst.columns(1, dtype=np.dtype(\"M8[ns]\"))))\ndef test_data_frames_with_timestamp_columns(df):\n    pass\n\n\n@given(\n    pdst.data_frames(\n        pdst.columns([\"A\"], dtype=float, fill=st.just(np.nan), unique=True)\n    )\n)\ndef test_unique_column_with_fill(df):\n    assert len(set(df[\"A\"])) == len(df[\"A\"])\n\n\n@settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.filter_too_much])\n@given(st.data())\ndef test_arbitrary_data_frames(data):\n    columns = data.draw(\n        st.lists(\n            column_strategy(),\n            unique_by=lambda c: c.name if c.name is not None else np.nan,\n        )\n    )\n\n    try:\n        # Use raw data to work around pandas bug in repr. See\n        # https://github.com/pandas-dev/pandas/issues/27484\n        df = data.conjecture_data.draw(pdst.data_frames(columns))\n    except Exception as e:\n        if type(e).__name__ == \"OutOfBoundsDatetime\":\n            # See https://github.com/HypothesisWorks/hypothesis-python/pull/826\n            reject()\n        else:\n            raise\n    data_frame_columns = list(df)\n\n    assert len(data_frame_columns) == len(columns)\n\n    for i, (c, n) in enumerate(zip(columns, df, strict=True)):\n        if c.name is None:\n            assert n == i\n        else:\n            assert c.name == n\n\n    for i, c in enumerate(columns):\n        column_name = data_frame_columns[i]\n        values = df[column_name]\n        if c.unique:\n            # NA values should always be treated as unique to each other, so we\n            # just ignore them here. Note NA values in the ecosystem can have\n            # different identity behaviours, e.g.\n            #\n            #     >>> set([float(\"nan\"), float(\"nan\")])\n            #     {nan, nan}\n            #     >>> set([pd.NaT, pd.NaT])\n            #     {NaT}\n            #\n            non_na_values = values.dropna()\n            assert len(set(non_na_values)) == len(non_na_values)\n\n\n@given(\n    pdst.data_frames(\n        pdst.columns([\"A\"], unique=True, dtype=int), rows=st.tuples(st.integers(0, 10))\n    )\n)\ndef test_can_specify_unique_with_rows(df):\n    column = df[\"A\"]\n    assert len(set(column)) == len(column)\n\n\ndef test_uniqueness_does_not_affect_other_rows_1():\n    data_frames = pdst.data_frames(\n        [\n            pdst.column(\"A\", dtype=int, unique=True),\n            pdst.column(\"B\", dtype=int, unique=False),\n        ],\n        rows=st.tuples(st.integers(0, 10), st.integers(0, 10)),\n        index=pdst.range_indexes(2, 2),\n    )\n    find_any(data_frames, lambda x: x[\"B\"][0] == x[\"B\"][1])\n\n\ndef test_uniqueness_does_not_affect_other_rows_2():\n    data_frames = pdst.data_frames(\n        [\n            pdst.column(\"A\", dtype=bool, unique=False),\n            pdst.column(\"B\", dtype=int, unique=True),\n        ],\n        rows=st.tuples(st.booleans(), st.integers(0, 10)),\n        index=pdst.range_indexes(2, 2),\n    )\n    find_any(data_frames, lambda x: x[\"A\"][0] == x[\"A\"][1])\n\n\n@given(\n    pdst.data_frames(pdst.columns([\"A\"], dtype=int, fill=st.just(7)), rows=st.tuples())\n)\ndef test_will_fill_missing_columns_in_tuple_row(df):\n    for d in df[\"A\"]:\n        assert d == 7\n\n\n@settings(suppress_health_check=[HealthCheck.filter_too_much, HealthCheck.too_slow])\n@given(\n    pdst.data_frames(\n        index=pdst.range_indexes(10, 10),\n        columns=[pdst.column(elements=st.integers(0, 9), fill=None, unique=True)],\n    )\n)\ndef test_can_generate_unique_columns(df):\n    assert set(df[0]) == set(range(10))\n\n\n@pytest.mark.skip(reason=\"Just works on Pandas 1.4, though the changelog is silent\")\n@pytest.mark.parametrize(\"dtype\", [None, object])\ndef test_expected_failure_from_omitted_object_dtype(dtype):\n    # See https://github.com/HypothesisWorks/hypothesis/issues/3133\n    col = pdst.column(elements=st.sets(st.text(), min_size=1), dtype=dtype)\n\n    @given(pdst.data_frames(columns=[col]))\n    def works_with_object_dtype(df):\n        pass\n\n    if dtype is object:\n        works_with_object_dtype()\n    else:\n        assert dtype is None\n        with pytest.raises(ValueError, match=\"Maybe passing dtype=object would help\"):\n            works_with_object_dtype()\n\n\n@pytest.mark.skipif(\n    not IntegerDtype, reason=\"Nullable types not available in this version of Pandas\"\n)\ndef test_pandas_nullable_types():\n    st = pdst.data_frames(pdst.columns(2, dtype=pd.core.arrays.integer.Int8Dtype()))\n    df = find_any(st, lambda s: s.isna().any().any())\n    for s in df.columns:\n        assert type(df[s].dtype) == pd.core.arrays.integer.Int8Dtype\n\n\n@given(pdst.data_frames(columns=[pdst.column(\"col\", dtype=object)]))\ndef test_object_columns_are_of_type_object(df):\n    assert df[\"col\"].dtype == np.dtype(\"O\")\n\n\ndef test_class_instances_not_allowed_in_scalar_columns():\n    class A:\n        pass\n\n    s = pdst.data_frames(\n        columns=[\n            pdst.column(\n                \"col\",\n                elements=st.just(A()),\n                dtype=npst.scalar_dtypes(),\n            )\n        ]\n    )\n\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(s)\n\n\ndef test_can_generate_object_arrays_with_mixed_dtype_elements():\n    class A:\n        pass\n\n    s = pdst.data_frames(\n        columns=[pdst.column(\"col\", st.just(A()) | st.integers(), dtype=object)],\n        index=pdst.range_indexes(1),\n    )\n    assert_all_examples(s, lambda df: df[\"col\"].dtype == np.dtype(\"O\"))\n    find_any(s, lambda df: len({type(x) for x in df[\"col\"].values}) > 1)\n\n\n@given(st.data())\n@pytest.mark.xfail(\n    strict=False,\n    reason=\"not actually true due to pandas conversion. see \"\n    \"https://github.com/HypothesisWorks/hypothesis/pull/4444#issuecomment-3413951478\",\n)\ndef test_object_dataframe_can_hold_arbitrary_class_instances(data):\n    instance = data.draw(st.from_type(type).flatmap(st.from_type))\n    s = pdst.data_frames(\n        columns=[pdst.column(\"col\", elements=st.just(instance), dtype=object)]\n    )\n    df = data.draw(s)\n\n    assert all(v is instance for v in df[\"col\"].values)\n"
  },
  {
    "path": "hypothesis-python/tests/pandas/test_indexes.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport sys\n\nimport numpy as np\nimport pandas\nimport pytest\n\nfrom hypothesis import HealthCheck, given, reject, settings, strategies as st\nfrom hypothesis.errors import Unsatisfiable\nfrom hypothesis.extra import numpy as npst, pandas as pdst\n\nfrom tests.common.debug import check_can_generate_examples\nfrom tests.pandas.helpers import supported_by_pandas\n\n\n# https://pandas.pydata.org/docs/whatsnew/v2.0.0.html#index-can-now-hold-numpy-numeric-dtypes\n@given(pdst.indexes(dtype=int, max_size=0))\ndef test_gets_right_dtype_for_empty_indices(ix):\n    is_32bit = sys.maxsize == 2**31 - 1\n    pandas2 = pandas.__version__.startswith(\"2.\")\n    numpy1 = np.__version__.startswith(\"1.\")\n    windows = sys.platform == \"win32\"  # including 64-bit windows, confusingly\n    if pandas2 and (is_32bit or (windows and numpy1)):\n        # No, I don't know what this is int32 on 64-bit windows until Numpy 2.0\n        assert ix.dtype == np.dtype(\"int32\")\n    else:\n        assert ix.dtype == np.dtype(\"int64\")\n\n\n@given(pdst.indexes(elements=st.integers(0, sys.maxsize), max_size=0))\ndef test_gets_right_dtype_for_empty_indices_with_elements(ix):\n    assert ix.dtype == np.dtype(\"int64\")\n\n\ndef test_does_not_generate_impossible_conditions():\n    with pytest.raises(Unsatisfiable):\n        check_can_generate_examples(pdst.indexes(min_size=3, max_size=3, dtype=bool))\n\n\n@given(pdst.indexes(dtype=bool, unique=True))\ndef test_unique_indexes_of_small_values(ix):\n    assert len(ix) <= 2\n    assert len(set(ix)) == len(ix)\n\n\n@given(pdst.indexes(dtype=bool, min_size=2, unique=True))\ndef test_unique_indexes_of_many_small_values(ix):\n    assert len(ix) == 2\n    assert len(set(ix)) == len(ix)\n\n\n@given(pdst.indexes(dtype=\"int8\", name=st.just(\"test_name\")))\ndef test_name_passed_on_indexes(s):\n    assert s.name == \"test_name\"\n\n\n# Sizes that fit into an int64 without overflow\nrange_sizes = st.integers(0, 2**63 - 1)\n\n\n@given(range_sizes, range_sizes | st.none(), st.data())\ndef test_arbitrary_range_index(i, j, data):\n    if j is not None:\n        i, j = sorted((i, j))\n    data.draw(pdst.range_indexes(i, j))\n\n\n@given(pdst.range_indexes(name=st.just(\"test_name\")))\ndef test_name_passed_on_range_indexes(s):\n    assert s.name == \"test_name\"\n\n\n@given(pdst.range_indexes())\ndef test_basic_range_indexes(ix):\n    assert isinstance(ix, pandas.RangeIndex)\n\n\n@settings(suppress_health_check=[HealthCheck.too_slow])\n@given(st.data())\ndef test_generate_arbitrary_indices(data):\n    min_size = data.draw(st.integers(0, 10), \"min_size\")\n    max_size = data.draw(st.none() | st.integers(min_size, min_size + 10), \"max_size\")\n    unique = data.draw(st.booleans(), \"unique\")\n    dtype = data.draw(\n        st.one_of(\n            npst.boolean_dtypes(),\n            npst.integer_dtypes(endianness=\"=\"),\n            npst.floating_dtypes(endianness=\"=\", sizes=(32, 64)),\n            npst.datetime64_dtypes(endianness=\"=\"),\n            npst.timedelta64_dtypes(endianness=\"=\"),\n        ).filter(supported_by_pandas),\n        \"dtype\",\n    )\n    pass_elements = data.draw(st.booleans(), \"pass_elements\")\n\n    converted_dtype = pandas.Index([], dtype=dtype).dtype\n\n    try:\n        inferred_dtype = pandas.Index([data.draw(npst.from_dtype(dtype))]).dtype\n\n        if pass_elements:\n            elements = npst.from_dtype(dtype)\n            dtype = None\n        else:\n            elements = None\n\n        index = data.draw(\n            pdst.indexes(\n                elements=elements,\n                dtype=dtype,\n                min_size=min_size,\n                max_size=max_size,\n                unique=unique,\n            )\n        )\n\n    except Exception as e:\n        if type(e).__name__ == \"OutOfBoundsDatetime\":\n            # See https://github.com/HypothesisWorks/hypothesis-python/pull/826\n            reject()\n        else:\n            raise\n    if dtype is None:\n        assert index.dtype == inferred_dtype\n    else:\n        assert index.dtype == converted_dtype\n\n    if unique:\n        assert len(set(index.values)) == len(index)\n"
  },
  {
    "path": "hypothesis-python/tests/pandas/test_series.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport numpy as np\nimport pandas as pd\nimport pytest\n\nfrom hypothesis import given, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra import numpy as nps, pandas as pdst\nfrom hypothesis.extra.pandas.impl import IntegerDtype\n\nfrom tests.common.debug import (\n    assert_all_examples,\n    assert_no_examples,\n    check_can_generate_examples,\n    find_any,\n)\nfrom tests.pandas.helpers import supported_by_pandas\n\n\n@given(st.data())\ndef test_can_create_a_series_of_any_dtype(data):\n    dtype = data.draw(nps.scalar_dtypes().filter(supported_by_pandas))\n    # Use raw data to work around pandas bug in repr. See\n    # https://github.com/pandas-dev/pandas/issues/27484\n    series = data.conjecture_data.draw(pdst.series(dtype=dtype))\n    assert series.dtype == dtype\n\n\n@given(pdst.series(dtype=object))\ndef test_can_create_a_series_of_object_python_type(series):\n    assert series.dtype == np.dtype(\"O\")\n\n\n@given(\n    pdst.series(\n        elements=nps.arrays(\n            nps.array_dtypes() | nps.scalar_dtypes(),\n            nps.array_shapes(),\n        ),\n        dtype=object,\n    )\n)\n@settings(max_examples=5)\ndef test_object_series_are_of_type_object(series):\n    assert series.dtype == np.dtype(\"O\")\n\n\ndef test_class_instances_not_allowed_in_scalar_series():\n    class A:\n        pass\n\n    with pytest.raises(InvalidArgument):\n        check_can_generate_examples(\n            pdst.series(elements=st.just(A()), dtype=np.dtype(\"int\"))\n        )\n\n\ndef test_object_series_with_mixed_elements_still_has_object_dtype():\n    class A:\n        pass\n\n    s = nps.arrays(\n        np.dtype(\"O\"),\n        shape=nps.array_shapes(),\n        elements=st.just(A()) | st.integers(),\n    )\n\n    assert_all_examples(s, lambda arr: arr.dtype == np.dtype(\"O\"))\n    find_any(s, lambda arr: len({type(x) for x in arr.ravel()}) > 1)\n\n\n@given(st.data())\n@settings(max_examples=10)\ndef test_series_can_hold_arbitrary_class_instances(data):\n    instance = data.draw(st.from_type(type).flatmap(st.from_type))\n    s = pdst.series(elements=st.just(instance), dtype=object)\n    series = data.draw(s)\n\n    assert all(v is instance for v in series.values)\n\n\n@given(pdst.series(dtype=float, index=pdst.range_indexes(min_size=2, max_size=5)))\ndef test_series_respects_size_bounds(s):\n    assert 2 <= len(s) <= 5\n\n\ndef test_can_fill_series():\n    nan_backed = pdst.series(elements=st.floats(allow_nan=False), fill=st.just(np.nan))\n    find_any(nan_backed, lambda x: np.isnan(x).any())\n\n\n@given(pdst.series(dtype=int))\ndef test_can_generate_integral_series(s):\n    assert s.dtype == np.dtype(int)\n\n\n@given(pdst.series(elements=st.integers(0, 10)))\ndef test_will_use_dtype_of_elements(s):\n    assert s.dtype == np.dtype(\"int64\")\n\n\n@given(pdst.series(elements=st.floats(allow_nan=False)))\ndef test_will_use_a_provided_elements_strategy(s):\n    assert not np.isnan(s).any()\n\n\n@given(pdst.series(dtype=\"int8\", unique=True))\ndef test_unique_series_are_unique(s):\n    assert len(s) == len(set(s))\n\n\n@given(pdst.series(dtype=\"int8\", name=st.just(\"test_name\")))\ndef test_name_passed_on(s):\n    assert s.name == \"test_name\"\n\n\n@pytest.mark.skipif(\n    not IntegerDtype, reason=\"Nullable types not available in this version of Pandas\"\n)\n@pytest.mark.parametrize(\n    \"dtype\", [\"Int8\", pd.core.arrays.integer.Int8Dtype() if IntegerDtype else None]\n)\ndef test_pandas_nullable_types(dtype):\n    assert_no_examples(\n        pdst.series(dtype=dtype, elements=st.just(0)),\n        lambda s: s.isna().any(),\n    )\n    assert_all_examples(\n        pdst.series(dtype=dtype, elements=st.none()),\n        lambda s: s.isna().all(),\n    )\n    find_any(pdst.series(dtype=dtype), lambda s: not s.isna().any())\n    e = find_any(pdst.series(dtype=dtype), lambda s: s.isna().any())\n    assert type(e.dtype) == pd.core.arrays.integer.Int8Dtype\n"
  },
  {
    "path": "hypothesis-python/tests/patching/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/patching/callables.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"A stable file for which we can write patches.  Don't move stuff around!\"\"\"\n\nfrom pathlib import Path\n\nimport numpy as np\n\nfrom hypothesis import example, given, strategies as st\nfrom hypothesis.extra import numpy as npst\n\nWHERE = Path(__file__).relative_to(Path.cwd())\n\n\n@given(st.integers())\ndef fn(x):\n    \"\"\"A trivial test function.\"\"\"\n\n\nclass Cases:\n    @example(n=0, label=\"whatever\")\n    @given(st.integers(), st.text())\n    def mth(self, n, label):\n        \"\"\"Indented method with existing example decorator.\"\"\"\n\n\n@given(st.integers())\n@example(x=2).via(\"not a literal when repeated \" * 2)\n@example(x=1).via(\"covering example\")\ndef covered(x):\n    \"\"\"A test function with a removable explicit example.\"\"\"\n\n\n@given(npst.arrays(np.int8, 1))\ndef undef_name(array):\n    assert sum(array) < 100\n\n\n# TODO: test function for insertion-order logic, once I get that set up.\n"
  },
  {
    "path": "hypothesis-python/tests/patching/test_patching.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\nfrom datetime import datetime\nfrom pathlib import Path\n\nimport pytest\n\nfrom hypothesis.extra._patching import (\n    FAIL_MSG,\n    HEADER,\n    get_patch_for,\n    indent,\n    make_patch,\n)\nfrom hypothesis.internal.compat import WINDOWS\n\nfrom .callables import WHERE, Cases, covered, fn, undef_name\nfrom .toplevel import WHERE_TOP, fn_top\nfrom tests.common.utils import skipif_threading\n\nSIMPLE = (\n    fn,\n    (\"fn(\\n    x=1,\\n)\", FAIL_MSG),\n    indent('@example(x=1).via(\"discovered failure\")', prefix=\"+\"),\n)\nCASES = (\n    Cases.mth,\n    ('mth(\\n    n=100,\\n    label=\"a long label which forces a newline\",\\n)', FAIL_MSG),\n    indent(\n        '@example(n=100, label=\"a long label which forces a newline\")'\n        '.via(\\n    \"discovered failure\"\\n)',\n        prefix=\"+    \",\n    ),\n)\nTOPLEVEL = (\n    fn_top,\n    (\"fn_top(\\n    x=1,\\n)\", FAIL_MSG),\n    indent('@hypothesis.example(x=1).via(\"discovered failure\")', prefix=\"+\"),\n)\nCOVERING = (\n    covered,\n    (\"covered(\\n    x=0,\\n)\", \"covering example\"),\n    indent('@example(x=1).via(\"covering example\")', prefix=\"-\")\n    + \"\\n\"\n    + indent('@example(x=0).via(\"covering example\")', prefix=\"+\"),\n)\nUNDEF_NAME = (\n    undef_name,\n    (\"undef_name(\\n    array=array([100], dtype=int8),\\n)\", FAIL_MSG),\n    '+@example(array=np.array([100], dtype=np.int8)).via(\"discovered failure\")',\n)\n\n\ndef strip_trailing_whitespace(s):\n    \"\"\"Patches have whitespace-only lines; strip that out.\"\"\"\n    return re.sub(r\" +$\", \"\", s, flags=re.MULTILINE)\n\n\n@pytest.mark.parametrize(\n    \"tst, example, expected\",\n    [\n        pytest.param(*SIMPLE, id=\"simple\"),\n        pytest.param(*CASES, id=\"cases\"),\n    ],\n)\ndef test_adds_simple_patch(tst, example, expected):\n    where, before, after = get_patch_for(tst, [example])\n    assert Path(where) == WHERE\n    added = set(after.splitlines()) - set(before.splitlines())\n    assert added == {line.lstrip(\"+\") for line in expected.splitlines()}\n\n\nSIMPLE_PATCH_BODY = f'''\\\n--- ./{WHERE}\n+++ ./{WHERE}\n@@ -21,6 +21,7 @@\n\n\n @given(st.integers())\n{{0}}\n def fn(x):\n     \"\"\"A trivial test function.\"\"\"\n\n'''\nCASES_PATCH_BODY = f'''\\\n--- ./{WHERE}\n+++ ./{WHERE}\n@@ -28,6 +28,9 @@\n class Cases:\n     @example(n=0, label=\"whatever\")\n     @given(st.integers(), st.text())\n{{0}}\n     def mth(self, n, label):\n         \"\"\"Indented method with existing example decorator.\"\"\"\n\n'''\nTOPLEVEL_PATCH_BODY = f'''\\\n--- ./{WHERE_TOP}\n+++ ./{WHERE_TOP}\n@@ -19,5 +19,6 @@\n\n\n @hypothesis.given(st.integers())\n{{0}}\n def fn_top(x):\n     \"\"\"A trivial test function.\"\"\"\n'''\nCOVERING_PATCH_BODY = f'''\\\n--- ./{WHERE}\n+++ ./{WHERE}\n@@ -34,7 +34,7 @@\n\n @given(st.integers())\n @example(x=2).via(\"not a literal when repeated \" * 2)\n{{0}}\n def covered(x):\n     \"\"\"A test function with a removable explicit example.\"\"\"\n\n'''\n\nUNDEF_NAME_PATCH_BODY = f\"\"\"\\\n--- ./{WHERE}\n+++ ./{WHERE}\n@@ -40,6 +40,7 @@\n\n\n @given(npst.arrays(np.int8, 1))\n{{0}}\n def undef_name(array):\n     assert sum(array) < 100\n\n\"\"\"\n\n\n@pytest.mark.parametrize(\n    \"tst, example, expected, body, remove\",\n    [\n        pytest.param(*SIMPLE, SIMPLE_PATCH_BODY, (), id=\"simple\"),\n        pytest.param(*CASES, CASES_PATCH_BODY, (), id=\"cases\"),\n        pytest.param(*TOPLEVEL, TOPLEVEL_PATCH_BODY, (), id=\"toplevel\"),\n        pytest.param(\n            *COVERING, COVERING_PATCH_BODY, (\"covering example\",), id=\"covering\"\n        ),\n        pytest.param(*UNDEF_NAME, UNDEF_NAME_PATCH_BODY, (), id=\"undef_name\"),\n    ],\n)\ndef test_make_full_patch(tst, example, expected, body, remove):\n    when = datetime.now()\n    msg = \"a message from the test\"\n    author = \"the patch author\"\n    expected = HEADER.format(when=when, msg=msg, author=author) + body.format(expected)\n\n    triple = get_patch_for(tst, [example], strip_via=remove)\n    got = make_patch([triple], when=when, msg=msg, author=author)\n    stripped = strip_trailing_whitespace(got)\n\n    assert stripped.splitlines() == expected.splitlines()\n\n\n@pytest.mark.parametrize(\"n\", [0, 1, 2])\ndef test_invalid_syntax_cases_dropped(n):\n    tst, (ex, via), _expected = SIMPLE\n    example_ls = [(ex.replace(\"x=1\", f\"x={x}\"), via) for x in range(n)]\n    example_ls.insert(-1, (\"fn(\\n    x=<__main__.Cls object at 0x>,\\n)\", FAIL_MSG))\n\n    got = get_patch_for(tst, example_ls)\n    if n == 0:\n        assert got is None, \"no valid examples, and hence no patch\"\n        return\n    where, _, after = got\n\n    assert Path(where) == WHERE\n    assert after.count(\"@example(x=\") == n\n\n\ndef test_no_example_for_data_strategy():\n    assert get_patch_for(fn, [(\"fn(data=data(...))\", \"msg\")]) is None\n    assert get_patch_for(fn, [(\"fn(123, data(...))\", \"msg\")]) is None\n\n    assert get_patch_for(fn, [(\"fn(data='data(...)')\", \"msg\")]) is not None\n    assert get_patch_for(fn, [(\"fn(Foo(data=data(...)))\", \"msg\")]) is not None\n\n\ndef test_patch_order_preserved():\n    (_fname, _before, after) = get_patch_for(\n        fn, [(\"fn(a=1)\", \"msg\"), (\"fn(b=2)\", \"msg\")]\n    )\n    assert after.startswith(\n        '@given(st.integers())\\n@example(a=1).via(\"msg\")\\n@example(b=2).via(\"msg\")'\n    )\n\n    (_fname, _before, after) = get_patch_for(\n        fn, [(\"fn(b=2)\", \"msg\"), (\"fn(a=1)\", \"msg\")]\n    )\n    assert after.startswith(\n        '@given(st.integers())\\n@example(b=2).via(\"msg\")\\n@example(a=1).via(\"msg\")'\n    )\n\n\ndef test_deduplicates_examples():\n    tst, example, expected = SIMPLE\n    where, _, after = get_patch_for(tst, [example, example])\n    assert Path(where) == WHERE\n    assert after.count(expected.lstrip(\"+\")) == 1\n\n\ndef test_irretrievable_callable():\n    # Check that we return None instead of raising an exception\n    old_module = fn.__module__\n    try:\n        fn.__module__ = \"this.does.not.exist\"\n        triple = get_patch_for(fn, [(SIMPLE[1], FAIL_MSG)])\n    finally:\n        fn.__module__ = old_module\n    assert triple is None\n\n\nTESTSCRIPT_DUMPS_PATCH = \"\"\"\nfrom hypothesis import Phase, given, settings, strategies as st\n\n@settings(phases=list(Phase))\n@given(st.integers(0, 10), st.integers(0, 10))\ndef test_failing_pbt(x, y):\n    assert not x\n\"\"\"\nADDED_LINES = \"\"\"\n+@example(\n+    x=1,\n+    y=0,  # or any other generated value\n+).via(\"discovered failure\")\n\"\"\"\n\n\n@skipif_threading\n@pytest.mark.skipif(WINDOWS, reason=\"backslash support is tricky\")\ndef test_pytest_reports_patch_file_location(pytester):\n    script = pytester.makepyfile(TESTSCRIPT_DUMPS_PATCH)\n    result = pytester.runpytest(script)\n    result.assert_outcomes(failed=1)\n\n    fname_pat = r\"\\.hypothesis/patches/\\d{4}-\\d\\d-\\d\\d--[0-9a-f]{8}.patch\"\n    pattern = f\"`git apply ({fname_pat})` to add failing examples to your code\\\\.\"\n    print(f\"{pattern=}\")\n    print(f\"result.stdout=\\n{indent(str(result.stdout), '    ')}\")\n    fname = re.search(pattern, str(result.stdout)).group(1)\n    patch = Path(pytester.path).joinpath(fname).read_text(encoding=\"utf-8\")\n    print(patch)\n    assert ADDED_LINES in patch\n"
  },
  {
    "path": "hypothesis-python/tests/patching/toplevel.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"A stable file for which we can write patches.  Don't move stuff around!\"\"\"\n\nfrom pathlib import Path\n\nimport hypothesis\nimport hypothesis.strategies as st\n\nWHERE_TOP = Path(__file__).relative_to(Path.cwd())\n\n\n@hypothesis.given(st.integers())\ndef fn_top(x):\n    \"\"\"A trivial test function.\"\"\"\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test__pytest.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport subprocess\nimport sys\n\nTESTSUITE = \"\"\"\nfrom hypothesis import given\nfrom hypothesis import strategies as st\nimport _pytest\n\n@given(st.integers())\ndef test_a(n):\n    pass\n\ntest_a()\n\"\"\"\n\n\ndef test_import_just_private_pytest_works(testdir):\n    # importing just _pytest does not import its submodules like _pytest.outcomes.\n    # Ensure we don't rely on this by writing conditional imports like\n    # `if \"_pytest\" in sys.modules: sys.modules[\"_pytest\"].outcomes`.\n    script = testdir.makepyfile(TESTSUITE)\n    result = subprocess.run(\n        [sys.executable, script],\n        # some hypothesis plugins (trio) import pytest, making this test pass\n        # even when hypothesis has a bug. This was the case for my local installation,\n        # and I am including this here on the off chance our CI setup has a similar\n        # install situation. I don't want to wait for another regression to find out\n        # this test doesn't work.\n        env=os.environ | {\"HYPOTHESIS_NO_PLUGINS\": \"1\"},\n    )\n    assert result.returncode == 0\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_capture.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis._settings import _CI_VARS\nfrom hypothesis.internal.compat import WINDOWS, escape_unicode_characters\n\npytest_plugins = \"pytester\"\n\nTESTSUITE = \"\"\"\nfrom hypothesis import given, settings, Verbosity\nfrom hypothesis.strategies import integers\n\n@settings(verbosity=Verbosity.verbose)\n@given(integers())\ndef test_should_be_verbose(x):\n    pass\n\n\"\"\"\n\n\n@pytest.mark.parametrize(\"capture,expected\", [(\"no\", True), (\"fd\", False)])\ndef test_output_without_capture(testdir, capture, expected):\n    script = testdir.makepyfile(TESTSUITE)\n    result = testdir.runpytest(script, \"--verbose\", \"--capture\", capture)\n    out = \"\\n\".join(result.stdout.lines)\n    assert \"test_should_be_verbose\" in out\n    assert (\"Trying example\" in out) == expected\n    assert result.ret == 0\n\n\nUNICODE_EMITTING = \"\"\"\nimport pytest\nfrom hypothesis import given, settings, Verbosity\nfrom hypothesis.strategies import text\nimport sys\n\ndef test_emits_unicode():\n    @settings(verbosity=Verbosity.verbose)\n    @given(text())\n    def test_should_emit_unicode(t):\n        assert all(ord(c) <= 1000 for c in t), ascii(t)\n    with pytest.raises(AssertionError):\n        test_should_emit_unicode()\n\"\"\"\n\n\n@pytest.mark.xfail(\n    WINDOWS,\n    reason=\"Encoding issues in running the subprocess, possibly pytest's fault\",\n    strict=False,  # It's possible, if rare, for this to pass on Windows too.\n)\ndef test_output_emitting_unicode(testdir, monkeypatch):\n    monkeypatch.setenv(\"LC_ALL\", \"C\")\n    monkeypatch.setenv(\"LANG\", \"C\")\n    script = testdir.makepyfile(UNICODE_EMITTING)\n    result = getattr(testdir, \"runpytest_subprocess\", testdir.runpytest)(\n        script, \"--verbose\", \"--capture=no\"\n    )\n    out = \"\\n\".join(result.stdout.lines)\n    assert \"test_emits_unicode\" in out\n    assert chr(1001) in out or escape_unicode_characters(chr(1001)) in out\n    assert result.ret == 0\n\n\ndef get_line_num(token, lines, skip_n=0):\n    skipped = 0\n    for i, line in enumerate(lines):\n        if token in line:\n            if skip_n == skipped:\n                return i\n            else:\n                skipped += 1\n    raise AssertionError(\n        f\"Token {token!r} not found (skipped {skipped} of planned {skip_n} skips)\"\n    )\n\n\nTRACEBACKHIDE_HEALTHCHECK = \"\"\"\nfrom hypothesis import given, settings\nfrom hypothesis.strategies import integers\nimport time\n@given(integers().map(lambda x: time.sleep(0.2)))\ndef test_healthcheck_traceback_is_hidden(x):\n    pass\n\"\"\"\n\n\ndef test_healthcheck_traceback_is_hidden(testdir, monkeypatch):\n    for key in _CI_VARS:\n        monkeypatch.delenv(key, raising=False)\n\n    script = testdir.makepyfile(TRACEBACKHIDE_HEALTHCHECK)\n    lines = testdir.runpytest(script, \"--verbose\").stdout.lines\n    def_token = \"__ test_healthcheck_traceback_is_hidden __\"\n    timeout_token = \": FailedHealthCheck\"\n    def_line = get_line_num(def_token, lines)\n    timeout_line = get_line_num(timeout_token, lines)\n    # 16 on pytest 8.4.0 combined with py3{9, 10} or 3.13 free-threading (but\n    # not with 3.13 normal??)\n    assert timeout_line - def_line in {15, 16}\n\n\nCOMPOSITE_IS_NOT_A_TEST = \"\"\"\nfrom hypothesis.strategies import composite, none\n@composite\ndef test_data_factory(draw):\n    return draw(none())\n\"\"\"\n\n\ndef test_deprecation_of_strategies_as_tests(testdir):\n    script = testdir.makepyfile(COMPOSITE_IS_NOT_A_TEST)\n    testdir.runpytest(script).assert_outcomes(failed=1)\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_checks.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nTEST_DECORATORS_ALONE = \"\"\"\nimport hypothesis\nfrom hypothesis.strategies import composite, none\n\n@composite\ndef test_composite_is_not_a_test(draw):\n    # This strategy will be instantiated, but no draws == no calls.\n    return draw(none())\n\n@hypothesis.seed(0)\ndef test_seed_without_given_fails():\n    pass\n\n@hypothesis.example(x=None)\ndef test_example_without_given_fails():\n    pass\n\n@hypothesis.reproduce_failure(hypothesis.__version__, b\"AA==\")\ndef test_repro_without_given_fails():\n    pass\n\"\"\"\n\n\ndef test_decorators_without_given_should_fail(testdir):\n    script = testdir.makepyfile(TEST_DECORATORS_ALONE)\n    result = testdir.runpytest(script)\n    result.assert_outcomes(failed=4)\n    assert \"pytest_runtest_call\" not in \"\\n\".join(result.outlines)\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_collection_warning.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom tests.common.utils import skipif_threading\n\npytest_plugins = \"pytester\"\n\nINI = \"\"\"\n[pytest]\nnorecursedirs = .svn tmp whatever*\n\"\"\"\n\nTEST_SCRIPT = \"\"\"\ndef test_noop():\n    pass\n\"\"\"\n\n\n@pytest.mark.skipif(int(pytest.__version__.split(\".\")[0]) < 7, reason=\"hook is new\")\n@skipif_threading  # colliding test_bad.py file\ndef test_collection_warning(pytester):\n    pytester.mkdir(\".hypothesis\")\n    pytester.path.joinpath(\"pytest.ini\").write_text(INI, encoding=\"utf-8\")\n    pytester.path.joinpath(\"test_ok.py\").write_text(TEST_SCRIPT, encoding=\"utf-8\")\n    pytester.path.joinpath(\".hypothesis/test_bad.py\").write_text(\n        TEST_SCRIPT.replace(\"pass\", \"raise Exception\"), encoding=\"utf-8\"\n    )\n\n    result = pytester.runpytest_subprocess()\n    result.assert_outcomes(passed=1, warnings=1)\n    assert \"Skipping collection of '.hypothesis'\" in \"\\n\".join(result.outlines)\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_compat.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import given\nfrom hypothesis.strategies import booleans\n\n\n@given(booleans())\n@pytest.mark.parametrize(\"hi\", (1, 2, 3))\ndef test_parametrize_after_given(hi, i):\n    pass\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_constant_collection_timing.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\n\nimport pytest\n\npytest_plugins = \"pytester\"\n\n\nCONFTEST = \"\"\"\nimport time\nimport hypothesis.internal.conjecture.providers as providers\n\n_called = False\n\ndef slow_get_local_constants():\n    global _called\n    if not _called:\n        _called = True\n        time.sleep(0.1)\n    return providers._local_constants\n\nproviders._get_local_constants = slow_get_local_constants\nproviders._sys_modules_len = None\n\"\"\"\n\n\nTESTSUITE = \"\"\"\nfrom hypothesis import given, Phase, settings\nfrom hypothesis.strategies import integers\nfrom hypothesis.internal.conjecture.providers import _get_local_constants\n\ndef test_first():\n    # Force constant collection to happen during this test\n    _get_local_constants()\n\n@given(integers())\n@settings(phases=[Phase.generate], max_examples=1, database=None)\ndef test_second(x):\n    pass\n\"\"\"\n\n\n@pytest.mark.parametrize(\"plugin_disabled\", [False, True])\ndef test_constant_collection_timing(testdir, plugin_disabled):\n    # See https://github.com/HypothesisWorks/hypothesis/issues/4627\n    testdir.makeconftest(CONFTEST)\n    testdir.makepyfile(TESTSUITE)\n\n    args = [\"--durations=0\", \"-vv\"]\n    if plugin_disabled:\n        args += [\"-p\", \"no:hypothesispytest\"]\n\n    result = testdir.runpytest(*args)\n    result.assert_outcomes(passed=2)\n\n    output = \"\\n\".join(result.stdout.lines)\n    match = re.search(r\"([\\d.]+)s call\\s+\\S+::test_first\", output)\n    assert match, f\"Could not find test_first timing in:\\n{output}\"\n    test_first_time = float(match.group(1))\n\n    if plugin_disabled:\n        assert test_first_time >= 0.05, f\"took {test_first_time}s, expected >= 0.05s\"\n    else:\n        assert test_first_time < 0.05, f\"took {test_first_time}s, expected < 0.05s\"\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_doctest.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\npytest_plugins = \"pytester\"\n\nfunc_with_doctest = \"\"\"\ndef hi():\n    '''\n    >>> i = 5\n    >>> i-1\n    4\n    '''\n\"\"\"\n\n\ndef test_can_run_doctests(testdir):\n    script = testdir.makepyfile(func_with_doctest)\n    result = testdir.runpytest(script, \"--doctest-modules\")\n    assert result.ret == 0\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_fixtures.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom unittest.mock import Mock, create_autospec\n\nimport pytest\n\nfrom hypothesis import example, given\nfrom hypothesis.strategies import integers\n\nfrom tests.common.utils import fails, skipif_threading\n\npytest_plugins = \"pytester\"\n\n\n@pytest.fixture(scope=\"session\")\ndef infinity():\n    return float(\"inf\")\n\n\n@pytest.fixture(scope=\"module\")\ndef mock_fixture():\n    return Mock()\n\n\n@pytest.fixture(scope=\"module\")\ndef spec_fixture():\n    class Foo:\n        def __init__(self):\n            pass\n\n        def bar(self):\n            return \"baz\"\n\n    return create_autospec(Foo)\n\n\n@given(integers())\ndef test_can_mix_fixture_and_positional_strategy(infinity, xs):\n    # Hypothesis fills arguments from the right, so if @given() uses\n    # positional arguments then any strategies need to be on the right.\n    assert xs <= infinity\n\n\n@given(xs=integers())\ndef test_can_mix_fixture_and_keyword_strategy(xs, infinity):\n    assert xs <= infinity\n\n\n@example(xs=0)\n@given(xs=integers())\ndef test_can_mix_fixture_example_and_keyword_strategy(xs, infinity):\n    assert xs <= infinity\n\n\n@fails\n@given(integers())\ndef test_can_inject_mock_via_fixture(mock_fixture, xs):\n    \"\"\"A negative test is better for this one - this condition uncovers a bug\n    whereby the mock fixture is executed instead of the test body and always\n    succeeds. If this test fails, then we know we've run the test body instead\n    of the mock.\n    \"\"\"\n    raise AssertionError\n\n\n@given(integers())\ndef test_can_inject_autospecced_mock_via_fixture(spec_fixture, xs):\n    spec_fixture.bar.return_value = float(\"inf\")\n    assert xs <= spec_fixture.bar()\n\n\nTESTSUITE = \"\"\"\nimport pytest\nfrom hypothesis import given, strategies as st\n\n@pytest.fixture(scope=\"function\", autouse=True)\ndef autofix(request):\n    pass\n\n@given(x=st.integers())\ndef test_requests_function_scoped_fixture(capsys, x):\n    pass\n\n@pytest.mark.parametrize(\"percent\", [\"%\", \"%s\"])\n@given(x=st.integers())\ndef test_requests_function_scoped_fixture_percent_parametrized(capsys, x, percent):\n    # See https://github.com/HypothesisWorks/hypothesis/issues/2469\n    pass\n\nclass TestClass:\n    @given(x=st.integers())\n    def test_requests_method_scoped_fixture(capsys, x):\n        pass\n\n@given(x=st.integers())\ndef test_autouse_function_scoped_fixture(x):\n    pass\n\"\"\"\n\n\ndef test_given_plus_function_scoped_non_autouse_fixtures_are_deprecated(testdir):\n    script = testdir.makepyfile(TESTSUITE)\n    testdir.runpytest(script).assert_outcomes(passed=1, failed=4)\n\n\nCONFTEST_SUPPRESS = \"\"\"\nfrom hypothesis import HealthCheck, settings\n\nsettings.register_profile(\n    \"suppress\",\n    suppress_health_check=[HealthCheck.function_scoped_fixture],\n)\n\"\"\"\n\n\n@skipif_threading\ndef test_suppress_fixture_health_check_via_profile(testdir):\n    script = testdir.makepyfile(TESTSUITE)\n    testdir.makeconftest(CONFTEST_SUPPRESS)\n\n    testdir.runpytest(script).assert_outcomes(passed=1, failed=4)\n    testdir.runpytest(script, \"--hypothesis-profile=suppress\").assert_outcomes(passed=5)\n\n\nTESTSCRIPT_SUPPRESS_FIXTURE = \"\"\"\nimport pytest\nfrom hypothesis import HealthCheck, given, settings, strategies as st\n\n@given(x=st.integers())\ndef test_fails_health_check(capsys, x):\n    pass\n\n@settings(suppress_health_check=[HealthCheck.function_scoped_fixture])\n@given(x=st.integers())\ndef test_suppresses_health_check(capsys, x):\n    pass\n\n@given(x=st.integers())\n@settings(suppress_health_check=[HealthCheck.function_scoped_fixture])\ndef test_suppresses_health_check_2(capsys, x):\n    pass\n\"\"\"\n\n\ndef test_suppress_health_check_function_scoped_fixture(testdir):\n    script = testdir.makepyfile(TESTSCRIPT_SUPPRESS_FIXTURE)\n    testdir.runpytest(script).assert_outcomes(passed=2, failed=1)\n\n\nTESTSCRIPT_OVERRIDE_FIXTURE = \"\"\"\nimport pytest\nfrom hypothesis import given, strategies as st\n\n@pytest.fixture(scope=\"function\", name=\"event_loop\")\ndef event_loop_1():\n    return\n\n@pytest.fixture(scope=\"module\", name=\"event_loop\")\ndef event_loop_2():\n    return\n\n@given(x=st.integers())\ndef test_override_fixture(event_loop, x):\n    pass\n\"\"\"\n\n\ndef test_given_plus_overridden_fixture(testdir):\n    script = testdir.makepyfile(TESTSCRIPT_OVERRIDE_FIXTURE)\n    testdir.runpytest(script, \"-Werror\").assert_outcomes(passed=1, failed=0)\n\n\nTESTSCRIPT_FIXTURE_THEN_GIVEN = \"\"\"\nimport pytest\nfrom hypothesis import given, strategies as st\n\n@given(x=st.integers())\n@pytest.fixture()\ndef test(x):\n    pass\n\"\"\"\n\npytest_version = tuple(map(int, pytest.__version__.split(\".\")[:2]))\n\n\ndef assert_outcomes(result, *, errors=0, failed=0):\n    kwargs = {\"errors\" if pytest_version[0] > 5 else \"error\": errors}\n    result.assert_outcomes(failed=failed, **kwargs)\n\n\ndef test_given_fails_if_already_decorated_with_fixture(testdir):\n    script = testdir.makepyfile(TESTSCRIPT_FIXTURE_THEN_GIVEN)\n    result = testdir.runpytest(script)\n    if pytest_version[:2] >= (8, 4):\n        assert_outcomes(result, errors=1)\n    else:\n        assert_outcomes(result, failed=1)\n\n\nTESTSCRIPT_GIVEN_THEN_FIXTURE = \"\"\"\nimport pytest\nfrom hypothesis import given, strategies as st\n\n@pytest.fixture()\n@given(x=st.integers())\ndef test(x):\n    pass\n\"\"\"\n\n\ndef test_fixture_errors_if_already_decorated_with_given(testdir):\n    script = testdir.makepyfile(TESTSCRIPT_GIVEN_THEN_FIXTURE)\n    assert_outcomes(testdir.runpytest(script), errors=1)\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_junit.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport xml.etree.ElementTree as ET\nfrom pathlib import Path\n\npytest_plugins = \"pytester\"\n\n\nTESTSUITE = \"\"\"\nfrom hypothesis import given\nfrom hypothesis.strategies import integers\n\n@given(integers())\ndef test_valid(x):\n    assert x == x\n\n@given(integers())\ndef test_invalid(x):\n    assert x != x\n\"\"\"\n\n\ndef _run_and_get_junit(testdir, *args):\n    script = testdir.makepyfile(TESTSUITE)\n    testdir.runpytest(script, \"--junit-xml=out.xml\", *args)\n    return ET.parse(Path(testdir.tmpdir) / \"out.xml\").getroot()\n\n\ndef _findall_from_root(junit_xml, path):\n    if junit_xml.tag == \"testsuites\":\n        return junit_xml.findall(f\"./testsuite/{path}\")\n    # This case only exists for tests against Pytest before 5.1.0;\n    # see https://github.com/pytest-dev/pytest/commit/a43ba78d3bde\n    return junit_xml.findall(f\"./{path}\")\n\n\ndef suite_properties_ok(junit_xml):\n    # Check whether <properties> is included in <testsuite>.  This is currently not\n    # the case when using pytest-xdist, which is a shame, but we can live with it.\n    testsuite_props = _findall_from_root(junit_xml, \"properties\")\n    return len(testsuite_props) == 1 and {\n        prop.get(\"name\") for prop in testsuite_props[0].findall(\"property\")\n    } == {\n        \"hypothesis-statistics-test_outputs_valid_xunit2.py::test_valid\",\n        \"hypothesis-statistics-test_outputs_valid_xunit2.py::test_invalid\",\n    }\n\n\ndef test_outputs_valid_xunit2(testdir):\n    # The thing we really care about with pytest-xdist + junitxml is that we don't\n    # break xunit2 compatibility by putting <properties> inside <testcase>.\n    junit_xml = _run_and_get_junit(testdir)\n    testcase_props = _findall_from_root(junit_xml, \"testcase/properties\")\n    assert len(testcase_props) == 0\n    # Check whether <properties> is included in <testsuite>\n    assert suite_properties_ok(junit_xml)\n\n\ndef test_outputs_valid_xunit2_with_xdist(testdir):\n    junit_xml = _run_and_get_junit(testdir, \"-n2\")\n    testcase_props = _findall_from_root(junit_xml, \"testcase/properties\")\n    assert len(testcase_props) == 0\n    # If <properties> is included in <testsuite>, this assertion will fail.\n    # That would be a GOOD THING, and we would remove the `not` to prevent regressions.\n    assert not suite_properties_ok(junit_xml)\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_mark.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\npytest_plugins = \"pytester\"\n\n\nTESTSUITE = \"\"\"\nfrom hypothesis import given\nfrom hypothesis.strategies import integers\n\n@given(integers())\ndef test_foo(x):\n    pass\n\ndef test_bar():\n    pass\n\"\"\"\n\n\ndef test_can_select_mark(testdir):\n    script = testdir.makepyfile(TESTSUITE)\n    result = testdir.runpytest(\n        script, \"--verbose\", \"--strict-markers\", \"-m\", \"hypothesis\"\n    )\n    out = \"\\n\".join(result.stdout.lines)\n    assert \"1 passed, 1 deselected\" in out\n\n\nUNITTEST_TESTSUITE = \"\"\"\nfrom hypothesis import given\nfrom hypothesis.strategies import integers\nfrom unittest import TestCase\n\nclass TestStuff(TestCase):\n    @given(integers())\n    def test_foo(self, x):\n        pass\n\n    def test_bar(self):\n        pass\n\"\"\"\n\n\ndef test_can_select_mark_on_unittest(testdir):\n    script = testdir.makepyfile(UNITTEST_TESTSUITE)\n    result = testdir.runpytest(\n        script, \"--verbose\", \"--strict-markers\", \"-m\", \"hypothesis\"\n    )\n    out = \"\\n\".join(result.stdout.lines)\n    assert \"1 passed, 1 deselected\" in out\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_parametrized_db_keys.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import HealthCheck, given, settings, strategies as st\n\nDB_KEY_TESTCASE = \"\"\"\nfrom hypothesis import settings, given\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.strategies import booleans\nimport pytest\n\nDB = InMemoryExampleDatabase()\n\n\n@settings(database=DB)\n@given(booleans())\n@pytest.mark.parametrize(\"hi\", (1, 2, 3))\n@pytest.mark.xfail()\ndef test_dummy_for_parametrized_db_keys(hi, i):\n    assert Fail  # Test *must* fail for it to end up the database anyway\n\n\ndef test_DB_keys_for_parametrized_test():\n    assert len(DB.data) == 3\n\"\"\"\n\n\ndef test_db_keys_for_parametrized_tests_are_unique(testdir):\n    script = testdir.makepyfile(DB_KEY_TESTCASE)\n    testdir.runpytest(script).assert_outcomes(xfailed=3, passed=1)\n\n\n@pytest.fixture(params=[\"a\", \"b\"])\ndef fixt(request):\n    return request.param\n\n\nclass TestNoDifferingExecutorsHealthCheck:\n    # Regression test for https://github.com/HypothesisWorks/hypothesis/issues/3733\n\n    @given(x=st.text())\n    @pytest.mark.parametrize(\"i\", range(2))\n    def test_method(self, x, i):\n        pass\n\n    @settings(suppress_health_check=[HealthCheck.function_scoped_fixture])\n    @given(x=st.text())\n    def test_method_fixture(self, x, fixt):\n        pass\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_profiles.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport importlib\n\nimport pytest\nfrom _hypothesis_pytestplugin import LOAD_PROFILE_OPTION\n\npytest_plugins = \"pytester\"\n\n\nCONFTEST = \"\"\"\nfrom hypothesis._settings import settings\nsettings.register_profile(\"test\", settings(max_examples=1))\n\"\"\"\n\nTESTSUITE = \"\"\"\nfrom hypothesis import given\nfrom hypothesis.strategies import integers\nfrom hypothesis._settings import settings\n\ndef test_this_one_is_ok():\n    assert settings().max_examples == 1\n\"\"\"\n\n\ndef test_does_not_run_reporting_hook_by_default(testdir):\n    script = testdir.makepyfile(TESTSUITE)\n    testdir.makeconftest(CONFTEST)\n    result = testdir.runpytest(script, LOAD_PROFILE_OPTION, \"test\")\n    out = \"\\n\".join(result.stdout.lines)\n    assert \"1 passed\" in out\n    assert \"hypothesis profile\" not in out\n    # importlib.metadata.version respects e.g. local -e installs of hypothesis,\n    # and matches what `pytest` uses more closely than `hypothesis.__version__`\n    # (which is the actually-latest version).\n    assert importlib.metadata.version(\"hypothesis\") in out\n\n\n@pytest.mark.parametrize(\"option\", [\"-v\", \"--hypothesis-verbosity=verbose\"])\ndef test_runs_reporting_hook_in_any_verbose_mode(testdir, option):\n    script = testdir.makepyfile(TESTSUITE)\n    testdir.makeconftest(CONFTEST)\n    result = testdir.runpytest(script, LOAD_PROFILE_OPTION, \"test\", option)\n    out = \"\\n\".join(result.stdout.lines)\n    assert \"1 passed\" in out\n    assert \"max_examples=1\" in out\n    assert \"hypothesis profile\" in out\n    assert importlib.metadata.version(\"hypothesis\") in out\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_pytest_detection.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport subprocess\nimport sys\n\nfrom hypothesis import core\n\n\ndef test_is_running_under_pytest():\n    assert core.running_under_pytest\n\n\nFILE_TO_RUN = \"\"\"\nimport hypothesis.core as core\nassert not core.running_under_pytest\n\"\"\"\n\n\ndef test_is_not_running_under_pytest(tmp_path):\n    pyfile = tmp_path / \"test.py\"\n    pyfile.write_text(FILE_TO_RUN, encoding=\"utf-8\")\n    subprocess.check_call([sys.executable, str(pyfile)])\n\n\nDOES_NOT_IMPORT_HYPOTHESIS = \"\"\"\nimport sys\n\ndef test_pytest_plugin_does_not_import_hypothesis():\n    assert \"hypothesis\" not in sys.modules\n\"\"\"\n\n\ndef test_plugin_does_not_import_pytest(testdir):\n    testdir.makepyfile(DOES_NOT_IMPORT_HYPOTHESIS)\n    testdir.runpytest_subprocess().assert_outcomes(passed=1)\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_reporting.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\npytest_plugins = \"pytester\"\n\n\nTESTSUITE = \"\"\"\nfrom hypothesis import given\nfrom hypothesis.strategies import lists, integers\n\n@given(integers())\ndef test_this_one_is_ok(x):\n    pass\n\n@given(lists(integers()))\ndef test_hi(xs):\n    assert False\n\"\"\"\n\n\ndef test_runs_reporting_hook(testdir):\n    script = testdir.makepyfile(TESTSUITE)\n    result = testdir.runpytest(script, \"--verbose\")\n    out = \"\\n\".join(result.stdout.lines)\n    assert \"test_this_one_is_ok\" in out\n    assert \"Captured stdout call\" not in out\n    assert \"Falsifying example\" in out\n    assert result.ret != 0\n\n\nTEST_EXCEPTIONGROUP = \"\"\"\nfrom hypothesis import given, strategies as st\n\n@given(x=st.booleans())\ndef test_fuzz_sorted(x):\n    raise ValueError if x else TypeError\n\"\"\"\n\n\n@pytest.mark.parametrize(\"tb\", [\"auto\", \"long\", \"short\", \"native\"])\ndef test_no_missing_reports(testdir, tb):\n    script = testdir.makepyfile(TEST_EXCEPTIONGROUP)\n    result = testdir.runpytest(script, f\"--tb={tb}\")\n    out = \"\\n\".join(result.stdout.lines)\n    # If the False case is missing, that means we're not printing exception info.\n    # See https://github.com/HypothesisWorks/hypothesis/issues/3430  With --tb=native,\n    # we should show the full ExceptionGroup with *both* errors.\n    assert \"x=False\" in out\n    assert \"x=True\" in out or tb != \"native\"\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_runs.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given\nfrom hypothesis.strategies import integers\n\nfrom tests.common.utils import fails\n\n\n@given(integers())\ndef test_ints_are_ints(x):\n    pass\n\n\n@fails\n@given(integers())\ndef test_ints_are_floats(x):\n    assert isinstance(x, float)\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_seeding.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\n\nimport pytest\n\nfrom hypothesis._settings import _CI_VARS\n\nfrom tests.common.utils import skipif_threading\n\npytest_plugins = \"pytester\"\n\n\nTEST_SUITE = \"\"\"\nfrom hypothesis import given, settings, assume\nimport hypothesis.strategies as st\n\n\nfirst = None\n\n@settings(database=None)\n@given(st.integers())\ndef test_fails_once(some_int):\n    assume(abs(some_int) > 1000)\n    global first\n    if first is None:\n        first = some_int\n\n    assert some_int != first\n\"\"\"\n\n\nCONTAINS_SEED_INSTRUCTION = re.compile(r\"--hypothesis-seed=\\d+\", re.MULTILINE)\n\n\n@skipif_threading\n@pytest.mark.parametrize(\"seed\", [0, 42, \"foo\"])\ndef test_runs_repeatably_when_seed_is_set(seed, testdir):\n    script = testdir.makepyfile(TEST_SUITE)\n\n    results = [\n        testdir.runpytest(\n            script, \"--verbose\", \"--strict-markers\", f\"--hypothesis-seed={seed}\", \"-rN\"\n        )\n        for _ in range(2)\n    ]\n\n    failure_lines = []\n    for r in results:\n        assert all(\"--hypothesis-seed\" not in l for l in r.stdout.lines)\n        failure_line = [l for l in r.stdout.lines if \"some_int=\" in l]\n        # each iteration should fail\n        assert len(failure_line) == 1\n        failure_lines.append(failure_line[0])\n\n    # all the same failure\n    assert len(set(failure_lines)) == 1\n\n\nHEALTH_CHECK_FAILURE = \"\"\"\nimport os\n\nfrom hypothesis import given, strategies as st, assume, reject\n\nRECORD_EXAMPLES = <file>\n\nif os.path.exists(RECORD_EXAMPLES):\n    target = None\n    with open(RECORD_EXAMPLES, \"r\", encoding=\"utf-8\") as i:\n        seen = set(map(int, i.read().strip().split(\"\\\\n\")))\nelse:\n    target = open(RECORD_EXAMPLES, \"w\", encoding=\"utf-8\")\n\n@given(st.integers())\ndef test_failure(i):\n    if target is None:\n        assume(i not in seen)\n    else:\n        target.write(f\"{i}\\\\n\")\n        reject()\n\"\"\"\n\n\ndef test_repeats_healthcheck_when_following_seed_instruction(\n    testdir, tmp_path, monkeypatch\n):\n    for key in _CI_VARS:\n        monkeypatch.delenv(key, raising=False)\n\n    health_check_test = HEALTH_CHECK_FAILURE.replace(\n        \"<file>\", repr(str(tmp_path / \"seen\"))\n    )\n\n    script = testdir.makepyfile(health_check_test)\n\n    initial = testdir.runpytest(script, \"--verbose\", \"--strict-markers\")\n\n    match = CONTAINS_SEED_INSTRUCTION.search(\"\\n\".join(initial.stdout.lines))\n    initial_output = \"\\n\".join(initial.stdout.lines)\n\n    match = CONTAINS_SEED_INSTRUCTION.search(initial_output)\n    assert match is not None\n\n    rerun = testdir.runpytest(script, \"--verbose\", \"--strict-markers\", match.group(0))\n    rerun_output = \"\\n\".join(rerun.stdout.lines)\n\n    assert \"FailedHealthCheck\" in rerun_output\n    assert \"--hypothesis-seed\" not in rerun_output\n\n    rerun2 = testdir.runpytest(\n        script, \"--verbose\", \"--strict-markers\", \"--hypothesis-seed=10\"\n    )\n    rerun2_output = \"\\n\".join(rerun2.stdout.lines)\n    assert \"FailedHealthCheck\" not in rerun2_output\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_sideeffect_warnings.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\npytest_plugins = \"pytester\"\n\nTEST_SCRIPT = \"\"\"\ndef test_noop():\n    pass\n\"\"\"\n\nLAZY_STRATEGY = \"integers()\"\n\nSIDEEFFECT_STATEMENT = f\"st.{LAZY_STRATEGY}.wrapped_strategy\"\n\nSIDEEFFECT_SCRIPT = f\"\"\"\nfrom hypothesis import strategies as st\n\n{SIDEEFFECT_STATEMENT}\n\"\"\"\n\n\n@pytest.mark.skipif(\n    tuple(map(int, pytest.__version__.split(\".\")[:2])) <= (6, 1),\n    reason=\"Older pytest don't capture these warnings during runpytest setup\",\n)\ndef test_sideeffect_warning(testdir):\n    testdir.makeconftest(SIDEEFFECT_SCRIPT)\n    script = testdir.makepyfile(TEST_SCRIPT)\n    result = testdir.runpytest_subprocess(script)\n    assert \"HypothesisSideeffectWarning\" in \"\\n\".join(result.outlines)\n    assert LAZY_STRATEGY in \"\\n\".join(result.outlines)\n\n\ndef test_conftest_sideeffect_pinpoint_error(testdir, monkeypatch):\n    # -Werror is not sufficient since warning is emitted before session start. Additionally, we\n    # don't want to raise errors from other plugins. Due to limited filtering capabilities of\n    # PYTHONWARNINGS/-W (\"message is a literal string that the start of the warning message must\n    # contain\" and only built-in categories), we must fall back to the actual message text.\n    monkeypatch.setenv(\"PYTHONWARNINGS\", \"error:Slow code in plugin\")\n    testdir.makeconftest(SIDEEFFECT_SCRIPT)\n    script = testdir.makepyfile(TEST_SCRIPT)\n    result = testdir.runpytest_subprocess(script)\n    assert \"HypothesisSideeffectWarning\" in \"\\n\".join(result.errlines)\n    # Plugin is always loaded before conftest, so \"during pytest plugin initialization\"\n    assert \"during pytest\" in \"\\n\".join(result.errlines)\n    assert SIDEEFFECT_STATEMENT in \"\\n\".join(result.errlines)\n\n\ndef test_plugin_sideeffect_pinpoint_error(testdir, monkeypatch):\n    # See comment above regarding this line\n    monkeypatch.setenv(\"PYTHONWARNINGS\", \"error:Slow code in plugin\")\n    # Ensure we see the correct stacktrace regardless of plugin load order\n    monkeypatch.setenv(\"HYPOTHESIS_EXTEND_INITIALIZATION\", \"1\")\n    testdir.makepyfile(sideeffect_plugin=SIDEEFFECT_SCRIPT)\n    script = testdir.makepyfile(TEST_SCRIPT)\n    result = testdir.runpytest_subprocess(script, \"-p\", \"sideeffect_plugin\")\n    assert \"HypothesisSideeffectWarning\" in \"\\n\".join(result.errlines)\n    # Plugin order unknown, but certainly not at import time\n    assert \"at import time\" not in \"\\n\".join(result.errlines)\n    assert SIDEEFFECT_STATEMENT in \"\\n\".join(result.errlines)\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_skipping.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\npytest_plugins = \"pytester\"\n\n\nPYTEST_TESTSUITE = \"\"\"\nfrom hypothesis import given\nfrom hypothesis.strategies import integers\nimport pytest\n\n@given(xs=integers())\ndef test_to_be_skipped(xs):\n    # We always try the simplest example first, raising a Skipped exception\n    # which we know to propagate immediately...\n    if xs == 0:\n        pytest.skip()\n    # But the pytest 3.0 internals don't have such an exception, so we keep\n    # going and raise a BaseExceptionGroup error.  Ah well.\n    else:\n        assert xs == 0\n\"\"\"\n\n\ndef test_no_falsifying_example_if_pytest_skip(testdir):\n    \"\"\"If ``pytest.skip() is called during a test, Hypothesis should not\n    continue running the test and shrink process, nor should it print anything\n    about falsifying examples.\"\"\"\n    script = testdir.makepyfile(PYTEST_TESTSUITE)\n    result = testdir.runpytest(\n        script, \"--verbose\", \"--strict-markers\", \"-m\", \"hypothesis\"\n    )\n    out = \"\\n\".join(result.stdout.lines)\n    assert \"Falsifying example\" not in out\n\n\ndef test_issue_3453_regression(testdir):\n    \"\"\"If ``pytest.skip() is called during a test, Hypothesis should not\n    continue running the test and shrink process, nor should it print anything\n    about falsifying examples.\"\"\"\n    script = testdir.makepyfile(\n        \"\"\"\nfrom hypothesis import example, given, strategies as st\nimport pytest\n\n@given(value=st.none())\n@example(\"hello\")\n@example(\"goodbye\")\ndef test_skip_on_first_skipping_example(value):\n    assert value is not None\n    assert value != \"hello\"  # queue up a non-skip error which must be discarded\n    pytest.skip()\n\"\"\"\n    )\n    result = testdir.runpytest(script, \"--tb=native\")\n    result.assert_outcomes(skipped=1)\n"
  },
  {
    "path": "hypothesis-python/tests/pytest/test_statistics.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\nfrom _hypothesis_pytestplugin import PRINT_STATISTICS_OPTION\n\nfrom tests.common.utils import skipif_threading\n\npytest_plugins = \"pytester\"\n\n\ndef get_output(testdir, suite, *args):\n    script = testdir.makepyfile(suite)\n    result = testdir.runpytest(script, *args)\n    return \"\\n\".join(result.stdout.lines)\n\n\nTESTSUITE = \"\"\"\nfrom hypothesis import HealthCheck, given, settings, assume\nfrom hypothesis.strategies import integers\nimport time\nimport warnings\nfrom hypothesis.errors import HypothesisDeprecationWarning\n\nwarnings.simplefilter('always', HypothesisDeprecationWarning)\n\n\n@given(integers())\ndef test_all_valid(x):\n    pass\n\n\n@settings(max_examples=100, suppress_health_check=list(HealthCheck))\n@given(integers())\ndef test_iterations(x):\n    assume(x == 13)\n\"\"\"\n\n\ndef test_does_not_run_statistics_by_default(testdir):\n    out = get_output(testdir, TESTSUITE)\n    assert \"Hypothesis Statistics\" not in out\n\n\ndef test_prints_statistics_given_option(testdir):\n    out = get_output(testdir, TESTSUITE, PRINT_STATISTICS_OPTION)\n    assert \"Hypothesis Statistics\" in out\n    assert \"max_examples=100\" in out\n    assert \"< 1% of examples satisfied assumptions\" in out\n\n\ndef test_prints_statistics_given_option_under_xdist(testdir):\n    out = get_output(testdir, TESTSUITE, PRINT_STATISTICS_OPTION, \"-n\", \"2\")\n    assert \"Hypothesis Statistics\" in out\n    assert \"max_examples=100\" in out\n    assert \"< 1% of examples satisfied assumptions\" in out\n\n\ndef test_prints_statistics_given_option_with_junitxml(testdir):\n    out = get_output(testdir, TESTSUITE, PRINT_STATISTICS_OPTION, \"--junit-xml=out.xml\")\n    assert \"Hypothesis Statistics\" in out\n    assert \"max_examples=100\" in out\n    assert \"< 1% of examples satisfied assumptions\" in out\n\n\n@skipif_threading\n@pytest.mark.skipif(\n    tuple(map(int, pytest.__version__.split(\".\")[:2])) < (5, 4), reason=\"too old\"\n)\ndef test_prints_statistics_given_option_under_xdist_with_junitxml(testdir):\n    out = get_output(\n        testdir, TESTSUITE, PRINT_STATISTICS_OPTION, \"-n\", \"2\", \"--junit-xml=out.xml\"\n    )\n    assert \"Hypothesis Statistics\" in out\n    assert \"max_examples=100\" in out\n    assert \"< 1% of examples satisfied assumptions\" in out\n\n\nUNITTEST_TESTSUITE = \"\"\"\n\nfrom hypothesis import given\nfrom hypothesis.strategies import integers\nfrom unittest import TestCase\n\n\nclass TestStuff(TestCase):\n    @given(integers())\n    def test_all_valid(self, x):\n        pass\n\"\"\"\n\n\ndef test_prints_statistics_for_unittest_tests(testdir):\n    script = testdir.makepyfile(UNITTEST_TESTSUITE)\n    result = testdir.runpytest(script, PRINT_STATISTICS_OPTION)\n    out = \"\\n\".join(result.stdout.lines)\n    assert \"Hypothesis Statistics\" in out\n    assert \"TestStuff::test_all_valid\" in out\n    assert \"max_examples=100\" in out\n\n\nSTATEFUL_TESTSUITE = \"\"\"\nfrom hypothesis.stateful import RuleBasedStateMachine, rule\n\nclass Stuff(RuleBasedStateMachine):\n    @rule()\n    def step(self):\n        pass\n\nTestStuff = Stuff.TestCase\n\"\"\"\n\n\ndef test_prints_statistics_for_stateful_tests(testdir):\n    script = testdir.makepyfile(STATEFUL_TESTSUITE)\n    result = testdir.runpytest(script, PRINT_STATISTICS_OPTION)\n    out = \"\\n\".join(result.stdout.lines)\n    assert \"Hypothesis Statistics\" in out\n    assert \"TestStuff::runTest\" in out\n    assert \"max_examples=100\" in out\n"
  },
  {
    "path": "hypothesis-python/tests/quality/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/quality/test_deferred_strategies.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import strategies as st\n\nfrom tests.common.debug import minimal\n\n\ndef test_large_branching_tree():\n    tree = st.deferred(lambda: st.integers() | st.tuples(tree, tree, tree, tree, tree))\n    assert minimal(tree) == 0\n    assert minimal(tree, lambda x: isinstance(x, tuple)) == (0,) * 5\n\n\ndef test_non_trivial_json():\n    json = st.deferred(lambda: st.none() | st.floats() | st.text() | lists | objects)\n\n    lists = st.lists(json)\n    objects = st.dictionaries(st.text(), json)\n\n    assert minimal(json) is None\n    assert minimal(json, lambda x: isinstance(x, list) and x) == [None]\n    assert minimal(\n        json, lambda x: isinstance(x, dict) and isinstance(x.get(\"\"), list)\n    ) == {\"\": []}\n\n\ndef test_self_recursive_lists():\n    x = st.deferred(lambda: st.lists(x))\n    assert minimal(x) == []\n    assert minimal(x, bool) == [[]]\n    assert minimal(x, lambda x: len(x) > 1) == [[], []]\n"
  },
  {
    "path": "hypothesis-python/tests/quality/test_discovery_ability.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n# -*- coding: utf-8 -*-\n\"\"\"Statistical tests over the forms of the distributions in the standard set of\ndefinitions.\n\nThese tests all take the form of a classic hypothesis test with the null\nhypothesis being that the probability of some event occurring when\ndrawing data from the distribution produced by some specifier is >=\nREQUIRED_P\n\"\"\"\n\nimport collections\nimport math\nimport re\n\nfrom hypothesis import HealthCheck, settings as Settings\nfrom hypothesis.control import BuildContext\nfrom hypothesis.errors import UnsatisfiedAssumption\nfrom hypothesis.internal import reflection\nfrom hypothesis.internal.conjecture.engine import ConjectureRunner\nfrom hypothesis.strategies import (\n    binary,\n    booleans,\n    floats,\n    integers,\n    just,\n    lists,\n    one_of,\n    sampled_from,\n    sets,\n    text,\n    tuples,\n)\n\nfrom tests.common.utils import no_shrink\nfrom tests.conjecture.common import interesting_origin\n\n\nclass HypothesisFalsified(AssertionError):\n    pass\n\n\ndef define_test(specifier, predicate, condition=None, p=0.5, suppress_health_check=()):\n    runs = 100\n    required_runs = int(runs * p)\n\n    def run_test():\n        if condition is None:\n\n            def _condition(x):\n                return True\n\n            condition_string = \"\"\n        else:\n            _condition = condition\n            condition_string = reflection.get_pretty_function_description(condition)\n            condition_string = re.compile(\"^lambda[^:]*:\\\\s*\").sub(\"\", condition_string)\n\n        def test_function(data):\n            with BuildContext(data, wrapped_test=None):\n                try:\n                    value = data.draw(specifier)\n                except UnsatisfiedAssumption:\n                    data.mark_invalid()\n                if not _condition(value):\n                    data.mark_invalid()\n                if predicate(value):\n                    data.mark_interesting(interesting_origin())\n\n        successes = 0\n        actual_runs = 0\n        for actual_runs in range(1, runs + 1):\n            # We choose the max_examples a bit larger than default so that we\n            # run at least 100 examples outside of the small example generation\n            # part of the generation phase.\n            runner = ConjectureRunner(\n                test_function,\n                settings=Settings(\n                    max_examples=150,\n                    phases=no_shrink,\n                    suppress_health_check=suppress_health_check,\n                ),\n            )\n            runner.run()\n            if runner.interesting_examples:\n                successes += 1\n                if successes >= required_runs:\n                    return\n\n            # If we reach a point where it's impossible to hit our target even\n            # if every remaining attempt were to succeed, give up early and\n            # report failure.\n            if (required_runs - successes) > (runs - actual_runs):\n                break\n\n        event = reflection.get_pretty_function_description(predicate)\n        if condition is not None:\n            event += \"|\"\n            event += condition_string\n\n        raise HypothesisFalsified(\n            f\"P({event}) ~ {successes} / {actual_runs} = \"\n            f\"{successes / actual_runs:.2f} < {required_runs / runs:.2f}; \"\n            \"rejected\"\n        )\n\n    return run_test\n\n\ntest_can_produce_zero = define_test(integers(), lambda x: x == 0)\ntest_can_produce_large_magnitude_integers = define_test(\n    integers(), lambda x: abs(x) > 1000\n)\ntest_can_produce_large_positive_integers = define_test(integers(), lambda x: x > 1000)\ntest_can_produce_large_negative_integers = define_test(integers(), lambda x: x < -1000)\n\n\n_factorials = {math.factorial(n) for n in range(9, 21)}\n\n\ndef is_factorial(n):\n    return abs(n) in _factorials\n\n\ntest_can_produce_large_factorial = define_test(\n    integers(), lambda n: n >= 50_000 and is_factorial(n), p=0.01\n)\ntest_can_produce_above_large_factorial = define_test(\n    integers(), lambda n: n >= 50_000 and is_factorial(n - 1), p=0.01\n)\ntest_can_produce_below_large_factorial = define_test(\n    integers(), lambda n: n >= 50_000 and is_factorial(n + 1), p=0.01\n)\ntest_can_produce_large_factorial_negative = define_test(\n    integers(), lambda n: n <= -50_000 and is_factorial(n), p=0.01\n)\ntest_can_produce_above_large_factorial_negative = define_test(\n    integers(), lambda n: n <= -50_000 and is_factorial(n - 1), p=0.01\n)\ntest_can_produce_below_large_factorial_negative = define_test(\n    integers(), lambda n: n <= -50_000 and is_factorial(n + 1), p=0.01\n)\n\n\ntest_can_produce_unstripped_strings = define_test(text(), lambda x: x != x.strip())\ntest_can_produce_stripped_strings = define_test(text(), lambda x: x == x.strip())\n# The pass probability here was previously 0.5, but some intermediate changes\n# while working on the ir tweaked the distribution and made it flaky. We can\n# reevaluate this once things have settled down, and likely bump the pass\n# probability back up.\ntest_can_produce_multi_line_strings = define_test(text(), lambda x: \"\\n\" in x, p=0.35)\ntest_can_produce_ascii_strings = define_test(\n    text(), lambda x: all(ord(c) <= 127 for c in x)\n)\ntest_can_produce_long_strings_with_no_ascii = define_test(\n    text(min_size=5), lambda x: all(ord(c) > 127 for c in x), p=0.1\n)\ntest_can_produce_short_strings_with_some_non_ascii = define_test(\n    text(), lambda x: any(ord(c) > 127 for c in x), condition=lambda x: len(x) <= 3\n)\ntest_can_produce_large_binary_strings = define_test(\n    binary(), lambda x: len(x) > 10, p=0.3\n)\ntest_can_produce_positive_infinity = define_test(floats(), lambda x: x == math.inf)\ntest_can_produce_negative_infinity = define_test(floats(), lambda x: x == -math.inf)\ntest_can_produce_nan = define_test(floats(), math.isnan)\ntest_can_produce_floats_near_left = define_test(floats(0, 1), lambda t: t < 0.2)\ntest_can_produce_floats_near_right = define_test(floats(0, 1), lambda t: t > 0.8)\ntest_can_produce_floats_in_middle = define_test(floats(0, 1), lambda t: 0.2 <= t <= 0.8)\ntest_can_produce_long_lists = define_test(\n    lists(integers()), lambda x: len(x) >= 10, p=0.3\n)\ntest_can_produce_short_lists = define_test(lists(integers()), lambda x: len(x) <= 10)\ntest_can_produce_the_same_int_twice = define_test(\n    lists(integers()), lambda t: len(set(t)) < len(t)\n)\n\n\ndef distorted_value(x):\n    c = collections.Counter(x)\n    return min(c.values()) * 3 <= max(c.values())\n\n\ntest_sampled_from_large_number_can_mix = define_test(\n    lists(sampled_from(range(50)), min_size=50), lambda x: len(set(x)) >= 25\n)\ntest_sampled_from_often_distorted = define_test(\n    lists(sampled_from(range(5))), distorted_value, condition=lambda x: len(x) >= 3\n)\ntest_non_empty_subset_of_two_is_usually_large = define_test(\n    sets(sampled_from((1, 2))), lambda t: len(t) == 2\n)\ntest_subset_of_ten_is_sometimes_empty = define_test(\n    sets(integers(1, 10)), lambda t: len(t) == 0\n)\n\ntest_mostly_sensible_floats = define_test(floats(), lambda t: t + 1 > t)\ntest_mostly_largish_floats = define_test(\n    floats(), lambda t: t + 1 > 1, condition=lambda x: x > 0\n)\ntest_ints_can_occasionally_be_really_large = define_test(\n    integers(), lambda t: t >= 2**63\n)\n\ntest_mixing_is_sometimes_distorted = define_test(\n    lists(booleans() | tuples()),\n    lambda x: distorted_value(map(type, x)),\n    condition=lambda x: len(set(map(type, x))) == 2,\n    suppress_health_check=[HealthCheck.filter_too_much],\n)\n\ntest_mixes_2_reasonably_often = define_test(\n    lists(booleans() | tuples()), lambda x: len(set(map(type, x))) > 1, condition=bool\n)\n\ntest_partial_mixes_3_reasonably_often = define_test(\n    lists(booleans() | tuples() | just(\"hi\")),\n    lambda x: 1 < len(set(map(type, x))) < 3,\n    condition=bool,\n)\n\ntest_mixes_not_too_often = define_test(\n    lists(booleans() | tuples()), lambda x: len(set(map(type, x))) == 1, condition=bool\n)\n\ntest_integers_are_usually_non_zero = define_test(integers(), lambda x: x != 0)\ntest_integers_are_sometimes_zero = define_test(integers(), lambda x: x == 0)\ntest_integers_are_often_small = define_test(integers(), lambda x: abs(x) <= 100)\ntest_integers_are_often_small_but_not_that_small = define_test(\n    integers(), lambda x: 50 <= abs(x) <= 255\n)\n\n\n# This series of tests checks that the one_of() strategy flattens branches\n# correctly.  We assert that the probability of any branch is >= 0.1,\n# approximately (1/8 = 0.125), regardless of how heavily nested it is in the\n# strategy.\n\n# This first strategy chooses an integer between 0 and 7 (inclusive).\none_of_nested_strategy = one_of(\n    just(0),\n    one_of(\n        just(1), just(2), one_of(just(3), just(4), one_of(just(5), just(6), just(7)))\n    ),\n)\n\nfor i in range(8):\n    exec(f\"\"\"test_one_of_flattens_branches_{i} = define_test(\n        one_of_nested_strategy, lambda x: x == {i}\n    )\"\"\")\n\n\nxor_nested_strategy = just(0) | (\n    just(1) | just(2) | (just(3) | just(4) | (just(5) | just(6) | just(7)))\n)\n\nfor i in range(8):\n    exec(f\"\"\"test_xor_flattens_branches_{i} = define_test(\n        xor_nested_strategy, lambda x: x == {i}\n    )\"\"\")\n\n\n# This strategy tests interactions with `map()`.  They generate integers\n# from the set {1, 4, 6, 16, 20, 24, 28, 32}.\ndef double(x):\n    return x * 2\n\n\none_of_nested_strategy_with_map = one_of(\n    just(1),\n    one_of(\n        (just(2) | just(3)).map(double),\n        one_of(\n            (just(4) | just(5)).map(double),\n            one_of((just(6) | just(7) | just(8)).map(double)),\n        ).map(double),\n    ),\n)\n\nfor i in (1, 4, 6, 16, 20, 24, 28, 32):\n    exec(f\"\"\"test_one_of_flattens_map_branches_{i} = define_test(\n        one_of_nested_strategy_with_map, lambda x: x == {i}\n    )\"\"\")\n\n\n# This strategy tests interactions with `flatmap()`.  It generates lists\n# of length 0-7 (inclusive) in which every element is `None`.\none_of_nested_strategy_with_flatmap = just(None).flatmap(\n    lambda x: one_of(\n        just([x] * 0),\n        just([x] * 1),\n        one_of(\n            just([x] * 2),\n            just([x] * 3),\n            one_of(just([x] * 4), just([x] * 5), one_of(just([x] * 6), just([x] * 7))),\n        ),\n    )\n)\n\nfor i in range(8):\n    exec(f\"\"\"test_one_of_flattens_flatmap_branches_{i} = define_test(\n        one_of_nested_strategy_with_flatmap, lambda x: len(x) == {i}\n    )\"\"\")\n\n\nxor_nested_strategy_with_flatmap = just(None).flatmap(\n    lambda x: (\n        just([x] * 0)\n        | just([x] * 1)\n        | (\n            just([x] * 2)\n            | just([x] * 3)\n            | (just([x] * 4) | just([x] * 5) | (just([x] * 6) | just([x] * 7)))\n        )\n    )\n)\n\nfor i in range(8):\n    exec(f\"\"\"test_xor_flattens_flatmap_branches_{i} = define_test(\n        xor_nested_strategy_with_flatmap, lambda x: len(x) == {i}\n    )\"\"\")\n\n\n# This strategy tests interactions with `filter()`.  It generates the even\n# integers {0, 2, 4, 6} in equal measures.\none_of_nested_strategy_with_filter = one_of(\n    just(0),\n    just(1),\n    one_of(just(2), just(3), one_of(just(4), just(5), one_of(just(6), just(7)))),\n).filter(lambda x: x % 2 == 0)\n\nfor i in range(4):\n    exec(f\"\"\"test_one_of_flattens_filter_branches_{i} = define_test(\n        one_of_nested_strategy_with_filter, lambda x: x == 2 * {i}\n    )\"\"\")\n\n\ntest_long_duplicates_strings = define_test(\n    tuples(text(), text()), lambda s: len(s[0]) >= 5 and s[0] == s[1]\n)\ntest_can_produce_nasty_strings = define_test(\n    text(), lambda s: s in {\"NaN\", \"Inf\", \"undefined\"}, p=0.01\n)\n"
  },
  {
    "path": "hypothesis-python/tests/quality/test_float_shrinking.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesis import HealthCheck, example, given, settings, strategies as st\nfrom hypothesis.internal.compat import ceil\n\nfrom tests.common.debug import minimal\n\n\ndef test_shrinks_to_simple_floats():\n    assert minimal(st.floats(), lambda x: x > 1) == 2.0\n    assert minimal(st.floats(), lambda x: x > 0) == 1.0\n\n\n@pytest.mark.parametrize(\"n\", [1, 2, 3, 8, 10])\ndef test_can_shrink_in_variable_sized_context(n):\n    x = minimal(st.lists(st.floats(), min_size=n), any)\n    assert len(x) == n\n    assert x.count(0.0) == n - 1\n    assert 1 in x\n\n\n@example(1.7976931348623157e308)\n@example(1.5)\n@given(st.floats(min_value=0, allow_infinity=False, allow_nan=False))\n@settings(suppress_health_check=[HealthCheck.nested_given])\ndef test_shrinks_downwards_to_integers(f):\n    assert minimal(st.floats(min_value=f)) == ceil(f)\n\n\n@example(1)\n@given(st.integers(1, 2**16 - 1))\n@settings(suppress_health_check=[HealthCheck.nested_given])\ndef test_shrinks_downwards_to_integers_when_fractional(b):\n    g = minimal(\n        st.floats(\n            min_value=b, max_value=2**53, exclude_min=True, exclude_max=True\n        ).filter(lambda x: int(x) != x)\n    )\n    assert g == b + 0.5\n"
  },
  {
    "path": "hypothesis-python/tests/quality/test_integers.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis import given, settings, strategies as st\n\n\ndef test_biases_towards_boundary_values():\n    trillion = 10**12\n    boundary_vals = {-trillion, -trillion + 1, trillion - 1, trillion}\n\n    @given(st.integers(-trillion, trillion))\n    @settings(max_examples=1000)\n    def f(n):\n        boundary_vals.discard(n)\n\n    f()\n\n    assert (\n        not boundary_vals\n    ), f\"Expected to see all boundary vals, but still have {boundary_vals}\"\n"
  },
  {
    "path": "hypothesis-python/tests/quality/test_poisoned_lists.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom random import Random\n\nimport pytest\n\nfrom hypothesis import settings, strategies as st\nfrom hypothesis.internal.compat import ceil\nfrom hypothesis.internal.conjecture.engine import ConjectureData, ConjectureRunner\nfrom hypothesis.strategies._internal import SearchStrategy\n\nfrom tests.conjecture.common import interesting_origin\n\nPOISON = \"POISON\"\n\n\nclass Poisoned(SearchStrategy):\n    def __init__(self, poison_chance):\n        super().__init__()\n        self.__poison_chance = poison_chance\n        self.__ints = st.integers(0, 10)\n\n    def do_draw(self, data):\n        if data.draw_boolean(self.__poison_chance):\n            return POISON\n        else:\n            return data.draw(self.__ints)\n\n\nclass LinearLists(SearchStrategy):\n    def __init__(self, elements, size):\n        super().__init__()\n        self.__length = st.integers(0, size)\n        self.__elements = elements\n\n    def do_draw(self, data):\n        return [data.draw(self.__elements) for _ in range(data.draw(self.__length))]\n\n\nclass Matrices(SearchStrategy):\n    def __init__(self, elements, size):\n        super().__init__()\n        self.__length = st.integers(0, ceil(size**0.5))\n        self.__elements = elements\n\n    def do_draw(self, data):\n        n = data.draw(self.__length)\n        m = data.draw(self.__length)\n\n        return [data.draw(self.__elements) for _ in range(n * m)]\n\n\nLOTS = 10**6\n\nTRIAL_SETTINGS = settings(max_examples=LOTS, database=None)\n\n\n@pytest.mark.parametrize(\n    \"seed\", [2282791295271755424, 1284235381287210546, 14202812238092722246, 26097]\n)\n@pytest.mark.parametrize(\"size\", [5, 10, 20])\n@pytest.mark.parametrize(\"p\", [0.01, 0.1])\n@pytest.mark.parametrize(\"strategy_class\", [LinearLists, Matrices])\ndef test_minimal_poisoned_containers(seed, size, p, strategy_class):\n    elements = Poisoned(p)\n    strategy = strategy_class(elements, size)\n\n    def test_function(data):\n        v = data.draw(strategy)\n        data.output = repr(v)\n        if POISON in v:\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(\n        test_function, random=Random(seed), settings=TRIAL_SETTINGS\n    )\n    runner.run()\n    (v,) = runner.interesting_examples.values()\n    result = ConjectureData.for_choices(v.choices).draw(strategy)\n    assert len(result) == 1\n"
  },
  {
    "path": "hypothesis-python/tests/quality/test_poisoned_trees.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom random import Random\n\nimport pytest\n\nfrom hypothesis import HealthCheck, settings\nfrom hypothesis.internal.conjecture.engine import ConjectureData, ConjectureRunner\nfrom hypothesis.strategies._internal import SearchStrategy\n\nfrom tests.conjecture.common import interesting_origin\n\nPOISON = \"POISON\"\nMAX_INT = 2**32 - 1\n\n\nclass PoisonedTree(SearchStrategy):\n    \"\"\"Generates variable sized tuples with an implicit tree structure.\n\n    The actual result is flattened out, but the hierarchy is implicit in\n    the data.\n    \"\"\"\n\n    def __init__(self, p):\n        super().__init__()\n        self.__p = p\n\n    def do_draw(self, data):\n        if data.draw_boolean(self.__p):\n            return data.draw(self) + data.draw(self)\n        else:\n            # We draw n as two separate calls so that it doesn't show up as a\n            # single choice. If it did, the heuristics that allow us to move\n            # choices around would fire and it would move right, which would\n            # then allow us to shrink it more easily.\n            n1 = data.draw_integer(0, 2**16 - 1) << 16\n            n2 = data.draw_integer(0, 2**16 - 1)\n            n = n1 | n2\n            if n == MAX_INT:\n                return (POISON,)\n            else:\n                return (None,)\n\n\nTEST_SETTINGS = settings(\n    database=None,\n    suppress_health_check=list(HealthCheck),\n    max_examples=10**6,\n    deadline=None,\n)\n\n\n@pytest.mark.parametrize(\"size\", [2, 5, 10])\n@pytest.mark.parametrize(\"seed\", [0, 15993493061449915028])\ndef test_can_reduce_poison_from_any_subtree(size, seed):\n    \"\"\"This test validates that we can minimize to any leaf node of a binary\n    tree, regardless of where in the tree the leaf is.\"\"\"\n    random = Random(seed)\n\n    # Initially we create the minimal tree of size n, regardless of whether it\n    # is poisoned (which it won't be - the poison event essentially never\n    # happens when drawing uniformly at random).\n\n    # Choose p so that the expected size of the tree is equal to the desired\n    # size.\n    p = 1.0 / (2.0 - 1.0 / size)\n    strat = PoisonedTree(p)\n\n    def test_function(data):\n        v = data.draw(strat)\n        if len(v) >= size:\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(test_function, random=random, settings=TEST_SETTINGS)\n    runner.generate_new_examples()\n    runner.shrink_interesting_examples()\n    (data,) = runner.interesting_examples.values()\n    assert len(ConjectureData.for_choices(data.choices).draw(strat)) == size\n\n    # find the nodes corresponding to n1 and n2\n    nodes = [\n        node\n        for node in data.nodes\n        if node.type == \"integer\" and node.constraints[\"max_value\"] == 2**16 - 1\n    ]\n    assert len(nodes) % 2 == 0\n\n    marker = bytes([1, 2, 3, 4])\n    for i in range(0, len(nodes), 2):\n        # Now for each leaf position in the tree we try inserting a poison\n        # value artificially. Additionally, we add a marker to the end that\n        # must be preserved. The marker means that we are not allow to rely on\n        # discarding the end of the choice sequence to get the desired shrink.\n        node = nodes[i]\n\n        def test_function_with_poison(data):\n            v = data.draw(strat)\n            m = data.draw_bytes(len(marker), len(marker))\n            if POISON in v and m == marker:\n                data.mark_interesting(interesting_origin())\n\n        runner = ConjectureRunner(\n            test_function_with_poison, random=random, settings=TEST_SETTINGS\n        )\n        # replace n1 and n2 with 2**16 - 1 to insert a poison value here\n        runner.cached_test_function(\n            data.choices[: node.index]\n            + (2**16 - 1, 2**16 - 1)\n            + (data.choices[node.index + 2 :])\n            + (marker,)\n        )\n        assert runner.interesting_examples\n\n        runner.shrink_interesting_examples()\n        (shrunk,) = runner.interesting_examples.values()\n        assert ConjectureData.for_choices(shrunk.choices).draw(strat) == (POISON,)\n"
  },
  {
    "path": "hypothesis-python/tests/quality/test_shrink_quality.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom collections import Counter, OrderedDict, namedtuple\nfrom fractions import Fraction\nfrom functools import reduce\n\nimport pytest\n\nimport hypothesis.strategies as st\nfrom hypothesis import HealthCheck, assume, given, settings\nfrom hypothesis.strategies import (\n    booleans,\n    builds,\n    dictionaries,\n    fixed_dictionaries,\n    fractions,\n    frozensets,\n    integers,\n    just,\n    lists,\n    none,\n    sampled_from,\n    sets,\n    text,\n    tuples,\n)\n\nfrom tests.common.debug import minimal\nfrom tests.common.utils import flaky\n\n\ndef test_integers_from_minimizes_leftwards():\n    assert minimal(integers(min_value=101)) == 101\n\n\ndef test_minimize_bounded_integers_to_zero():\n    assert minimal(integers(-10, 10)) == 0\n\n\ndef test_minimize_bounded_integers_to_positive():\n    zero = 0\n\n    def not_zero(x):\n        return x != zero\n\n    assert minimal(integers(-10, 10).filter(not_zero)) == 1\n\n\ndef test_minimal_fractions_1():\n    assert minimal(fractions()) == Fraction(0)\n\n\ndef test_minimal_fractions_2():\n    assert minimal(fractions(), lambda x: x >= 1) == Fraction(1)\n\n\ndef test_minimal_fractions_3():\n    assert minimal(lists(fractions()), lambda s: len(s) >= 5) == [Fraction(0)] * 5\n\n\ndef test_minimize_string_to_empty():\n    assert minimal(text()) == \"\"\n\n\ndef test_minimize_one_of():\n    for _ in range(100):\n        assert minimal(integers() | text() | booleans()) in (0, \"\", False)\n\n\ndef test_minimize_mixed_list():\n    mixed = minimal(lists(integers() | text()), lambda x: len(x) >= 10)\n    assert set(mixed).issubset({0, \"\"})\n\n\ndef test_minimize_longer_string():\n    assert minimal(text(), lambda x: len(x) >= 10) == \"0\" * 10\n\n\ndef test_minimize_longer_list_of_strings():\n    assert minimal(lists(text()), lambda x: len(x) >= 10) == [\"\"] * 10\n\n\ndef test_minimize_3_set():\n    assert minimal(sets(integers()), lambda x: len(x) >= 3) in ({0, 1, 2}, {-1, 0, 1})\n\n\ndef test_minimize_3_set_of_tuples():\n    assert minimal(sets(tuples(integers())), lambda x: len(x) >= 2) == {(0,), (1,)}\n\n\ndef test_minimize_sets_of_sets():\n    elements = integers(1, 100)\n    size = 8\n    set_of_sets = minimal(sets(frozensets(elements), min_size=size))\n    assert frozenset() in set_of_sets\n    assert len(set_of_sets) == size\n    for s in set_of_sets:\n        if len(s) > 1:\n            assert any(s != t and t.issubset(s) for t in set_of_sets)\n\n\ndef test_minimize_sets_sampled_from():\n    assert minimal(st.sets(st.sampled_from(range(10)), min_size=3)) == {0, 1, 2}\n\n\ndef test_can_simplify_flatmap_with_bounded_left_hand_size():\n    assert (\n        minimal(booleans().flatmap(lambda x: lists(just(x))), lambda x: len(x) >= 10)\n        == [False] * 10\n    )\n\n\ndef test_can_simplify_across_flatmap_of_just():\n    assert minimal(integers().flatmap(just)) == 0\n\n\ndef test_can_simplify_on_right_hand_strategy_of_flatmap():\n    assert minimal(integers().flatmap(lambda x: lists(just(x)))) == []\n\n\n@flaky(min_passes=5, max_runs=5)\ndef test_can_ignore_left_hand_side_of_flatmap():\n    assert (\n        minimal(integers().flatmap(lambda x: lists(integers())), lambda x: len(x) >= 10)\n        == [0] * 10\n    )\n\n\ndef test_can_simplify_on_both_sides_of_flatmap():\n    assert (\n        minimal(integers().flatmap(lambda x: lists(just(x))), lambda x: len(x) >= 10)\n        == [0] * 10\n    )\n\n\ndef test_flatmap_rectangles():\n    lengths = integers(min_value=0, max_value=10)\n\n    def lists_of_length(n):\n        return lists(sampled_from(\"ab\"), min_size=n, max_size=n)\n\n    xs = minimal(\n        lengths.flatmap(lambda w: lists(lists_of_length(w))),\n        lambda x: [\"a\", \"b\"] in x,\n        settings=settings(database=None, max_examples=2000),\n    )\n    assert xs == [[\"a\", \"b\"]]\n\n\n@flaky(min_passes=5, max_runs=5)\n@pytest.mark.parametrize(\"dict_class\", [dict, OrderedDict])\ndef test_dictionary(dict_class):\n    assert (\n        minimal(dictionaries(keys=integers(), values=text(), dict_class=dict_class))\n        == dict_class()\n    )\n\n    x = minimal(\n        dictionaries(keys=integers(), values=text(), dict_class=dict_class),\n        lambda t: len(t) >= 3,\n    )\n    assert isinstance(x, dict_class)\n    assert set(x.values()) == {\"\"}\n    for k in x:\n        if k < 0:\n            assert k + 1 in x\n        if k > 0:\n            assert k - 1 in x\n\n\ndef test_minimize_single_element_in_silly_large_int_range():\n    assert minimal(integers(-(2**256), 2**256), lambda x: x >= -(2**255)) == 0\n\n\ndef test_minimize_multiple_elements_in_silly_large_int_range():\n    actual = minimal(\n        lists(integers(-(2**256), 2**256)),\n        lambda x: len(x) >= 20,\n        settings(max_examples=10_000),\n    )\n    assert actual == [0] * 20\n\n\ndef test_minimize_multiple_elements_in_silly_large_int_range_min_is_not_dupe():\n    target = list(range(20))\n\n    actual = minimal(\n        lists(integers(0, 2**256)),\n        lambda x: (assume(len(x) >= 20) and all(x[i] >= target[i] for i in target)),\n    )\n    assert actual == target\n\n\ndef test_find_large_union_list():\n    size = 10\n\n    def large_mostly_non_overlapping(xs):\n        union = reduce(set.union, xs)\n        return len(union) >= size\n\n    result = minimal(\n        lists(sets(integers(), min_size=1), min_size=1),\n        large_mostly_non_overlapping,\n    )\n    assert len(result) == 1\n    union = reduce(set.union, result)\n    assert len(union) == size\n    assert max(union) == min(union) + len(union) - 1\n\n\n@pytest.mark.parametrize(\"n\", [0, 1, 10, 100, 1000])\n@pytest.mark.parametrize(\n    \"seed\", [13878544811291720918, 15832355027548327468, 12901656430307478246]\n)\ndef test_containment(n, seed):\n    iv = minimal(\n        tuples(lists(integers()), integers()),\n        lambda x: x[1] in x[0] and x[1] >= n,\n    )\n    assert iv == ([n], n)\n\n\ndef test_duplicate_containment():\n    ls, i = minimal(\n        tuples(lists(integers()), integers()),\n        lambda s: s[0].count(s[1]) > 1,\n    )\n    assert ls == [0, 0]\n    assert i == 0\n\n\n@pytest.mark.parametrize(\"seed\", [11, 28, 37])\ndef test_reordering_bytes(seed):\n    ls = minimal(lists(integers()), lambda x: sum(x) >= 10 and len(x) >= 3)\n    assert ls == sorted(ls)\n\n\ndef test_minimize_long_list():\n    assert (\n        minimal(lists(booleans(), min_size=50), lambda x: len(x) >= 70) == [False] * 70\n    )\n\n\ndef test_minimize_list_of_longish_lists():\n    size = 5\n    xs = minimal(\n        lists(lists(booleans())),\n        lambda x: len([t for t in x if any(t) and len(t) >= 2]) >= size,\n    )\n    assert len(xs) == size\n    for x in xs:\n        assert x == [False, True]\n\n\ndef test_minimize_list_of_fairly_non_unique_ints():\n    xs = minimal(lists(integers()), lambda x: len(set(x)) < len(x))\n    assert len(xs) == 2\n\n\ndef test_list_with_complex_sorting_structure():\n    xs = minimal(\n        lists(lists(booleans())),\n        lambda x: [list(reversed(t)) for t in x] > x and len(x) > 3,\n    )\n    assert len(xs) == 4\n\n\ndef test_list_with_wide_gap():\n    xs = minimal(lists(integers()), lambda x: x and (max(x) > min(x) + 10 > 0))\n    assert len(xs) == 2\n    xs.sort()\n    assert xs[1] == 11 + xs[0]\n\n\ndef test_minimize_namedtuple():\n    T = namedtuple(\"T\", (\"a\", \"b\"))\n    tab = minimal(builds(T, integers(), integers()), lambda x: x.a < x.b)\n    assert tab.b == tab.a + 1\n\n\ndef test_minimize_dict():\n    tab = minimal(\n        fixed_dictionaries({\"a\": booleans(), \"b\": booleans()}),\n        lambda x: x[\"a\"] or x[\"b\"],\n    )\n    assert not (tab[\"a\"] and tab[\"b\"])\n\n\ndef test_minimize_list_of_sets():\n    assert minimal(\n        lists(sets(booleans())), lambda x: len(list(filter(None, x))) >= 3\n    ) == ([{False}] * 3)\n\n\ndef test_minimize_list_of_lists():\n    assert minimal(\n        lists(lists(integers())), lambda x: len(list(filter(None, x))) >= 3\n    ) == ([[0]] * 3)\n\n\ndef test_minimize_list_of_tuples():\n    xs = minimal(lists(tuples(integers(), integers())), lambda x: len(x) >= 2)\n    assert xs == [(0, 0), (0, 0)]\n\n\ndef test_minimize_multi_key_dicts():\n    assert minimal(dictionaries(keys=booleans(), values=booleans()), bool) == {\n        False: False\n    }\n\n\ndef test_multiple_empty_lists_are_independent():\n    x = minimal(lists(lists(none(), max_size=0)), lambda t: len(t) >= 2)\n    u, v = x\n    assert u is not v\n\n\ndef test_can_find_sets_unique_by_incomplete_data():\n    size = 5\n    ls = minimal(\n        lists(tuples(integers(), integers()), unique_by=max), lambda x: len(x) >= size\n    )\n    assert len(ls) == size\n    values = sorted(map(max, ls))\n    assert values[-1] - values[0] == size - 1\n    for u, _ in ls:\n        assert u <= 0\n\n\n@pytest.mark.parametrize(\"n\", range(10))\ndef test_lists_forced_near_top(n):\n    assert minimal(\n        lists(integers(), min_size=n, max_size=n + 2), lambda t: len(t) == n + 2\n    ) == [0] * (n + 2)\n\n\ndef test_sum_of_pair_int():\n    assert minimal(\n        tuples(integers(0, 1000), integers(0, 1000)), lambda x: sum(x) > 1000\n    ) == (1, 1000)\n\n\ndef test_sum_of_pair_float():\n    assert minimal(\n        tuples(st.floats(0, 1000), st.floats(0, 1000)), lambda x: sum(x) > 1000\n    ) == (1.0, 1000.0)\n\n\ndef test_sum_of_pair_mixed():\n    # check both orderings\n    assert minimal(\n        tuples(st.floats(0, 1000), st.integers(0, 1000)), lambda x: sum(x) > 1000\n    ) == (1.0, 1000)\n    assert minimal(\n        tuples(st.integers(0, 1000), st.floats(0, 1000)), lambda x: sum(x) > 1000\n    ) == (1, 1000.0)\n\n\ndef test_sum_of_pair_separated_int():\n    @st.composite\n    def separated_sum(draw):\n        n1 = draw(st.integers(0, 1000))\n        draw(st.text())\n        draw(st.booleans())\n        draw(st.integers())\n        n2 = draw(st.integers(0, 1000))\n        return (n1, n2)\n\n    assert minimal(separated_sum(), lambda x: sum(x) > 1000) == (1, 1000)\n\n\ndef test_sum_of_pair_separated_float():\n    @st.composite\n    def separated_sum(draw):\n        f1 = draw(st.floats(0, 1000))\n        draw(st.text())\n        draw(st.booleans())\n        draw(st.integers())\n        f2 = draw(st.floats(0, 1000))\n        return (f1, f2)\n\n    assert minimal(separated_sum(), lambda x: sum(x) > 1000) == (1, 1000)\n\n\ndef test_calculator_benchmark():\n    \"\"\"This test comes from\n    https://github.com/jlink/shrinking-challenge/blob/main/challenges/calculator.md,\n    which is originally from Pike, Lee. \"SmartCheck: automatic and efficient\n    counterexample reduction and generalization.\"\n    Proceedings of the 2014 ACM SIGPLAN symposium on Haskell. 2014.\n    \"\"\"\n\n    expression = st.deferred(\n        lambda: st.one_of(\n            st.integers(),\n            st.tuples(st.just(\"+\"), expression, expression),\n            st.tuples(st.just(\"/\"), expression, expression),\n        )\n    )\n\n    def div_subterms(e):\n        if isinstance(e, int):\n            return True\n        if e[0] == \"/\" and e[-1] == 0:\n            return False\n        return div_subterms(e[1]) and div_subterms(e[2])\n\n    def evaluate(e):\n        if isinstance(e, int):\n            return e\n        elif e[0] == \"+\":\n            return evaluate(e[1]) + evaluate(e[2])\n        else:\n            assert e[0] == \"/\"\n            return evaluate(e[1]) // evaluate(e[2])\n\n    def is_failing(e):\n        assume(div_subterms(e))\n        try:\n            evaluate(e)\n            return False\n        except ZeroDivisionError:\n            return True\n\n    x = minimal(expression, is_failing)\n\n    assert x == (\"/\", 0, (\"+\", 0, 0))\n\n\ndef test_one_of_slip():\n    assert minimal(st.integers(101, 200) | st.integers(0, 100)) == 101\n\n\n# this limit is only to avoid Unsatisfiable when searching for an initial\n# counterexample in minimal, as we may generate a very large magnitude n.\n@given(st.integers(-(2**32), 2**32))\n@settings(max_examples=3, suppress_health_check=[HealthCheck.nested_given])\ndef test_perfectly_shrinks_integers(n):\n    if n >= 0:\n        assert minimal(st.integers(), lambda x: x >= n) == n\n    else:\n        assert minimal(st.integers(), lambda x: x <= n) == n\n\n\n@given(st.integers(0, 20))\n@settings(suppress_health_check=[HealthCheck.nested_given])\ndef test_lowering_together_positive(gap):\n    s = st.tuples(st.integers(0, 20), st.integers(0, 20))\n    assert minimal(s, lambda x: x[0] + gap == x[1]) == (0, gap)\n\n\n@given(st.integers(-20, 0))\n@settings(suppress_health_check=[HealthCheck.nested_given])\ndef test_lowering_together_negative(gap):\n    s = st.tuples(st.integers(-20, 0), st.integers(-20, 0))\n    assert minimal(s, lambda x: x[0] + gap == x[1]) == (0, gap)\n\n\n@given(st.integers(-10, 10))\n@settings(suppress_health_check=[HealthCheck.nested_given])\ndef test_lowering_together_mixed(gap):\n    s = st.tuples(st.integers(-10, 10), st.integers(-10, 10))\n    assert minimal(s, lambda x: x[0] + gap == x[1]) == (0, gap)\n\n\n@given(st.integers(-10, 10))\n@settings(suppress_health_check=[HealthCheck.nested_given])\ndef test_lowering_together_with_gap(gap):\n    s = st.tuples(st.integers(-10, 10), st.text(), st.floats(), st.integers(-10, 10))\n    assert minimal(s, lambda x: x[0] + gap == x[3]) == (0, \"\", 0.0, gap)\n\n\ndef test_run_length_encoding():\n    # extracted from https://github.com/HypothesisWorks/hypothesis/issues/4286,\n    # as well as our docs\n\n    def decode(table: list[tuple[int, str]]) -> str:\n        out = \"\"\n        for count, char in table:\n            out += count * char\n        return out\n\n    def encode(s: str) -> list[tuple[int, str]]:\n        count = 1\n        prev = \"\"\n        out = []\n\n        if not s:\n            return []\n\n        for char in s:\n            if char != prev:\n                if prev:\n                    entry = (count, prev)\n                    out.append(entry)\n                # BUG:\n                # count = 1\n                prev = char\n            else:\n                count += 1\n\n        entry = (count, char)\n        out.append(entry)\n        return out\n\n    assert minimal(st.text(), lambda s: decode(encode(s)) != s) == \"001\"\n\n\ndef test_minimize_duplicated_characters_within_a_choice():\n    # look for strings which have at least 3 of the same character, and also at\n    # least two different characters (to avoid the trivial shrink of replacing\n    # everything with \"0\" from working).\n\n    # we should test this for st.binary too, but it's difficult to get it\n    # to satisfy this precondition in the first place (probably worth improving\n    # our generation here to duplicate binary elements in generate_mutations_from)\n    assert (\n        minimal(\n            st.text(min_size=1),\n            lambda v: Counter(v).most_common()[0][1] > 2 and len(set(v)) > 1,\n        )\n        == \"0001\"\n    )\n\n\ndef test_nasty_string_shrinks():\n    # failures found via NASTY_STRINGS should shrink like normal\n    assert (\n        minimal(st.text(), lambda s: \"𝕿𝖍𝖊\" in s, settings=settings(max_examples=10000))\n        == \"𝕿𝖍𝖊\"\n    )\n\n\ndef test_bound5():\n    # redistribute_numeric_pairs should work for negative integers too\n    bounded_ints = st.lists(st.integers(-100, 0), max_size=1)\n\n    s = st.tuples(\n        bounded_ints,\n        bounded_ints,\n        bounded_ints,\n        bounded_ints,\n        bounded_ints,\n    )\n    assert minimal(s, lambda v: sum(sum(v, []), 0) < -150) == (\n        [],\n        [],\n        [],\n        [-51],\n        [-100],\n    )\n"
  },
  {
    "path": "hypothesis-python/tests/quality/test_zig_zagging.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom math import log\nfrom random import Random\n\nfrom hypothesis import (\n    HealthCheck,\n    Phase,\n    Verbosity,\n    assume,\n    example,\n    given,\n    settings,\n    strategies as st,\n)\nfrom hypothesis.internal.compat import ceil\nfrom hypothesis.internal.conjecture.data import ConjectureData\nfrom hypothesis.internal.conjecture.engine import ConjectureRunner\n\nfrom tests.conjecture.common import interesting_origin\n\n\n@st.composite\ndef problems(draw):\n    m = draw(st.integers(256, 2**64 - 1))\n    assume(m > 0)\n    marker = draw(st.binary(max_size=8))\n    bound = draw(st.integers(0, m - 1))\n    return (m, marker, bound)\n\n\nbase_settings = settings(\n    database=None,\n    deadline=None,\n    suppress_health_check=list(HealthCheck),\n    max_examples=10,\n    verbosity=Verbosity.normal,\n    phases=(Phase.explicit, Phase.generate),\n)\n\n\n@example((4503599627370496, b\"\", 2861143707951135))\n@example((88305152, b\"%\\x1b\\xa0\\xfa\", 12394667))\n@example((99742672384, b\"\\xf5|\", 24300326997))\n@example((1454610481571840, b\"\", 1076887621690235))\n@example((15616, b\"\", 2508))\n@example((65536, b\"\", 20048))\n@example((256, b\"\", 0))\n@example((512, b\"\", 258))\n@example((2048, b\"\", 1792))\n@example((3072, b\"\", 0))\n@example((256, b\"\", 1))\n@settings(\n    base_settings,\n    verbosity=Verbosity.normal,\n    phases=(\n        # We disable shrinking for this test because when it fails it's a sign\n        # that the shrinker is working really badly, so it ends up very slow!\n        Phase.explicit,\n        Phase.generate,\n    ),\n    max_examples=20,\n)\n@given(problems())\ndef test_avoids_zig_zag_trap(p):\n    m, marker, lower_bound = p\n    n_bits = m.bit_length() + 1\n\n    def test_function(data):\n        m = data.draw_integer(0, 2**n_bits - 1)\n        if m < lower_bound:\n            data.mark_invalid()\n        n = data.draw_integer(0, 2**n_bits - 1)\n        if data.draw_bytes(len(marker), len(marker)) != marker:\n            data.mark_invalid()\n        if abs(m - n) == 1:\n            data.mark_interesting(interesting_origin())\n\n    runner = ConjectureRunner(\n        test_function,\n        database_key=None,\n        settings=settings(base_settings, phases=(Phase.generate, Phase.shrink)),\n        random=Random(0),\n    )\n\n    runner.cached_test_function((m, m + 1, marker))\n    assert runner.interesting_examples\n    runner.run()\n    (v,) = runner.interesting_examples.values()\n    data = ConjectureData.for_choices(v.choices)\n\n    m = data.draw_integer(0, 2**n_bits - 1)\n    n = data.draw_integer(0, 2**n_bits - 1)\n    assert m == lower_bound\n    if m == 0:\n        assert n == 1\n    else:\n        assert n == m - 1\n\n    budget = 2 * n_bits * ceil(log(n_bits, 2)) + 2\n    assert runner.shrinks <= budget\n"
  },
  {
    "path": "hypothesis-python/tests/redis/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/redis/test_redis_exampledatabase.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport uuid\n\nimport pytest\nfrom fakeredis import FakeRedis\n\nfrom hypothesis import settings, strategies as st\nfrom hypothesis.database import InMemoryExampleDatabase\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.extra.redis import RedisExampleDatabase\nfrom hypothesis.stateful import Bundle, RuleBasedStateMachine, rule\n\nfrom tests.cover.test_database_backend import _database_conforms_to_listener_api\n\n\n@pytest.mark.parametrize(\n    \"kw\",\n    [\n        {\"redis\": \"not a redis instance\"},\n        {\"redis\": FakeRedis(), \"expire_after\": 10},  # not a timedelta\n        {\"redis\": FakeRedis(), \"key_prefix\": \"not a bytestring\"},\n        {\"redis\": FakeRedis(), \"listener_channel\": 2},  # not a str\n    ],\n)\ndef test_invalid_args_raise(kw):\n    with pytest.raises(InvalidArgument):\n        RedisExampleDatabase(**kw)\n\n\ndef test_all_methods():\n    db = RedisExampleDatabase(FakeRedis())\n    db.save(b\"key1\", b\"value\")\n    assert list(db.fetch(b\"key1\")) == [b\"value\"]\n    db.move(b\"key1\", b\"key2\", b\"value\")\n    assert list(db.fetch(b\"key1\")) == []\n    assert list(db.fetch(b\"key2\")) == [b\"value\"]\n    db.delete(b\"key2\", b\"value\")\n    assert list(db.fetch(b\"key2\")) == []\n    db.delete(b\"key2\", b\"unknown value\")\n\n\nclass DatabaseComparison(RuleBasedStateMachine):\n    def __init__(self):\n        super().__init__()\n        server = FakeRedis(host=uuid.uuid4().hex)  # Different (fake) server each time\n        self.dbs = [InMemoryExampleDatabase(), RedisExampleDatabase(server)]\n\n    keys = Bundle(\"keys\")\n    values = Bundle(\"values\")\n\n    @rule(target=keys, k=st.binary())\n    def k(self, k):\n        return k\n\n    @rule(target=values, v=st.binary())\n    def v(self, v):\n        return v\n\n    @rule(k=keys, v=values)\n    def save(self, k, v):\n        for db in self.dbs:\n            db.save(k, v)\n\n    @rule(k=keys, v=values)\n    def delete(self, k, v):\n        for db in self.dbs:\n            db.delete(k, v)\n\n    @rule(k1=keys, k2=keys, v=values)\n    def move(self, k1, k2, v):\n        for db in self.dbs:\n            db.move(k1, k2, v)\n\n    @rule(k=keys)\n    def values_agree(self, k):\n        last = None\n        last_db = None\n        for db in self.dbs:\n            keys = set(db.fetch(k))\n            if last is not None:\n                assert last == keys, (last_db, db)\n            last = keys\n            last_db = db\n\n\nTestDBs = DatabaseComparison.TestCase\n\n\ndef flush_messages(db):\n    # fake redis doesn't have the background polling for pubsub that an actual\n    # redis server does, so we have to flush when we want them.\n    if db._pubsub is None:\n        return\n    # arbitrarily high.\n    for _ in range(100):\n        db._pubsub.get_message()\n\n\ndef test_redis_listener():\n    _database_conforms_to_listener_api(\n        lambda _path: RedisExampleDatabase(FakeRedis()),\n        flush=flush_messages,\n        parent_settings=settings(\n            max_examples=5,\n            stateful_step_count=10,\n        ),\n    )\n\n\ndef test_redis_listener_explicit():\n    calls = 0\n\n    def listener(event):\n        nonlocal calls\n        calls += 1\n\n    redis = FakeRedis()\n    db = RedisExampleDatabase(redis)\n    db.add_listener(listener)\n\n    db.save(b\"a\", b\"a\")\n    flush_messages(db)\n    assert calls == 1\n\n    db.remove_listener(listener)\n    db.delete(b\"a\", b\"a\")\n    db.save(b\"a\", b\"b\")\n    flush_messages(db)\n    assert calls == 1\n\n    db.add_listener(listener)\n    db.delete(b\"a\", b\"b\")\n    db.save(b\"a\", b\"c\")\n    flush_messages(db)\n    assert calls == 3\n\n    db.save(b\"a\", b\"c\")\n    flush_messages(db)\n    assert calls == 3\n\n\ndef test_redis_move_from_key_without_value():\n    # explicit covering test for:\n    # * moving a value from a key without that value\n    redis = FakeRedis()\n    db = RedisExampleDatabase(redis)\n    db.save(b\"a\", b\"x\")\n    db.save(b\"b\", b\"x\")\n    db.move(b\"a\", b\"b\", b\"y\")\n\n\ndef test_redis_move_into_key_with_value():\n    # explicit covering test for:\n    # * moving a value into a key with that value\n    redis = FakeRedis()\n    db = RedisExampleDatabase(redis)\n    db.save(b\"a\", b\"y\")\n    db.save(b\"b\", b\"x\")\n    db.move(b\"a\", b\"b\", b\"x\")\n\n\ndef test_redis_move_to_same_key():\n    # explicit covering test for:\n    # * moving a value where src == dest\n    redis = FakeRedis()\n    db = RedisExampleDatabase(redis)\n    db.move(b\"a\", b\"a\", b\"x\")\n    assert list(db.fetch(b\"a\")) == [b\"x\"]\n\n\ndef test_redis_equality():\n    redis = FakeRedis()\n    assert RedisExampleDatabase(redis) == RedisExampleDatabase(redis)\n    # FakeRedis() != FakeRedis(), not much we can do here\n    assert RedisExampleDatabase(FakeRedis()) != RedisExampleDatabase(FakeRedis())\n"
  },
  {
    "path": "hypothesis-python/tests/test_annotated_types.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\nimport sys\nfrom typing import Annotated\n\nimport pytest\n\nfrom hypothesis import given, strategies as st\nfrom hypothesis.errors import HypothesisWarning, ResolutionFailed\nfrom hypothesis.strategies._internal.lazy import unwrap_strategies\nfrom hypothesis.strategies._internal.strategies import FilteredStrategy\nfrom hypothesis.strategies._internal.types import _get_constraints\n\nfrom tests.common.debug import assert_simple_property, check_can_generate_examples\n\ntry:\n    import annotated_types as at\nexcept ImportError:\n    pytest.skip(allow_module_level=True)\n\n\ndef test_strategy_priority_over_constraints():\n    expected_strategy = st.SearchStrategy()\n\n    strategy = st.from_type(Annotated[int, expected_strategy, at.Gt(1)])\n    assert strategy is expected_strategy\n\n\ndef test_invalid_annotated_type():\n    msg = re.escape(\"Did you mean `Annotated[str | int, 'dummy']`?\")\n    with pytest.raises(ResolutionFailed, match=f\".*{msg}$\"):\n        check_can_generate_examples(\n            st.from_type(Annotated[str, \"dummy\", Annotated[int, \"dummy\"]])\n        )\n\n\n@pytest.mark.parametrize(\n    \"unsupported_constraints,message\",\n    [\n        ((at.Timezone(None),), \"Ignoring unsupported Timezone(tz=None)\"),\n        ((at.MultipleOf(1),), \"Ignoring unsupported MultipleOf(multiple_of=1)\"),\n        (\n            (at.Timezone(None), at.MultipleOf(1)),\n            \"Ignoring unsupported Timezone(tz=None), MultipleOf(multiple_of=1)\",\n        ),\n    ],\n)\ndef test_unsupported_constraints(unsupported_constraints, message):\n    if sys.version_info >= (3, 11):\n        # This is the preferred format, but also a SyntaxError on Python <= 3.10\n        t = eval(\"Annotated[int, *unsupported_constraints]\", globals(), locals())\n    else:\n        t = Annotated.__class_getitem__((int, *unsupported_constraints))\n    with pytest.warns(HypothesisWarning, match=re.escape(message)):\n        check_can_generate_examples(st.from_type(t))\n\n\n@pytest.mark.parametrize(\n    \"annotated_type,expected_strategy_repr\",\n    [\n        (Annotated[int, at.Gt(1)], \"integers(min_value=2)\"),\n        (Annotated[int, at.Ge(1)], \"integers(min_value=1)\"),\n        (Annotated[int, at.Lt(1)], \"integers(max_value=0)\"),\n        (Annotated[int, at.Le(1)], \"integers(max_value=1)\"),\n        (Annotated[int, at.Interval(ge=1, le=3)], \"integers(1, 3)\"),\n        (Annotated[int, at.Interval(ge=1), at.Ge(2)], \"integers(min_value=2)\"),\n    ],\n)\ndef test_annotated_type_int(annotated_type, expected_strategy_repr):\n    strategy = unwrap_strategies(st.from_type(annotated_type))\n    assert repr(strategy) == expected_strategy_repr\n\n\ndef test_predicate_constraint():\n    def func(_):\n        return True\n\n    strategy = unwrap_strategies(st.from_type(Annotated[int, at.Predicate(func)]))\n    assert isinstance(strategy, FilteredStrategy)\n    assert strategy.flat_conditions == (func,)\n\n\nclass MyCollection:\n    def __init__(self, values: list[int]) -> None:\n        self._values = values\n\n    def __len__(self) -> int:\n        return len(self._values)\n\n\n@pytest.mark.parametrize(\"lo\", [0, 1])\n@pytest.mark.parametrize(\"hi\", [None, 10])\n@pytest.mark.parametrize(\"type_\", [list[int], set[int], MyCollection])\n@given(data=st.data())\ndef test_collection_sizes(data, lo, hi, type_):\n    print(f\"{type_=} {lo=} {hi=}\")\n    assert lo < (hi or 11)\n    t = Annotated[type_, at.Len(min_length=lo, max_length=hi)]\n    s = st.from_type(t)\n    value = data.draw(s)\n    assert lo is None or lo <= len(value)\n    assert hi is None or len(value) <= hi\n\n\n@given(st.data())\ndef test_collection_size_from_slice(data):\n    t = Annotated[MyCollection, \"we just ignore this\", slice(1, 10)]\n    value = data.draw(st.from_type(t))\n    assert 1 <= len(value) <= 10\n\n\ndef test_unhashable_annotated_metadata():\n    t = Annotated[int, {\"key\": \"value\"}]\n    assert_simple_property(st.from_type(t), lambda x: isinstance(x, int))\n\n\nclass GroupedStuff:\n    __is_annotated_types_grouped_metadata__ = True\n\n    def __init__(self, *args) -> None:\n        self._args = args\n\n    def __iter__(self):\n        return iter(self._args)\n\n    def __repr__(self) -> str:\n        return f\"GroupedStuff({', '.join(map(repr, self._args))})\"\n\n\ndef test_flattens_grouped_metadata():\n    grp = GroupedStuff(GroupedStuff(GroupedStuff(at.Len(min_length=1, max_length=5))))\n    constraints = list(_get_constraints(grp))\n    assert constraints == [at.MinLen(1), at.MaxLen(5)]\n\n\ntry:\n    # we can drop this ugly code when Python 3.10 reaches EOL\n    from typing import NotRequired, TypedDict\nexcept ImportError:\n    pass\nelse:\n\n    class TypedDictWithAnnotations(TypedDict):\n        x: Annotated[int, at.Ge(0)]\n        y: Annotated[NotRequired[int], at.Ge(0)]\n        z: NotRequired[Annotated[int, at.Ge(0)]]\n\n    @given(st.from_type(TypedDictWithAnnotations))\n    def test_typeddict_with_annotated_constraints(value):\n        assert value[\"x\"] >= 0\n        assert value.get(\"y\", 0) >= 0\n        assert value.get(\"z\", 0) >= 0\n"
  },
  {
    "path": "hypothesis-python/tests/typing_extensions/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/typing_extensions/test_backported_types.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport collections\nfrom collections.abc import Callable\nfrom typing import Annotated, Concatenate, DefaultDict, NewType, TypeGuard, Union\n\nimport pytest\nimport typing_extensions\nfrom typing_extensions import (\n    LiteralString,\n    NotRequired,\n    ParamSpec,\n    ReadOnly,\n    Required,\n    TypedDict,\n    TypeIs,\n)\n\nfrom hypothesis import HealthCheck, assume, given, settings, strategies as st\nfrom hypothesis.errors import InvalidArgument\nfrom hypothesis.strategies import from_type\nfrom hypothesis.strategies._internal.types import NON_RUNTIME_TYPES\n\nfrom tests.common.debug import (\n    assert_all_examples,\n    assert_simple_property,\n    check_can_generate_examples,\n    find_any,\n)\n\n# we'll continue testing the typing variants until their removal from the stdlib\n# ruff: noqa: UP035, UP006, UP007\n\n# See also nocover/test_type_lookup.py\n\n\n@pytest.mark.parametrize(\"value\", [\"dog\", b\"goldfish\", 42, 63.4, -80.5, False])\ndef test_typing_extensions_Literal(value):\n    assert_simple_property(\n        from_type(typing_extensions.Literal[value]), lambda v: v == value\n    )\n\n\n@given(st.data())\ndef test_typing_extensions_Literal_nested(data):\n    lit = typing_extensions.Literal\n    values = [\n        (lit[\"hamster\", 0], (\"hamster\", 0)),\n        (lit[26, False, \"bunny\", 130], (26, False, \"bunny\", 130)),\n        (lit[lit[1]], {1}),\n        (lit[lit[1], 2], {1, 2}),\n        (lit[1, lit[2], 3], {1, 2, 3}),\n        (lit[lit[lit[1], lit[2]], lit[lit[3], lit[4]]], {1, 2, 3, 4}),\n        # See https://github.com/HypothesisWorks/hypothesis/pull/2886\n        (Union[lit[\"hamster\"], lit[\"bunny\"]], {\"hamster\", \"bunny\"}),  # noqa\n        (Union[lit[lit[1], lit[2]], lit[lit[3], lit[4]]], {1, 2, 3, 4}),\n    ]\n    literal_type, flattened_literals = data.draw(st.sampled_from(values))\n    assert data.draw(st.from_type(literal_type)) in flattened_literals\n\n\nclass A(TypedDict):\n    a: int\n\n\n@given(from_type(A))\ndef test_simple_typeddict(value):\n    assert type(value) == dict\n    assert set(value) == {\"a\"}\n    assert isinstance(value[\"a\"], int)\n\n\ndef test_typing_extensions_Type_int():\n    assert_simple_property(from_type(type[int]), lambda v: v is int)\n\n\n@given(from_type(Union[type[str], type[list]]))\ndef test_typing_extensions_Type_Union(ex):\n    assert ex in (str, list)\n\n\ndef test_resolves_NewType():\n    typ = NewType(\"T\", int)\n    nested = NewType(\"NestedT\", typ)\n    uni = NewType(\"UnionT\", Union[int, None])\n    uni_new = NewType(\"UnionT\", int | None)\n    assert_simple_property(from_type(typ), lambda x: isinstance(x, int))\n    assert_simple_property(from_type(nested), lambda x: isinstance(x, int))\n    assert_simple_property(from_type(uni), lambda x: isinstance(x, (int, type(None))))\n    assert_simple_property(\n        from_type(uni_new), lambda x: isinstance(x, (int, type(None)))\n    )\n    find_any(from_type(uni), lambda x: isinstance(x, int))\n    find_any(from_type(uni), lambda x: isinstance(x, type(None)))\n\n\n@given(from_type(DefaultDict[int, int]) | from_type(collections.defaultdict[int, int]))\ndef test_defaultdict(ex):\n    assert isinstance(ex, collections.defaultdict)\n    assume(ex)\n    assert all(isinstance(elem, int) for elem in ex)\n    assert all(isinstance(elem, int) for elem in ex.values())\n\n\n@pytest.mark.parametrize(\"non_runtime_type\", NON_RUNTIME_TYPES)\ndef test_non_runtime_type_cannot_be_resolved(non_runtime_type):\n    strategy = st.from_type(non_runtime_type)\n    with pytest.raises(\n        InvalidArgument, match=\"there is no such thing as a runtime instance\"\n    ):\n        check_can_generate_examples(strategy)\n\n\n@pytest.mark.parametrize(\"non_runtime_type\", NON_RUNTIME_TYPES)\ndef test_non_runtime_type_cannot_be_registered(non_runtime_type):\n    with pytest.raises(\n        InvalidArgument, match=\"there is no such thing as a runtime instance\"\n    ):\n        st.register_type_strategy(non_runtime_type, st.none())\n\n\ndef test_callable_with_concatenate():\n    P = ParamSpec(\"P\")\n    func_type = Callable[Concatenate[int, P], None]\n    strategy = st.from_type(func_type)\n    with pytest.raises(\n        InvalidArgument,\n        match=\"Hypothesis can't yet construct a strategy for instances of a Callable type\",\n    ):\n        check_can_generate_examples(strategy)\n\n    with pytest.raises(InvalidArgument, match=\"Cannot register generic type\"):\n        st.register_type_strategy(func_type, st.none())\n\n\ndef test_callable_with_paramspec():\n    P = ParamSpec(\"P\")\n    func_type = Callable[P, None]\n    strategy = st.from_type(func_type)\n    with pytest.raises(\n        InvalidArgument,\n        match=\"Hypothesis can't yet construct a strategy for instances of a Callable type\",\n    ):\n        check_can_generate_examples(strategy)\n\n    with pytest.raises(InvalidArgument, match=\"Cannot register generic type\"):\n        st.register_type_strategy(func_type, st.none())\n\n\n@pytest.mark.parametrize(\"typ\", [TypeGuard, TypeIs])\ndef test_callable_return_typegard_type(typ):\n    strategy = st.from_type(Callable[[], typ[int]])\n    with pytest.raises(\n        InvalidArgument,\n        match=\"Hypothesis cannot yet construct a strategy for callables \"\n        \"which are PEP-647 TypeGuards or PEP-742 TypeIs\",\n    ):\n        check_can_generate_examples(strategy)\n\n    with pytest.raises(InvalidArgument, match=\"Cannot register generic type\"):\n        st.register_type_strategy(Callable[[], typ[int]], st.none())\n\n\nclass Movie(TypedDict):  # implicitly total=True\n    title: str\n    year: NotRequired[int]\n\n\n@given(from_type(Movie))\ndef test_typeddict_not_required(value):\n    assert type(value) == dict\n    assert set(value).issubset({\"title\", \"year\"})\n    assert isinstance(value[\"title\"], str)\n    if \"year\" in value:\n        assert isinstance(value[\"year\"], int)\n\n\ndef test_typeddict_not_required_can_skip():\n    find_any(from_type(Movie), lambda movie: \"year\" not in movie)\n\n\nclass OtherMovie(TypedDict, total=False):\n    title: Required[str]\n    year: int\n\n\n@given(from_type(OtherMovie))\ndef test_typeddict_required(value):\n    assert type(value) == dict\n    assert set(value).issubset({\"title\", \"year\"})\n    assert isinstance(value[\"title\"], str)\n    if \"year\" in value:\n        assert isinstance(value[\"year\"], int)\n\n\ndef test_typeddict_required_must_have():\n    assert_all_examples(from_type(OtherMovie), lambda movie: \"title\" in movie)\n\n\nclass Story(TypedDict, total=True):\n    author: str\n\n\nclass Book(Story, total=False):\n    pages: int\n\n\nclass Novel(Book):\n    genre: Required[str]\n    rating: NotRequired[str]\n\n\n@pytest.mark.parametrize(\n    \"check,condition\",\n    [\n        pytest.param(\n            assert_all_examples,\n            lambda novel: \"author\" in novel,\n            id=\"author-is-required\",\n        ),\n        pytest.param(\n            assert_all_examples, lambda novel: \"genre\" in novel, id=\"genre-is-required\"\n        ),\n        pytest.param(\n            find_any, lambda novel: \"pages\" in novel, id=\"pages-may-be-present\"\n        ),\n        pytest.param(\n            find_any, lambda novel: \"pages\" not in novel, id=\"pages-may-be-absent\"\n        ),\n        pytest.param(\n            find_any, lambda novel: \"rating\" in novel, id=\"rating-may-be-present\"\n        ),\n        pytest.param(\n            find_any, lambda novel: \"rating\" not in novel, id=\"rating-may-be-absent\"\n        ),\n    ],\n)\ndef test_required_and_not_required_keys(check, condition):\n    check(from_type(Novel), condition)\n\n\nclass DeeplyNestedQualifiers(TypedDict):\n    a: ReadOnly[Required[int]]\n    b: NotRequired[Annotated[ReadOnly[int], \"metadata\"]]\n    c: Annotated[ReadOnly[NotRequired[str]], \"metadata\"]\n\n\n@pytest.mark.parametrize(\n    \"check,condition\",\n    [\n        pytest.param(\n            assert_all_examples,\n            lambda novel: \"a\" in novel,\n            id=\"a-is-required\",\n        ),\n        pytest.param(find_any, lambda novel: \"b\" in novel, id=\"b-may-be-present\"),\n        pytest.param(find_any, lambda novel: \"b\" not in novel, id=\"b-may-be-absent\"),\n        pytest.param(find_any, lambda novel: \"c\" in novel, id=\"c-may-be-present\"),\n        pytest.param(find_any, lambda novel: \"c\" not in novel, id=\"c-may-be-absent\"),\n    ],\n)\ndef test_required_and_not_required_keys_deeply_nested(check, condition):\n    check(from_type(DeeplyNestedQualifiers), condition)\n\n\ndef test_typeddict_error_msg():\n    with pytest.raises(TypeError, match=\"is not valid as type argument\"):\n\n        class Foo(TypedDict):\n            attr: Required\n\n    with pytest.raises(TypeError, match=\"is not valid as type argument\"):\n\n        class Bar(TypedDict):\n            attr: NotRequired\n\n    with pytest.raises(TypeError, match=\"is not valid as type argument\"):\n\n        class Baz(TypedDict):\n            attr: ReadOnly\n\n\ndef test_literal_string_is_just_a_string():\n    assert_all_examples(from_type(LiteralString), lambda thing: isinstance(thing, str))\n\n\nclass Foo:\n    def __init__(self, x):\n        pass\n\n\nclass Bar(Foo):\n    pass\n\n\nclass Baz(Foo):\n    pass\n\n\nst.register_type_strategy(Bar, st.builds(Bar, st.integers()))\nst.register_type_strategy(Baz, st.builds(Baz, st.integers()))\n\nT = typing_extensions.TypeVar(\"T\")\nT_int = typing_extensions.TypeVar(\"T_int\", bound=int)\n\n\n@pytest.mark.parametrize(\n    \"var,expected\",\n    [\n        (typing_extensions.TypeVar(\"V\"), object),\n        # Bound:\n        (typing_extensions.TypeVar(\"V\", bound=int), int),\n        (typing_extensions.TypeVar(\"V\", bound=Foo), (Bar, Baz)),\n        (typing_extensions.TypeVar(\"V\", bound=Union[int, str]), (int, str)),\n        (typing_extensions.TypeVar(\"V\", bound=int | str), (int, str)),\n        # Constraints:\n        (typing_extensions.TypeVar(\"V\", int, str), (int, str)),\n        # Default:\n        (typing_extensions.TypeVar(\"V\", default=int), int),\n        (typing_extensions.TypeVar(\"V\", default=T), object),\n        (typing_extensions.TypeVar(\"V\", default=Foo), (Bar, Baz)),\n        (typing_extensions.TypeVar(\"V\", default=Union[int, str]), (int, str)),\n        (typing_extensions.TypeVar(\"V\", default=int | str), (int, str)),\n        (typing_extensions.TypeVar(\"V\", default=T_int), int),\n        (typing_extensions.TypeVar(\"V\", default=T_int, bound=int), int),\n        (typing_extensions.TypeVar(\"V\", int, str, default=int), (int, str)),\n        # This case is not correct from typing's perspective, but its not\n        # our job to very this, static type-checkers should do that:\n        (typing_extensions.TypeVar(\"V\", default=T_int, bound=str), (int, str)),\n    ],\n)\n@settings(suppress_health_check=[HealthCheck.too_slow])\n@given(data=st.data())\ndef test_typevar_type_is_consistent(data, var, expected):\n    strat = st.from_type(var)\n    v1 = data.draw(strat)\n    v2 = data.draw(strat)\n    assume(v1 != v2)  # Values may vary, just not types\n    assert type(v1) == type(v2)\n    assert isinstance(v1, expected)\n"
  },
  {
    "path": "hypothesis-python/tests/watchdog/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hypothesis-python/tests/watchdog/test_database.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport sys\nimport time\nfrom collections import Counter\n\nimport pytest\n\nfrom hypothesis import Phase, settings\nfrom hypothesis.database import (\n    DirectoryBasedExampleDatabase,\n    InMemoryExampleDatabase,\n    MultiplexedDatabase,\n)\n\nfrom tests.common.utils import flaky, skipif_threading, wait_for\nfrom tests.cover.test_database_backend import _database_conforms_to_listener_api\n\n# Our database listener tests are tantalizingly close to being useful, but are\n# still subtly flaky. I have spent two afternoons trying to isolate the problem\n# and have concluded it would require sitting down at a deep level with not only\n# the watchdog implementation but also platform-specific filesystem watcher details.\n#\n# I've seen issues like duplicate events being emitted, stopping/starting a listener\n# in quick succession repeating the previous batch of events, and other weirdness.\n#\n# These tests are still useful as a manual check when changing database listener\n# code, and as an encoding of our desired semantics.\npytestmark = pytest.mark.skip(reason=\"see comment\")\n\n\n# we need real time here, not monkeypatched for CI\ntime_sleep = time.sleep\n\n\ndef test_database_listener_directory():\n    _database_conforms_to_listener_api(\n        lambda path: DirectoryBasedExampleDatabase(path),\n        supports_value_delete=False,\n        parent_settings=settings(\n            # this test is very expensive because we wait between every rule for\n            # the filesystem observer to fire.\n            max_examples=5,\n            stateful_step_count=10,\n            # expensive runtime makes shrinking take forever\n            phases=set(Phase) - {Phase.shrink},\n            deadline=None,\n        ),\n    )\n\n\n# seen flaky on test-win; we get *three* of the same save events in the first\n# assertion, which...is baffling, and possibly a genuine bug (most likely in\n# watchdog).\n@skipif_threading  # add_listener is not thread safe because watchdog is not\ndef test_database_listener_multiplexed(tmp_path):\n    db = MultiplexedDatabase(\n        InMemoryExampleDatabase(), DirectoryBasedExampleDatabase(tmp_path)\n    )\n    events = []\n\n    def listener(event):\n        events.append(event)\n\n    db.add_listener(listener)\n    time_sleep(0.1)\n\n    db.save(b\"a\", b\"a\")\n    wait_for(lambda: events == [(\"save\", (b\"a\", b\"a\"))] * 2, timeout=30)\n\n    db.remove_listener(listener)\n    db.delete(b\"a\", b\"a\")\n    db.save(b\"a\", b\"b\")\n    wait_for(lambda: events == [(\"save\", (b\"a\", b\"a\"))] * 2, timeout=30)\n\n    db.add_listener(listener)\n    time_sleep(0.1)\n\n    db.delete(b\"a\", b\"b\")\n    db.save(b\"a\", b\"c\")\n    # InMemory database fires immediately, while DirectoryBased has to\n    # wait for filesystem listeners. Therefore the events can arrive out of\n    # order. Test a weaker multiset property, disregarding ordering.\n    wait_for(\n        lambda: Counter(events[2:])\n        == {\n            # InMemory\n            (\"delete\", (b\"a\", b\"b\")): 1,\n            # DirectoryBased\n            (\"delete\", (b\"a\", None)): 1,\n            # both\n            (\"save\", (b\"a\", b\"c\")): 2,\n        },\n        timeout=30,\n    )\n\n\n@skipif_threading  # add_listener is not thread safe because watchdog is not\ndef test_database_listener_directory_explicit(tmp_path):\n    db = DirectoryBasedExampleDatabase(tmp_path)\n    events = []\n\n    def listener(event):\n        events.append(event)\n\n    time_sleep(0.1)\n    db.add_listener(listener)\n    time_sleep(0.1)\n\n    db.save(b\"k1\", b\"v1\")\n    wait_for(lambda: events == [(\"save\", (b\"k1\", b\"v1\"))], timeout=30)\n\n    time_sleep(0.1)\n    db.remove_listener(listener)\n    time_sleep(0.1)\n\n    db.delete(b\"k1\", b\"v1\")\n    db.save(b\"k1\", b\"v2\")\n    wait_for(lambda: events == [(\"save\", (b\"k1\", b\"v1\"))], timeout=30)\n\n    time_sleep(0.1)\n    db.add_listener(listener)\n    time_sleep(0.1)\n\n    db.delete(b\"k1\", b\"v2\")\n    db.save(b\"k1\", b\"v3\")\n    wait_for(\n        lambda: events[1:]\n        == [\n            (\"delete\", (b\"k1\", None)),\n            (\"save\", (b\"k1\", b\"v3\")),\n        ],\n        timeout=30,\n    )\n\n    # moving into a nonexistent key\n    db.move(b\"k1\", b\"k2\", b\"v3\")\n    time_sleep(0.5)\n    # moving back into an existing key\n    db.move(b\"k2\", b\"k1\", b\"v3\")\n    time_sleep(0.5)\n\n    if sys.platform.startswith(\"darwin\"):\n        assert events[3:] == [\n            (\"delete\", (b\"k1\", b\"v3\")),\n            (\"save\", (b\"k2\", b\"v3\")),\n            (\"delete\", (b\"k2\", b\"v3\")),\n            (\"save\", (b\"k1\", b\"v3\")),\n        ], str(events[3:])\n    elif sys.platform.startswith(\"win\"):\n        # watchdog fires save/delete events instead of move events on windows.\n        # This means we don't broadcast the exact deleted value.\n        assert events[3:] == [\n            (\"delete\", (b\"k1\", None)),\n            (\"save\", (b\"k2\", b\"v3\")),\n            (\"delete\", (b\"k2\", None)),\n            (\"save\", (b\"k1\", b\"v3\")),\n        ], str(events[3:])\n    elif sys.platform.startswith(\"linux\"):\n        # move #1\n        assert (\"save\", (b\"k2\", b\"v3\")) in events\n        # sometimes watchdog fires a move event (= save + delete with value),\n        # and other times it fires separate save and delete events (= delete with\n        # no value). I think this is due to particulars of what happens when\n        # a new directory gets created very close to the time when a file is\n        # saved to that directory.\n        assert any((\"delete\", (b\"k1\", val)) in events for val in [b\"v3\", None])\n\n        # move #2\n        assert (\"save\", (b\"k1\", b\"v3\")) in events\n        assert any((\"delete\", (b\"k2\", val)) in events for val in [b\"v3\", None])\n    else:\n        raise NotImplementedError(f\"unknown platform {sys.platform}\")\n\n\n@flaky(max_runs=5, min_passes=1)  # time_sleep(0.1) probably isn't enough here\n@skipif_threading  # add_listener is not thread safe because watchdog is not\ndef test_database_listener_directory_move(tmp_path):\n    db = DirectoryBasedExampleDatabase(tmp_path)\n    events = []\n\n    def listener(event):\n        events.append(event)\n\n    # make sure both keys exist and that v1 exists in k1 and not k2\n    db.save(b\"k1\", b\"v1\")\n    db.save(b\"k2\", b\"v_unrelated\")\n\n    time_sleep(0.1)\n    db.add_listener(listener)\n    time_sleep(0.1)\n\n    db.move(b\"k1\", b\"k2\", b\"v1\")\n    # events might arrive in either order\n    wait_for(\n        lambda: set(events)\n        == {\n            (\"save\", (b\"k2\", b\"v1\")),\n            # windows doesn't fire move events, so value is None\n            (\"delete\", (b\"k1\", None if sys.platform.startswith(\"win\") else b\"v1\")),\n        },\n        timeout=30,\n    )\n\n\n@skipif_threading  # add_listener is not thread safe because watchdog is not\ndef test_still_listens_if_directory_did_not_exist(tmp_path):\n    # if we start listening on a nonexistent path, we will create that path and\n    # still listen for events\n    events = []\n\n    def listener(event):\n        events.append(event)\n\n    p = tmp_path / \"does_not_exist_yet\"\n    db = DirectoryBasedExampleDatabase(p)\n    assert not p.exists()\n\n    db.add_listener(listener)\n    assert p.exists()\n\n    assert not events\n    db.save(b\"k1\", b\"v1\")\n    wait_for(lambda: len(events) == 1, timeout=30)\n"
  },
  {
    "path": "hypothesis-python/tests/watchdog/test_database_cover.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesis.database import (\n    DirectoryBasedExampleDatabase,\n    InMemoryExampleDatabase,\n    MultiplexedDatabase,\n)\n\nfrom tests.common.utils import skipif_threading\n\n# trivial covering tests as a stopgap while we skip our proper database listener\n# tests. Can be removed when we re-enable those.\n\n\n@skipif_threading\ndef test_start_stop_multiplexed_listener(tmp_path):\n    db = MultiplexedDatabase(\n        InMemoryExampleDatabase(), DirectoryBasedExampleDatabase(tmp_path)\n    )\n    listener = lambda event: None\n    db.add_listener(listener)\n    db.remove_listener(listener)\n\n\n@skipif_threading\ndef test_start_stop_directory_listener(tmp_path):\n    db = DirectoryBasedExampleDatabase(tmp_path)\n    listener = lambda event: None\n    db.add_listener(listener)\n    db.remove_listener(listener)\n"
  },
  {
    "path": "hypothesis-python/tox.ini",
    "content": "[tox]\nenvlist = py{310,py310,311,py311,312,313,313t,314,314t,315,315t}-{brief,full,cover,rest,nocover,niche,custom}\ntoxworkdir={env:TOX_WORK_DIR:.tox}\n\n[testenv]\nbasepython={env:TOX_PYTHON_VERSION:python3}\ndeps =\n    -r../requirements/test.txt\nextras =\n    zoneinfo\nallowlist_externals =\n    bash\npassenv=\n    HOME\n    LC_ALL\n    COVERAGE_FILE\n    TOXENV\n    # Allow CI builds (or user builds) to force coloured terminal output.\n    PY_COLORS\nsetenv =\n    # If PY...ING is set in calling environment, use that; default to 1\n    # If PY...ING is set in calling environment, use that; default to 1\n    PYTHONWARNDEFAULTENCODING={env:PYTHONWARNDEFAULTENCODING:1}\n    brief: HYPOTHESIS_PROFILE=speedy\ncommands =\n    full: bash scripts/basic-test.sh\n    brief: python -bb -X dev -m pytest -n auto tests/cover/test_testdecorators.py {posargs}\n    cover: python -bb -X dev -m pytest -n auto tests/cover/ tests/pytest/ tests/conjecture/ {posargs}\n    rest: python -bb -X dev -m pytest -n auto tests/ --ignore=tests/cover/ --ignore=tests/pytest/ --ignore=tests/conjecture/ --ignore=tests/nocover/ --ignore=tests/quality/ --ignore=tests/ghostwriter/ --ignore=tests/patching/ --ignore=tests/crosshair/test_crosshair.py {posargs}\n    conjecture: python -bb -X dev -m pytest -n auto tests/conjecture/ {posargs}\n    nocover: python -bb -X dev -m pytest -n auto tests/nocover/ {posargs}\n    niche: bash scripts/other-tests.sh\n    custom: python -bb -X dev -m pytest {posargs}\n\n[testenv:py310-pyjion]\ndeps =\n    -r../requirements/test.txt\n    # We'd like to pin this, but pip-compile has to run under Python 3.10 (+)\n    # to do so and that's painful because other tools aren't compatible yet.\n    # If it's mid-2022, try again, starting by updating ci_version to 3.10\n    pyjion\ncommands =\n    # TODO: restore `-n auto` https://github.com/tonybaloney/Pyjion/issues/456\n    # TODO: re-enable in Actions main.yml once this actually works\n    pyjion -m pytest tests/cover tests/pytest tests/nocover\n\n[testenv:quality]\ndeps=\n    -r../requirements/test.txt\ncommands=\n    python -bb -X dev -m pytest tests/quality/ -n auto\n\n# This test job runs on the oldest version of CPython we support, against the minimum\n# version specified in our runtime dependencies.  For now, that's the oldest version\n# with a wheel for non-EOL Python.  In future we might deprecate faster per NEP-29.\n[testenv:py310-oldestnumpy]\ndeps=\n    -r../requirements/test.txt\nallowlist_externals =\n    bash\ncommands_pre =\n    bash -c \"pip install --only-binary=:all: numpy==$(grep -m 1 'numpy>=' pyproject.toml | grep -oE '[0-9.]+')\"\ncommands =\n    python -bb -X dev -m pytest tests/numpy/ -n auto\n\n# This test job runs against the nightly version of `numpy`\n[testenv:numpy-nightly]\ndeps=\n    -r../requirements/test.txt\n    pandas\n    black\n    click\n    attrs  # ghostwriter has an attrs test\nallowlist_externals =\n    bash\ncommands_pre =\n    bash -c \"pip install --upgrade --pre --only-binary :all: -i https://pypi.anaconda.org/scientific-python-nightly-wheels/simple numpy\"\ncommands =\n    python -bb -X dev -m pytest tests/numpy/ tests/array_api/ tests/pandas/ tests/ghostwriter/ tests/conjecture/ tests/cover -n auto {posargs}\n\n# Note: when adding or removing tested Pandas versions, make sure to update the\n# docs in numpy.rst too.  To see current download rates of each minor version:\n# https://pepy.tech/project/pandas?versions=1.1.*&versions=1.2.*&versions=1.3.*&versions=1.4.*&versions=1.5.*&versions=2.0.*&versions=2.1.*&versions=2.2.*\n[testenv:py310-pandas11]\ndeps =\n    -r../requirements/test.txt\n    numpy~=1.26.4\n    pandas~=1.1.5\ncommands =\n    python -bb -X dev -m pytest tests/pandas -n auto\n\n[testenv:py310-pandas12]\ndeps =\n    -r../requirements/test.txt\n    numpy~=1.26.4\n    pandas~=1.2.5\ncommands =\n    python -bb -X dev -m pytest tests/pandas -n auto\n\n[testenv:py310-pandas13]\ndeps =\n    -r../requirements/test.txt\n    numpy~=1.26.4\n    pandas~=1.3.5\ncommands =\n    python -bb -X dev -m pytest tests/pandas -n auto\n\n[testenv:py310-pandas14]\ndeps =\n    -r../requirements/test.txt\n    numpy~=1.26.4\n    pandas~=1.4.4\ncommands =\n    python -bb -X dev -m pytest tests/pandas -n auto\n\n[testenv:py311-pandas15]\ndeps =\n    -r../requirements/test.txt\n    numpy~=1.26.4\n    pandas~=1.5.3\ncommands =\n    python -bb -X dev -m pytest tests/pandas -n auto\n\n[testenv:py311-pandas20]\ndeps =\n    -r../requirements/test.txt\n    numpy~=1.26.4\n    pandas~=2.0.3\ncommands =\n    python -bb -X dev -m pytest tests/pandas -n auto\n\n[testenv:py312-pandas21]\ndeps =\n    -r../requirements/test.txt\n    numpy~=1.26.4\n    pandas~=2.1.4\nsetenv=\n    PYTHONWARNDEFAULTENCODING=1\ncommands =\n    python -bb -X dev -m pytest tests/pandas -n auto\n\n[testenv:py313-pandas22]\ndeps =\n    -r../requirements/test.txt\n    pandas~=2.2.2\n    # https://pandas.pydata.org/docs/whatsnew/v2.2.2.html#pandas-2-2-2-is-now-compatible-with-numpy-2-0\nsetenv=\n    PYTHONWARNDEFAULTENCODING=1\ncommands =\n    python -bb -X dev -m pytest tests/pandas -n auto\n\n# Adding a new pandas?  See comment above!\n\n[testenv:rest]\ndeps =\n    -r../requirements/coverage.txt\n    -r../requirements/crosshair.txt\n\n[testenv:alt-{rest,nocover}]\ndeps =\n    -r../requirements/test.txt\n    -r../requirements/crosshair.txt  # for conformance test\n    numpy==1.26.4\n    pandas==2.0.3  # latest available as x86 binary wheel\nallowlist_externals =\n    bash\ncommands_pre =\n    bash -c \"grep -v 'numpy=\\|pandas=\\|pyarrow=' ../requirements/coverage.txt >coverage-mod.txt\"\n    pip install -r coverage-mod.txt\n\n[testenv:crosshair-{cover,nocover,niche,custom}]\ndeps =\n    -r../requirements/test.txt\n    -r../requirements/crosshair.txt\nallowlist_externals =\n    bash\nsetenv=\n    HYPOTHESIS_PROFILE=crosshair\ncommands =\n    # invoke with `./build.sh check-crosshair-cover -- -x -Wignore`\n    cover: python -bb -X dev -m pytest -n auto tests/cover/ tests/pytest/ {posargs}\n    nocover: python -bb -X dev -m pytest -n auto tests/nocover/ {posargs}\n    niche: bash scripts/other-tests.sh\n    custom: python -bb -X dev -m pytest {posargs}\n\n[testenv:django{42,52,60,-nocontrib}]\nsetenv=\n    PYTHONWARNDEFAULTENCODING=1\n    DJANGO_SETTINGS_MODULE=tests.django.toys.settings.settings\n    nocontrib: DJANGO_SETTINGS_MODULE=tests.django.toys.settings.settings_no_contrib\ndeps=\n    -r../requirements/test.txt\n    django42: django==4.2.29\n    django52: django==5.2.12\n    django60: django==6.0.3\n    django-nocontrib: django==6.0.3\ncommands =\n    python -bb -X dev -m tests.django.manage test tests.django {posargs}\n\n[testenv:py{39}-pytest54]\ndeps =\n    -r../requirements/test.txt\ncommands_pre =\n    pip install pytest==5.4.3 pytest-xdist\ncommands =\n    python -bb -X dev -m pytest tests/pytest tests/cover/test_testdecorators.py\n\n[testenv:pytest62]\ndeps =\n    -r../requirements/test.txt\nsetenv=\n    PYTHONWARNDEFAULTENCODING=\ncommands_pre =\n    pip install pytest==6.2.5 pytest-xdist\ncommands =\n    python -bb -X dev -m pytest tests/pytest tests/cover/test_testdecorators.py\n\n[testenv:pytest74]\ndeps =\n    -r../requirements/test.txt\ncommands_pre =\n    pip install pytest==7.4.4 pytest-xdist\ncommands =\n    python -bb -X dev -m pytest tests/pytest tests/cover/test_testdecorators.py\n\n[testenv:pytest84]\ndeps =\n    -r../requirements/test.txt\ncommands_pre =\n    pip install pytest==8.4.2 pytest-xdist\ncommands =\n    python -bb -X dev -m pytest tests/pytest tests/cover/test_testdecorators.py\n\n[testenv:pytest9]\ndeps =\n    -r../requirements/test.txt\ncommands_pre =\n    pip install pytest==9.* pytest-xdist\ncommands =\n    python -bb -X dev -m pytest tests/pytest tests/cover/test_testdecorators.py\n\n[testenv:threading]\ndeps =\n    -r../requirements/test.txt\n    # in pytest-run-parallel==0.7.0, python3.10 + pytest-run-parallel + xdist does\n    # not collect any tests. I don't know why.\n    pytest-run-parallel==0.6.0\nsetenv=\n    PYTHONWARNDEFAULTENCODING=1\n    HYPOTHESIS_PROFILE=threading\ncommands =\n    python -bb -X dev -m pytest -n auto tests/cover --parallel-threads 3 --skip-thread-unsafe true {posargs}\n\n[testenv:coverage]\ndeps =\n    -r../requirements/coverage.txt\nallowlist_externals =\n    rm\nsetenv=\n    PYTHONWARNDEFAULTENCODING=1\n    HYPOTHESIS_INTERNAL_COVERAGE=true\n    COVERAGE_PROCESS_START=.coveragerc\ncommands_pre =\n    rm -f branch-check*\n    pip install .[zoneinfo]\n    pip install coverage_enable_subprocess\ncommands_post =\n    pip uninstall -y coverage_enable_subprocess\n# Produce a coverage report even if the test suite fails.\n# (The tox task will still count as failed.)\nignore_errors = true\n# We've had problems correctly measuring coverage using pytest-cov when running\n# in parallel, so instead we start coverage implicitly on all (sub-)processes by\n# way of the coverage_enable_subprocesses installation. This requires all options\n# to be set in .coveragerc (including source), but that's ok as it is overridden\n# by --cov=... in conjecture-coverage.\ncommands =\n    python -bb -X dev -m pytest -n auto --ff {posargs} \\\n        tests/cover tests/conjecture tests/datetime tests/numpy tests/pandas tests/lark \\\n        tests/redis tests/dpcontracts tests/codemods tests/typing_extensions tests/patching \\\n        tests/test_annotated_types.py tests/watchdog\n    python -m coverage combine\n    python -m coverage report\n    python scripts/validate_branch_check.py\n\n[testenv:conjecture-coverage]\ndeps =\n    -r../requirements/coverage.txt\nsetenv=\n    PYTHONWARNDEFAULTENCODING=1\n    HYPOTHESIS_INTERNAL_COVERAGE=true\ncommands =\n    python -bb -X dev \\\n        -m pytest -n auto tests/conjecture/ \\\n        --cov=hypothesis.internal.conjecture --cov-config=.coveragerc {posargs}\n\n\n[testenv:examples3]\ndeps=\n    -r../requirements/test.txt\ncommands_pre =\n    python -m pip install --editable examples/example_hypothesis_entrypoint\ncommands =\n    python -bb -X dev -m pytest examples\n"
  },
  {
    "path": "notebooks/Designing a better simplifier.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Designing a better simplifier\\n\",\n    \"\\n\",\n    \"This is a notebook talking through some of the considerations in the design of Hypothesis's approach to simplification.\\n\",\n    \"\\n\",\n    \"It doesn't perfectly mirror what actually happens in Hypothesis, but it should give some consideration to the sort of things that Hypothesis does and why it takes a particular approach.\\n\",\n    \"\\n\",\n    \"In order to simplify the scope of this document we are only going to\\n\",\n    \"concern ourselves with lists of integers. There are a number of API considerations involved in expanding beyond that point, however most of the algorithmic considerations are the same.\\n\",\n    \"\\n\",\n    \"The big difference between lists of integers and the general case is that integers can never be too complex. In particular we will rapidly get to the point where individual elements can be simplified in usually only log(n) calls. When dealing with e.g. lists of lists this is a much more complicated proposition. That may be covered in another notebook.\\n\",\n    \"\\n\",\n    \"Our objective here is to minimize the number of times we check the condition. We won't be looking at actual timing performance, because usually the speed of the condition is the bottleneck there (and where it's not, everything is fast enough that we need not worry).\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"def greedy_shrink(ls, constraint, shrink):\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    This is the \\\"classic\\\" QuickCheck algorithm which takes a shrink function\\n\",\n    \"    which will iterate over simpler versions of an example. We are trying\\n\",\n    \"    to find a local minima: That is an example ls such that condition(ls)\\n\",\n    \"    is True but that constraint(t) is False for each t in shrink(ls).\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    while True:\\n\",\n    \"        for s in shrink(ls):\\n\",\n    \"            if constraint(s):\\n\",\n    \"                ls = s\\n\",\n    \"                break\\n\",\n    \"        else:\\n\",\n    \"            return ls\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"def shrink1(ls):\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    This is our prototype shrink function. It is very bad. It makes the\\n\",\n    \"    mistake of only making very small changes to an example each time.\\n\",\n    \"\\n\",\n    \"    Most people write something like this the first time they come to\\n\",\n    \"    implement example shrinking. In particular early Hypothesis very much\\n\",\n    \"    made this mistake.\\n\",\n    \"\\n\",\n    \"    What this does:\\n\",\n    \"\\n\",\n    \"    For each index, if the value of the index is non-zero we try\\n\",\n    \"    decrementing it by 1.\\n\",\n    \"\\n\",\n    \"    We then (regardless of if it's zero) try the list with the value at\\n\",\n    \"    that index deleted.\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    for i in range(len(ls)):\\n\",\n    \"        s = list(ls)\\n\",\n    \"        if s[i] > 0:\\n\",\n    \"            s[i] -= 1\\n\",\n    \"            yield list(s)\\n\",\n    \"        del s[i]\\n\",\n    \"        yield list(s)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 3,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"def show_trace(start, constraint, simplifier):\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    This is a debug function. You shouldn't concern yourself with\\n\",\n    \"    its implementation too much.\\n\",\n    \"\\n\",\n    \"    What it does is print out every intermediate step in applying a\\n\",\n    \"    simplifier (a function of the form (list, constraint) -> list)\\n\",\n    \"    along with whether it is a successful shrink or not.\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    if start is None:\\n\",\n    \"        while True:\\n\",\n    \"            start = gen_list()\\n\",\n    \"            if constraint(start):\\n\",\n    \"                break\\n\",\n    \"\\n\",\n    \"    shrinks = [0]\\n\",\n    \"    tests = [0]\\n\",\n    \"\\n\",\n    \"    def print_shrink(ls):\\n\",\n    \"        tests[0] += 1\\n\",\n    \"        if constraint(ls):\\n\",\n    \"            shrinks[0] += 1\\n\",\n    \"            print(\\\"✓\\\", ls)\\n\",\n    \"            return True\\n\",\n    \"        else:\\n\",\n    \"            print(\\\"✗\\\", ls)\\n\",\n    \"        return False\\n\",\n    \"\\n\",\n    \"    print(\\\"✓\\\", start)\\n\",\n    \"    simplifier(start, print_shrink)\\n\",\n    \"    print()\\n\",\n    \"    print(\\\"%d shrinks with %d function calls\\\" % (shrinks[0], tests[0]))\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 4,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"from functools import partial\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 5,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [5, 5]\\n\",\n      \"✓ [4, 5]\\n\",\n      \"✓ [3, 5]\\n\",\n      \"✓ [2, 5]\\n\",\n      \"✓ [1, 5]\\n\",\n      \"✓ [0, 5]\\n\",\n      \"✗ [5]\\n\",\n      \"✓ [0, 4]\\n\",\n      \"✗ [4]\\n\",\n      \"✓ [0, 3]\\n\",\n      \"✗ [3]\\n\",\n      \"✓ [0, 2]\\n\",\n      \"✗ [2]\\n\",\n      \"✓ [0, 1]\\n\",\n      \"✗ [1]\\n\",\n      \"✓ [0, 0]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0]\\n\",\n      \"\\n\",\n      \"10 shrinks with 17 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace([5, 5], lambda x: len(x) >= 2, partial(greedy_shrink, shrink=shrink1))\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"That worked reasonably well, but it sure was a lot of function calls for such a small amount of shrinking. What would have happened if we'd started with [100, 100]?\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 6,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"def shrink2(ls):\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    Here is an improved shrink function. We first try deleting each element\\n\",\n    \"    and then we try making each element smaller, but we do so from the left\\n\",\n    \"    hand side instead of the right. This means we will always find the\\n\",\n    \"    smallest value that can go in there, but we will do so much sooner.\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    for i in range(len(ls)):\\n\",\n    \"        s = list(ls)\\n\",\n    \"        del s[i]\\n\",\n    \"        yield list(s)\\n\",\n    \"\\n\",\n    \"    for i in range(len(ls)):\\n\",\n    \"        for x in range(ls[i]):\\n\",\n    \"            s = list(ls)\\n\",\n    \"            s[i] = x\\n\",\n    \"            yield s\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 7,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [5, 5]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5]\\n\",\n      \"✓ [0, 5]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [0]\\n\",\n      \"✓ [0, 0]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0]\\n\",\n      \"\\n\",\n      \"2 shrinks with 8 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace([5, 5], lambda x: len(x) >= 2, partial(greedy_shrink, shrink=shrink2))\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"This did indeed reduce the number of function calls significantly - we immediately determine that the value in the cell doesn't matter and we can just put zero there. \\n\",\n    \"\\n\",\n    \"But what would have happened if the value *did* matter?\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 8,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [1000]\\n\",\n      \"✗ []\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [1]\\n\",\n      \"✗ [2]\\n\",\n      \"✗ [3]\\n\",\n      \"✗ [4]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [6]\\n\",\n      \"✗ [7]\\n\",\n      \"✗ [8]\\n\",\n      \"✗ [9]\\n\",\n      \"✗ [10]\\n\",\n      \"✗ [11]\\n\",\n      \"✗ [12]\\n\",\n      \"✗ [13]\\n\",\n      \"✗ [14]\\n\",\n      \"✗ [15]\\n\",\n      \"✗ [16]\\n\",\n      \"✗ [17]\\n\",\n      \"✗ [18]\\n\",\n      \"✗ [19]\\n\",\n      \"✗ [20]\\n\",\n      \"✗ [21]\\n\",\n      \"✗ [22]\\n\",\n      \"✗ [23]\\n\",\n      \"✗ [24]\\n\",\n      \"✗ [25]\\n\",\n      \"✗ [26]\\n\",\n      \"✗ [27]\\n\",\n      \"✗ [28]\\n\",\n      \"✗ [29]\\n\",\n      \"✗ [30]\\n\",\n      \"✗ [31]\\n\",\n      \"✗ [32]\\n\",\n      \"✗ [33]\\n\",\n      \"✗ [34]\\n\",\n      \"✗ [35]\\n\",\n      \"✗ [36]\\n\",\n      \"✗ [37]\\n\",\n      \"✗ [38]\\n\",\n      \"✗ [39]\\n\",\n      \"✗ [40]\\n\",\n      \"✗ [41]\\n\",\n      \"✗ [42]\\n\",\n      \"✗ [43]\\n\",\n      \"✗ [44]\\n\",\n      \"✗ [45]\\n\",\n      \"✗ [46]\\n\",\n      \"✗ [47]\\n\",\n      \"✗ [48]\\n\",\n      \"✗ [49]\\n\",\n      \"✗ [50]\\n\",\n      \"✗ [51]\\n\",\n      \"✗ [52]\\n\",\n      \"✗ [53]\\n\",\n      \"✗ [54]\\n\",\n      \"✗ [55]\\n\",\n      \"✗ [56]\\n\",\n      \"✗ [57]\\n\",\n      \"✗ [58]\\n\",\n      \"✗ [59]\\n\",\n      \"✗ [60]\\n\",\n      \"✗ [61]\\n\",\n      \"✗ [62]\\n\",\n      \"✗ [63]\\n\",\n      \"✗ [64]\\n\",\n      \"✗ [65]\\n\",\n      \"✗ [66]\\n\",\n      \"✗ [67]\\n\",\n      \"✗ [68]\\n\",\n      \"✗ [69]\\n\",\n      \"✗ [70]\\n\",\n      \"✗ [71]\\n\",\n      \"✗ [72]\\n\",\n      \"✗ [73]\\n\",\n      \"✗ [74]\\n\",\n      \"✗ [75]\\n\",\n      \"✗ [76]\\n\",\n      \"✗ [77]\\n\",\n      \"✗ [78]\\n\",\n      \"✗ [79]\\n\",\n      \"✗ [80]\\n\",\n      \"✗ [81]\\n\",\n      \"✗ [82]\\n\",\n      \"✗ [83]\\n\",\n      \"✗ [84]\\n\",\n      \"✗ [85]\\n\",\n      \"✗ [86]\\n\",\n      \"✗ [87]\\n\",\n      \"✗ [88]\\n\",\n      \"✗ [89]\\n\",\n      \"✗ [90]\\n\",\n      \"✗ [91]\\n\",\n      \"✗ [92]\\n\",\n      \"✗ [93]\\n\",\n      \"✗ [94]\\n\",\n      \"✗ [95]\\n\",\n      \"✗ [96]\\n\",\n      \"✗ [97]\\n\",\n      \"✗ [98]\\n\",\n      \"✗ [99]\\n\",\n      \"✗ [100]\\n\",\n      \"✗ [101]\\n\",\n      \"✗ [102]\\n\",\n      \"✗ [103]\\n\",\n      \"✗ [104]\\n\",\n      \"✗ [105]\\n\",\n      \"✗ [106]\\n\",\n      \"✗ [107]\\n\",\n      \"✗ [108]\\n\",\n      \"✗ [109]\\n\",\n      \"✗ [110]\\n\",\n      \"✗ [111]\\n\",\n      \"✗ [112]\\n\",\n      \"✗ [113]\\n\",\n      \"✗ [114]\\n\",\n      \"✗ [115]\\n\",\n      \"✗ [116]\\n\",\n      \"✗ [117]\\n\",\n      \"✗ [118]\\n\",\n      \"✗ [119]\\n\",\n      \"✗ [120]\\n\",\n      \"✗ [121]\\n\",\n      \"✗ [122]\\n\",\n      \"✗ [123]\\n\",\n      \"✗ [124]\\n\",\n      \"✗ [125]\\n\",\n      \"✗ [126]\\n\",\n      \"✗ [127]\\n\",\n      \"✗ [128]\\n\",\n      \"✗ [129]\\n\",\n      \"✗ [130]\\n\",\n      \"✗ [131]\\n\",\n      \"✗ [132]\\n\",\n      \"✗ [133]\\n\",\n      \"✗ [134]\\n\",\n      \"✗ [135]\\n\",\n      \"✗ [136]\\n\",\n      \"✗ [137]\\n\",\n      \"✗ [138]\\n\",\n      \"✗ [139]\\n\",\n      \"✗ [140]\\n\",\n      \"✗ [141]\\n\",\n      \"✗ [142]\\n\",\n      \"✗ [143]\\n\",\n      \"✗ [144]\\n\",\n      \"✗ [145]\\n\",\n      \"✗ [146]\\n\",\n      \"✗ [147]\\n\",\n      \"✗ [148]\\n\",\n      \"✗ [149]\\n\",\n      \"✗ [150]\\n\",\n      \"✗ [151]\\n\",\n      \"✗ [152]\\n\",\n      \"✗ [153]\\n\",\n      \"✗ [154]\\n\",\n      \"✗ [155]\\n\",\n      \"✗ [156]\\n\",\n      \"✗ [157]\\n\",\n      \"✗ [158]\\n\",\n      \"✗ [159]\\n\",\n      \"✗ [160]\\n\",\n      \"✗ [161]\\n\",\n      \"✗ [162]\\n\",\n      \"✗ [163]\\n\",\n      \"✗ [164]\\n\",\n      \"✗ [165]\\n\",\n      \"✗ [166]\\n\",\n      \"✗ [167]\\n\",\n      \"✗ [168]\\n\",\n      \"✗ [169]\\n\",\n      \"✗ [170]\\n\",\n      \"✗ [171]\\n\",\n      \"✗ [172]\\n\",\n      \"✗ [173]\\n\",\n      \"✗ [174]\\n\",\n      \"✗ [175]\\n\",\n      \"✗ [176]\\n\",\n      \"✗ [177]\\n\",\n      \"✗ [178]\\n\",\n      \"✗ [179]\\n\",\n      \"✗ [180]\\n\",\n      \"✗ [181]\\n\",\n      \"✗ [182]\\n\",\n      \"✗ [183]\\n\",\n      \"✗ [184]\\n\",\n      \"✗ [185]\\n\",\n      \"✗ [186]\\n\",\n      \"✗ [187]\\n\",\n      \"✗ [188]\\n\",\n      \"✗ [189]\\n\",\n      \"✗ [190]\\n\",\n      \"✗ [191]\\n\",\n      \"✗ [192]\\n\",\n      \"✗ [193]\\n\",\n      \"✗ [194]\\n\",\n      \"✗ [195]\\n\",\n      \"✗ [196]\\n\",\n      \"✗ [197]\\n\",\n      \"✗ [198]\\n\",\n      \"✗ [199]\\n\",\n      \"✗ [200]\\n\",\n      \"✗ [201]\\n\",\n      \"✗ [202]\\n\",\n      \"✗ [203]\\n\",\n      \"✗ [204]\\n\",\n      \"✗ [205]\\n\",\n      \"✗ [206]\\n\",\n      \"✗ [207]\\n\",\n      \"✗ [208]\\n\",\n      \"✗ [209]\\n\",\n      \"✗ [210]\\n\",\n      \"✗ [211]\\n\",\n      \"✗ [212]\\n\",\n      \"✗ [213]\\n\",\n      \"✗ [214]\\n\",\n      \"✗ [215]\\n\",\n      \"✗ [216]\\n\",\n      \"✗ [217]\\n\",\n      \"✗ [218]\\n\",\n      \"✗ [219]\\n\",\n      \"✗ [220]\\n\",\n      \"✗ [221]\\n\",\n      \"✗ [222]\\n\",\n      \"✗ [223]\\n\",\n      \"✗ [224]\\n\",\n      \"✗ [225]\\n\",\n      \"✗ [226]\\n\",\n      \"✗ [227]\\n\",\n      \"✗ [228]\\n\",\n      \"✗ [229]\\n\",\n      \"✗ [230]\\n\",\n      \"✗ [231]\\n\",\n      \"✗ [232]\\n\",\n      \"✗ [233]\\n\",\n      \"✗ [234]\\n\",\n      \"✗ [235]\\n\",\n      \"✗ [236]\\n\",\n      \"✗ [237]\\n\",\n      \"✗ [238]\\n\",\n      \"✗ [239]\\n\",\n      \"✗ [240]\\n\",\n      \"✗ [241]\\n\",\n      \"✗ [242]\\n\",\n      \"✗ [243]\\n\",\n      \"✗ [244]\\n\",\n      \"✗ [245]\\n\",\n      \"✗ [246]\\n\",\n      \"✗ [247]\\n\",\n      \"✗ [248]\\n\",\n      \"✗ [249]\\n\",\n      \"✗ [250]\\n\",\n      \"✗ [251]\\n\",\n      \"✗ [252]\\n\",\n      \"✗ [253]\\n\",\n      \"✗ [254]\\n\",\n      \"✗ [255]\\n\",\n      \"✗ [256]\\n\",\n      \"✗ [257]\\n\",\n      \"✗ [258]\\n\",\n      \"✗ [259]\\n\",\n      \"✗ [260]\\n\",\n      \"✗ [261]\\n\",\n      \"✗ [262]\\n\",\n      \"✗ [263]\\n\",\n      \"✗ [264]\\n\",\n      \"✗ [265]\\n\",\n      \"✗ [266]\\n\",\n      \"✗ [267]\\n\",\n      \"✗ [268]\\n\",\n      \"✗ [269]\\n\",\n      \"✗ [270]\\n\",\n      \"✗ [271]\\n\",\n      \"✗ [272]\\n\",\n      \"✗ [273]\\n\",\n      \"✗ [274]\\n\",\n      \"✗ [275]\\n\",\n      \"✗ [276]\\n\",\n      \"✗ [277]\\n\",\n      \"✗ [278]\\n\",\n      \"✗ [279]\\n\",\n      \"✗ [280]\\n\",\n      \"✗ [281]\\n\",\n      \"✗ [282]\\n\",\n      \"✗ [283]\\n\",\n      \"✗ [284]\\n\",\n      \"✗ [285]\\n\",\n      \"✗ [286]\\n\",\n      \"✗ [287]\\n\",\n      \"✗ [288]\\n\",\n      \"✗ [289]\\n\",\n      \"✗ [290]\\n\",\n      \"✗ [291]\\n\",\n      \"✗ [292]\\n\",\n      \"✗ [293]\\n\",\n      \"✗ [294]\\n\",\n      \"✗ [295]\\n\",\n      \"✗ [296]\\n\",\n      \"✗ [297]\\n\",\n      \"✗ [298]\\n\",\n      \"✗ [299]\\n\",\n      \"✗ [300]\\n\",\n      \"✗ [301]\\n\",\n      \"✗ [302]\\n\",\n      \"✗ [303]\\n\",\n      \"✗ [304]\\n\",\n      \"✗ [305]\\n\",\n      \"✗ [306]\\n\",\n      \"✗ [307]\\n\",\n      \"✗ [308]\\n\",\n      \"✗ [309]\\n\",\n      \"✗ [310]\\n\",\n      \"✗ [311]\\n\",\n      \"✗ [312]\\n\",\n      \"✗ [313]\\n\",\n      \"✗ [314]\\n\",\n      \"✗ [315]\\n\",\n      \"✗ [316]\\n\",\n      \"✗ [317]\\n\",\n      \"✗ [318]\\n\",\n      \"✗ [319]\\n\",\n      \"✗ [320]\\n\",\n      \"✗ [321]\\n\",\n      \"✗ [322]\\n\",\n      \"✗ [323]\\n\",\n      \"✗ [324]\\n\",\n      \"✗ [325]\\n\",\n      \"✗ [326]\\n\",\n      \"✗ [327]\\n\",\n      \"✗ [328]\\n\",\n      \"✗ [329]\\n\",\n      \"✗ [330]\\n\",\n      \"✗ [331]\\n\",\n      \"✗ [332]\\n\",\n      \"✗ [333]\\n\",\n      \"✗ [334]\\n\",\n      \"✗ [335]\\n\",\n      \"✗ [336]\\n\",\n      \"✗ [337]\\n\",\n      \"✗ [338]\\n\",\n      \"✗ [339]\\n\",\n      \"✗ [340]\\n\",\n      \"✗ [341]\\n\",\n      \"✗ [342]\\n\",\n      \"✗ [343]\\n\",\n      \"✗ [344]\\n\",\n      \"✗ [345]\\n\",\n      \"✗ [346]\\n\",\n      \"✗ [347]\\n\",\n      \"✗ [348]\\n\",\n      \"✗ [349]\\n\",\n      \"✗ [350]\\n\",\n      \"✗ [351]\\n\",\n      \"✗ [352]\\n\",\n      \"✗ [353]\\n\",\n      \"✗ [354]\\n\",\n      \"✗ [355]\\n\",\n      \"✗ [356]\\n\",\n      \"✗ [357]\\n\",\n      \"✗ [358]\\n\",\n      \"✗ [359]\\n\",\n      \"✗ [360]\\n\",\n      \"✗ [361]\\n\",\n      \"✗ [362]\\n\",\n      \"✗ [363]\\n\",\n      \"✗ [364]\\n\",\n      \"✗ [365]\\n\",\n      \"✗ [366]\\n\",\n      \"✗ [367]\\n\",\n      \"✗ [368]\\n\",\n      \"✗ [369]\\n\",\n      \"✗ [370]\\n\",\n      \"✗ [371]\\n\",\n      \"✗ [372]\\n\",\n      \"✗ [373]\\n\",\n      \"✗ [374]\\n\",\n      \"✗ [375]\\n\",\n      \"✗ [376]\\n\",\n      \"✗ [377]\\n\",\n      \"✗ [378]\\n\",\n      \"✗ [379]\\n\",\n      \"✗ [380]\\n\",\n      \"✗ [381]\\n\",\n      \"✗ [382]\\n\",\n      \"✗ [383]\\n\",\n      \"✗ [384]\\n\",\n      \"✗ [385]\\n\",\n      \"✗ [386]\\n\",\n      \"✗ [387]\\n\",\n      \"✗ [388]\\n\",\n      \"✗ [389]\\n\",\n      \"✗ [390]\\n\",\n      \"✗ [391]\\n\",\n      \"✗ [392]\\n\",\n      \"✗ [393]\\n\",\n      \"✗ [394]\\n\",\n      \"✗ [395]\\n\",\n      \"✗ [396]\\n\",\n      \"✗ [397]\\n\",\n      \"✗ [398]\\n\",\n      \"✗ [399]\\n\",\n      \"✗ [400]\\n\",\n      \"✗ [401]\\n\",\n      \"✗ [402]\\n\",\n      \"✗ [403]\\n\",\n      \"✗ [404]\\n\",\n      \"✗ [405]\\n\",\n      \"✗ [406]\\n\",\n      \"✗ [407]\\n\",\n      \"✗ [408]\\n\",\n      \"✗ [409]\\n\",\n      \"✗ [410]\\n\",\n      \"✗ [411]\\n\",\n      \"✗ [412]\\n\",\n      \"✗ [413]\\n\",\n      \"✗ [414]\\n\",\n      \"✗ [415]\\n\",\n      \"✗ [416]\\n\",\n      \"✗ [417]\\n\",\n      \"✗ [418]\\n\",\n      \"✗ [419]\\n\",\n      \"✗ [420]\\n\",\n      \"✗ [421]\\n\",\n      \"✗ [422]\\n\",\n      \"✗ [423]\\n\",\n      \"✗ [424]\\n\",\n      \"✗ [425]\\n\",\n      \"✗ [426]\\n\",\n      \"✗ [427]\\n\",\n      \"✗ [428]\\n\",\n      \"✗ [429]\\n\",\n      \"✗ [430]\\n\",\n      \"✗ [431]\\n\",\n      \"✗ [432]\\n\",\n      \"✗ [433]\\n\",\n      \"✗ [434]\\n\",\n      \"✗ [435]\\n\",\n      \"✗ [436]\\n\",\n      \"✗ [437]\\n\",\n      \"✗ [438]\\n\",\n      \"✗ [439]\\n\",\n      \"✗ [440]\\n\",\n      \"✗ [441]\\n\",\n      \"✗ [442]\\n\",\n      \"✗ [443]\\n\",\n      \"✗ [444]\\n\",\n      \"✗ [445]\\n\",\n      \"✗ [446]\\n\",\n      \"✗ [447]\\n\",\n      \"✗ [448]\\n\",\n      \"✗ [449]\\n\",\n      \"✗ [450]\\n\",\n      \"✗ [451]\\n\",\n      \"✗ [452]\\n\",\n      \"✗ [453]\\n\",\n      \"✗ [454]\\n\",\n      \"✗ [455]\\n\",\n      \"✗ [456]\\n\",\n      \"✗ [457]\\n\",\n      \"✗ [458]\\n\",\n      \"✗ [459]\\n\",\n      \"✗ [460]\\n\",\n      \"✗ [461]\\n\",\n      \"✗ [462]\\n\",\n      \"✗ [463]\\n\",\n      \"✗ [464]\\n\",\n      \"✗ [465]\\n\",\n      \"✗ [466]\\n\",\n      \"✗ [467]\\n\",\n      \"✗ [468]\\n\",\n      \"✗ [469]\\n\",\n      \"✗ [470]\\n\",\n      \"✗ [471]\\n\",\n      \"✗ [472]\\n\",\n      \"✗ [473]\\n\",\n      \"✗ [474]\\n\",\n      \"✗ [475]\\n\",\n      \"✗ [476]\\n\",\n      \"✗ [477]\\n\",\n      \"✗ [478]\\n\",\n      \"✗ [479]\\n\",\n      \"✗ [480]\\n\",\n      \"✗ [481]\\n\",\n      \"✗ [482]\\n\",\n      \"✗ [483]\\n\",\n      \"✗ [484]\\n\",\n      \"✗ [485]\\n\",\n      \"✗ [486]\\n\",\n      \"✗ [487]\\n\",\n      \"✗ [488]\\n\",\n      \"✗ [489]\\n\",\n      \"✗ [490]\\n\",\n      \"✗ [491]\\n\",\n      \"✗ [492]\\n\",\n      \"✗ [493]\\n\",\n      \"✗ [494]\\n\",\n      \"✗ [495]\\n\",\n      \"✗ [496]\\n\",\n      \"✗ [497]\\n\",\n      \"✗ [498]\\n\",\n      \"✗ [499]\\n\",\n      \"✓ [500]\\n\",\n      \"✗ []\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [1]\\n\",\n      \"✗ [2]\\n\",\n      \"✗ [3]\\n\",\n      \"✗ [4]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [6]\\n\",\n      \"✗ [7]\\n\",\n      \"✗ [8]\\n\",\n      \"✗ [9]\\n\",\n      \"✗ [10]\\n\",\n      \"✗ [11]\\n\",\n      \"✗ [12]\\n\",\n      \"✗ [13]\\n\",\n      \"✗ [14]\\n\",\n      \"✗ [15]\\n\",\n      \"✗ [16]\\n\",\n      \"✗ [17]\\n\",\n      \"✗ [18]\\n\",\n      \"✗ [19]\\n\",\n      \"✗ [20]\\n\",\n      \"✗ [21]\\n\",\n      \"✗ [22]\\n\",\n      \"✗ [23]\\n\",\n      \"✗ [24]\\n\",\n      \"✗ [25]\\n\",\n      \"✗ [26]\\n\",\n      \"✗ [27]\\n\",\n      \"✗ [28]\\n\",\n      \"✗ [29]\\n\",\n      \"✗ [30]\\n\",\n      \"✗ [31]\\n\",\n      \"✗ [32]\\n\",\n      \"✗ [33]\\n\",\n      \"✗ [34]\\n\",\n      \"✗ [35]\\n\",\n      \"✗ [36]\\n\",\n      \"✗ [37]\\n\",\n      \"✗ [38]\\n\",\n      \"✗ [39]\\n\",\n      \"✗ [40]\\n\",\n      \"✗ [41]\\n\",\n      \"✗ [42]\\n\",\n      \"✗ [43]\\n\",\n      \"✗ [44]\\n\",\n      \"✗ [45]\\n\",\n      \"✗ [46]\\n\",\n      \"✗ [47]\\n\",\n      \"✗ [48]\\n\",\n      \"✗ [49]\\n\",\n      \"✗ [50]\\n\",\n      \"✗ [51]\\n\",\n      \"✗ [52]\\n\",\n      \"✗ [53]\\n\",\n      \"✗ [54]\\n\",\n      \"✗ [55]\\n\",\n      \"✗ [56]\\n\",\n      \"✗ [57]\\n\",\n      \"✗ [58]\\n\",\n      \"✗ [59]\\n\",\n      \"✗ [60]\\n\",\n      \"✗ [61]\\n\",\n      \"✗ [62]\\n\",\n      \"✗ [63]\\n\",\n      \"✗ [64]\\n\",\n      \"✗ [65]\\n\",\n      \"✗ [66]\\n\",\n      \"✗ [67]\\n\",\n      \"✗ [68]\\n\",\n      \"✗ [69]\\n\",\n      \"✗ [70]\\n\",\n      \"✗ [71]\\n\",\n      \"✗ [72]\\n\",\n      \"✗ [73]\\n\",\n      \"✗ [74]\\n\",\n      \"✗ [75]\\n\",\n      \"✗ [76]\\n\",\n      \"✗ [77]\\n\",\n      \"✗ [78]\\n\",\n      \"✗ [79]\\n\",\n      \"✗ [80]\\n\",\n      \"✗ [81]\\n\",\n      \"✗ [82]\\n\",\n      \"✗ [83]\\n\",\n      \"✗ [84]\\n\",\n      \"✗ [85]\\n\",\n      \"✗ [86]\\n\",\n      \"✗ [87]\\n\",\n      \"✗ [88]\\n\",\n      \"✗ [89]\\n\",\n      \"✗ [90]\\n\",\n      \"✗ [91]\\n\",\n      \"✗ [92]\\n\",\n      \"✗ [93]\\n\",\n      \"✗ [94]\\n\",\n      \"✗ [95]\\n\",\n      \"✗ [96]\\n\",\n      \"✗ [97]\\n\",\n      \"✗ [98]\\n\",\n      \"✗ [99]\\n\",\n      \"✗ [100]\\n\",\n      \"✗ [101]\\n\",\n      \"✗ [102]\\n\",\n      \"✗ [103]\\n\",\n      \"✗ [104]\\n\",\n      \"✗ [105]\\n\",\n      \"✗ [106]\\n\",\n      \"✗ [107]\\n\",\n      \"✗ [108]\\n\",\n      \"✗ [109]\\n\",\n      \"✗ [110]\\n\",\n      \"✗ [111]\\n\",\n      \"✗ [112]\\n\",\n      \"✗ [113]\\n\",\n      \"✗ [114]\\n\",\n      \"✗ [115]\\n\",\n      \"✗ [116]\\n\",\n      \"✗ [117]\\n\",\n      \"✗ [118]\\n\",\n      \"✗ [119]\\n\",\n      \"✗ [120]\\n\",\n      \"✗ [121]\\n\",\n      \"✗ [122]\\n\",\n      \"✗ [123]\\n\",\n      \"✗ [124]\\n\",\n      \"✗ [125]\\n\",\n      \"✗ [126]\\n\",\n      \"✗ [127]\\n\",\n      \"✗ [128]\\n\",\n      \"✗ [129]\\n\",\n      \"✗ [130]\\n\",\n      \"✗ [131]\\n\",\n      \"✗ [132]\\n\",\n      \"✗ [133]\\n\",\n      \"✗ [134]\\n\",\n      \"✗ [135]\\n\",\n      \"✗ [136]\\n\",\n      \"✗ [137]\\n\",\n      \"✗ [138]\\n\",\n      \"✗ [139]\\n\",\n      \"✗ [140]\\n\",\n      \"✗ [141]\\n\",\n      \"✗ [142]\\n\",\n      \"✗ [143]\\n\",\n      \"✗ [144]\\n\",\n      \"✗ [145]\\n\",\n      \"✗ [146]\\n\",\n      \"✗ [147]\\n\",\n      \"✗ [148]\\n\",\n      \"✗ [149]\\n\",\n      \"✗ [150]\\n\",\n      \"✗ [151]\\n\",\n      \"✗ [152]\\n\",\n      \"✗ [153]\\n\",\n      \"✗ [154]\\n\",\n      \"✗ [155]\\n\",\n      \"✗ [156]\\n\",\n      \"✗ [157]\\n\",\n      \"✗ [158]\\n\",\n      \"✗ [159]\\n\",\n      \"✗ [160]\\n\",\n      \"✗ [161]\\n\",\n      \"✗ [162]\\n\",\n      \"✗ [163]\\n\",\n      \"✗ [164]\\n\",\n      \"✗ [165]\\n\",\n      \"✗ [166]\\n\",\n      \"✗ [167]\\n\",\n      \"✗ [168]\\n\",\n      \"✗ [169]\\n\",\n      \"✗ [170]\\n\",\n      \"✗ [171]\\n\",\n      \"✗ [172]\\n\",\n      \"✗ [173]\\n\",\n      \"✗ [174]\\n\",\n      \"✗ [175]\\n\",\n      \"✗ [176]\\n\",\n      \"✗ [177]\\n\",\n      \"✗ [178]\\n\",\n      \"✗ [179]\\n\",\n      \"✗ [180]\\n\",\n      \"✗ [181]\\n\",\n      \"✗ [182]\\n\",\n      \"✗ [183]\\n\",\n      \"✗ [184]\\n\",\n      \"✗ [185]\\n\",\n      \"✗ [186]\\n\",\n      \"✗ [187]\\n\",\n      \"✗ [188]\\n\",\n      \"✗ [189]\\n\",\n      \"✗ [190]\\n\",\n      \"✗ [191]\\n\",\n      \"✗ [192]\\n\",\n      \"✗ [193]\\n\",\n      \"✗ [194]\\n\",\n      \"✗ [195]\\n\",\n      \"✗ [196]\\n\",\n      \"✗ [197]\\n\",\n      \"✗ [198]\\n\",\n      \"✗ [199]\\n\",\n      \"✗ [200]\\n\",\n      \"✗ [201]\\n\",\n      \"✗ [202]\\n\",\n      \"✗ [203]\\n\",\n      \"✗ [204]\\n\",\n      \"✗ [205]\\n\",\n      \"✗ [206]\\n\",\n      \"✗ [207]\\n\",\n      \"✗ [208]\\n\",\n      \"✗ [209]\\n\",\n      \"✗ [210]\\n\",\n      \"✗ [211]\\n\",\n      \"✗ [212]\\n\",\n      \"✗ [213]\\n\",\n      \"✗ [214]\\n\",\n      \"✗ [215]\\n\",\n      \"✗ [216]\\n\",\n      \"✗ [217]\\n\",\n      \"✗ [218]\\n\",\n      \"✗ [219]\\n\",\n      \"✗ [220]\\n\",\n      \"✗ [221]\\n\",\n      \"✗ [222]\\n\",\n      \"✗ [223]\\n\",\n      \"✗ [224]\\n\",\n      \"✗ [225]\\n\",\n      \"✗ [226]\\n\",\n      \"✗ [227]\\n\",\n      \"✗ [228]\\n\",\n      \"✗ [229]\\n\",\n      \"✗ [230]\\n\",\n      \"✗ [231]\\n\",\n      \"✗ [232]\\n\",\n      \"✗ [233]\\n\",\n      \"✗ [234]\\n\",\n      \"✗ [235]\\n\",\n      \"✗ [236]\\n\",\n      \"✗ [237]\\n\",\n      \"✗ [238]\\n\",\n      \"✗ [239]\\n\",\n      \"✗ [240]\\n\",\n      \"✗ [241]\\n\",\n      \"✗ [242]\\n\",\n      \"✗ [243]\\n\",\n      \"✗ [244]\\n\",\n      \"✗ [245]\\n\",\n      \"✗ [246]\\n\",\n      \"✗ [247]\\n\",\n      \"✗ [248]\\n\",\n      \"✗ [249]\\n\",\n      \"✗ [250]\\n\",\n      \"✗ [251]\\n\",\n      \"✗ [252]\\n\",\n      \"✗ [253]\\n\",\n      \"✗ [254]\\n\",\n      \"✗ [255]\\n\",\n      \"✗ [256]\\n\",\n      \"✗ [257]\\n\",\n      \"✗ [258]\\n\",\n      \"✗ [259]\\n\",\n      \"✗ [260]\\n\",\n      \"✗ [261]\\n\",\n      \"✗ [262]\\n\",\n      \"✗ [263]\\n\",\n      \"✗ [264]\\n\",\n      \"✗ [265]\\n\",\n      \"✗ [266]\\n\",\n      \"✗ [267]\\n\",\n      \"✗ [268]\\n\",\n      \"✗ [269]\\n\",\n      \"✗ [270]\\n\",\n      \"✗ [271]\\n\",\n      \"✗ [272]\\n\",\n      \"✗ [273]\\n\",\n      \"✗ [274]\\n\",\n      \"✗ [275]\\n\",\n      \"✗ [276]\\n\",\n      \"✗ [277]\\n\",\n      \"✗ [278]\\n\",\n      \"✗ [279]\\n\",\n      \"✗ [280]\\n\",\n      \"✗ [281]\\n\",\n      \"✗ [282]\\n\",\n      \"✗ [283]\\n\",\n      \"✗ [284]\\n\",\n      \"✗ [285]\\n\",\n      \"✗ [286]\\n\",\n      \"✗ [287]\\n\",\n      \"✗ [288]\\n\",\n      \"✗ [289]\\n\",\n      \"✗ [290]\\n\",\n      \"✗ [291]\\n\",\n      \"✗ [292]\\n\",\n      \"✗ [293]\\n\",\n      \"✗ [294]\\n\",\n      \"✗ [295]\\n\",\n      \"✗ [296]\\n\",\n      \"✗ [297]\\n\",\n      \"✗ [298]\\n\",\n      \"✗ [299]\\n\",\n      \"✗ [300]\\n\",\n      \"✗ [301]\\n\",\n      \"✗ [302]\\n\",\n      \"✗ [303]\\n\",\n      \"✗ [304]\\n\",\n      \"✗ [305]\\n\",\n      \"✗ [306]\\n\",\n      \"✗ [307]\\n\",\n      \"✗ [308]\\n\",\n      \"✗ [309]\\n\",\n      \"✗ [310]\\n\",\n      \"✗ [311]\\n\",\n      \"✗ [312]\\n\",\n      \"✗ [313]\\n\",\n      \"✗ [314]\\n\",\n      \"✗ [315]\\n\",\n      \"✗ [316]\\n\",\n      \"✗ [317]\\n\",\n      \"✗ [318]\\n\",\n      \"✗ [319]\\n\",\n      \"✗ [320]\\n\",\n      \"✗ [321]\\n\",\n      \"✗ [322]\\n\",\n      \"✗ [323]\\n\",\n      \"✗ [324]\\n\",\n      \"✗ [325]\\n\",\n      \"✗ [326]\\n\",\n      \"✗ [327]\\n\",\n      \"✗ [328]\\n\",\n      \"✗ [329]\\n\",\n      \"✗ [330]\\n\",\n      \"✗ [331]\\n\",\n      \"✗ [332]\\n\",\n      \"✗ [333]\\n\",\n      \"✗ [334]\\n\",\n      \"✗ [335]\\n\",\n      \"✗ [336]\\n\",\n      \"✗ [337]\\n\",\n      \"✗ [338]\\n\",\n      \"✗ [339]\\n\",\n      \"✗ [340]\\n\",\n      \"✗ [341]\\n\",\n      \"✗ [342]\\n\",\n      \"✗ [343]\\n\",\n      \"✗ [344]\\n\",\n      \"✗ [345]\\n\",\n      \"✗ [346]\\n\",\n      \"✗ [347]\\n\",\n      \"✗ [348]\\n\",\n      \"✗ [349]\\n\",\n      \"✗ [350]\\n\",\n      \"✗ [351]\\n\",\n      \"✗ [352]\\n\",\n      \"✗ [353]\\n\",\n      \"✗ [354]\\n\",\n      \"✗ [355]\\n\",\n      \"✗ [356]\\n\",\n      \"✗ [357]\\n\",\n      \"✗ [358]\\n\",\n      \"✗ [359]\\n\",\n      \"✗ [360]\\n\",\n      \"✗ [361]\\n\",\n      \"✗ [362]\\n\",\n      \"✗ [363]\\n\",\n      \"✗ [364]\\n\",\n      \"✗ [365]\\n\",\n      \"✗ [366]\\n\",\n      \"✗ [367]\\n\",\n      \"✗ [368]\\n\",\n      \"✗ [369]\\n\",\n      \"✗ [370]\\n\",\n      \"✗ [371]\\n\",\n      \"✗ [372]\\n\",\n      \"✗ [373]\\n\",\n      \"✗ [374]\\n\",\n      \"✗ [375]\\n\",\n      \"✗ [376]\\n\",\n      \"✗ [377]\\n\",\n      \"✗ [378]\\n\",\n      \"✗ [379]\\n\",\n      \"✗ [380]\\n\",\n      \"✗ [381]\\n\",\n      \"✗ [382]\\n\",\n      \"✗ [383]\\n\",\n      \"✗ [384]\\n\",\n      \"✗ [385]\\n\",\n      \"✗ [386]\\n\",\n      \"✗ [387]\\n\",\n      \"✗ [388]\\n\",\n      \"✗ [389]\\n\",\n      \"✗ [390]\\n\",\n      \"✗ [391]\\n\",\n      \"✗ [392]\\n\",\n      \"✗ [393]\\n\",\n      \"✗ [394]\\n\",\n      \"✗ [395]\\n\",\n      \"✗ [396]\\n\",\n      \"✗ [397]\\n\",\n      \"✗ [398]\\n\",\n      \"✗ [399]\\n\",\n      \"✗ [400]\\n\",\n      \"✗ [401]\\n\",\n      \"✗ [402]\\n\",\n      \"✗ [403]\\n\",\n      \"✗ [404]\\n\",\n      \"✗ [405]\\n\",\n      \"✗ [406]\\n\",\n      \"✗ [407]\\n\",\n      \"✗ [408]\\n\",\n      \"✗ [409]\\n\",\n      \"✗ [410]\\n\",\n      \"✗ [411]\\n\",\n      \"✗ [412]\\n\",\n      \"✗ [413]\\n\",\n      \"✗ [414]\\n\",\n      \"✗ [415]\\n\",\n      \"✗ [416]\\n\",\n      \"✗ [417]\\n\",\n      \"✗ [418]\\n\",\n      \"✗ [419]\\n\",\n      \"✗ [420]\\n\",\n      \"✗ [421]\\n\",\n      \"✗ [422]\\n\",\n      \"✗ [423]\\n\",\n      \"✗ [424]\\n\",\n      \"✗ [425]\\n\",\n      \"✗ [426]\\n\",\n      \"✗ [427]\\n\",\n      \"✗ [428]\\n\",\n      \"✗ [429]\\n\",\n      \"✗ [430]\\n\",\n      \"✗ [431]\\n\",\n      \"✗ [432]\\n\",\n      \"✗ [433]\\n\",\n      \"✗ [434]\\n\",\n      \"✗ [435]\\n\",\n      \"✗ [436]\\n\",\n      \"✗ [437]\\n\",\n      \"✗ [438]\\n\",\n      \"✗ [439]\\n\",\n      \"✗ [440]\\n\",\n      \"✗ [441]\\n\",\n      \"✗ [442]\\n\",\n      \"✗ [443]\\n\",\n      \"✗ [444]\\n\",\n      \"✗ [445]\\n\",\n      \"✗ [446]\\n\",\n      \"✗ [447]\\n\",\n      \"✗ [448]\\n\",\n      \"✗ [449]\\n\",\n      \"✗ [450]\\n\",\n      \"✗ [451]\\n\",\n      \"✗ [452]\\n\",\n      \"✗ [453]\\n\",\n      \"✗ [454]\\n\",\n      \"✗ [455]\\n\",\n      \"✗ [456]\\n\",\n      \"✗ [457]\\n\",\n      \"✗ [458]\\n\",\n      \"✗ [459]\\n\",\n      \"✗ [460]\\n\",\n      \"✗ [461]\\n\",\n      \"✗ [462]\\n\",\n      \"✗ [463]\\n\",\n      \"✗ [464]\\n\",\n      \"✗ [465]\\n\",\n      \"✗ [466]\\n\",\n      \"✗ [467]\\n\",\n      \"✗ [468]\\n\",\n      \"✗ [469]\\n\",\n      \"✗ [470]\\n\",\n      \"✗ [471]\\n\",\n      \"✗ [472]\\n\",\n      \"✗ [473]\\n\",\n      \"✗ [474]\\n\",\n      \"✗ [475]\\n\",\n      \"✗ [476]\\n\",\n      \"✗ [477]\\n\",\n      \"✗ [478]\\n\",\n      \"✗ [479]\\n\",\n      \"✗ [480]\\n\",\n      \"✗ [481]\\n\",\n      \"✗ [482]\\n\",\n      \"✗ [483]\\n\",\n      \"✗ [484]\\n\",\n      \"✗ [485]\\n\",\n      \"✗ [486]\\n\",\n      \"✗ [487]\\n\",\n      \"✗ [488]\\n\",\n      \"✗ [489]\\n\",\n      \"✗ [490]\\n\",\n      \"✗ [491]\\n\",\n      \"✗ [492]\\n\",\n      \"✗ [493]\\n\",\n      \"✗ [494]\\n\",\n      \"✗ [495]\\n\",\n      \"✗ [496]\\n\",\n      \"✗ [497]\\n\",\n      \"✗ [498]\\n\",\n      \"✗ [499]\\n\",\n      \"\\n\",\n      \"1 shrinks with 1003 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace([1000], lambda x: sum(x) >= 500, partial(greedy_shrink, shrink=shrink2))\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"Because we're trying every intermediate value, what we have amounts to a linear probe up to the smallest value that will work. If that smallest value is large, this will take a long time. Our shrinking is still O(n), but n is now the size of the smallest value that will work rather than the starting value. This is still pretty suboptimal.\\n\",\n    \"\\n\",\n    \"What we want to do is try to replace our linear probe with a binary search. What we'll get isn't exactly a binary search, but it's close enough.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 9,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"def shrink_integer(n):\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    Shrinker for individual integers.\\n\",\n    \"\\n\",\n    \"    What happens is that we start from the left, first probing upwards in powers of two.\\n\",\n    \"\\n\",\n    \"    When this would take us past our target value we then binary chop towards it.\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    if not n:\\n\",\n    \"        return\\n\",\n    \"    for k in range(64):\\n\",\n    \"        probe = 2**k\\n\",\n    \"        if probe >= n:\\n\",\n    \"            break\\n\",\n    \"        yield probe - 1\\n\",\n    \"    probe //= 2\\n\",\n    \"    while True:\\n\",\n    \"        probe = (probe + n) // 2\\n\",\n    \"        yield probe\\n\",\n    \"        if probe == n - 1:\\n\",\n    \"            break\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"def shrink3(ls):\\n\",\n    \"    for i in range(len(ls)):\\n\",\n    \"        s = list(ls)\\n\",\n    \"        del s[i]\\n\",\n    \"        yield list(s)\\n\",\n    \"        for x in shrink_integer(ls[i]):\\n\",\n    \"            s = list(ls)\\n\",\n    \"            s[i] = x\\n\",\n    \"            yield s\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 10,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"[0, 1, 3, 7, 15, 31, 63, 127, 255, 378, 439, 469, 484, 492, 496, 498, 499]\"\n      ]\n     },\n     \"execution_count\": 10,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"list(shrink_integer(500))\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"This gives us a reasonable distribution of O(log(n)) values in the middle while still making sure we start with 0 and finish with n - 1.\\n\",\n    \"\\n\",\n    \"In Hypothesis's actual implementation we also try random values in the probe region in case there's something special about things near powers of two, but we won't worry about that here.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 11,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [1000]\\n\",\n      \"✗ []\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [1]\\n\",\n      \"✗ [3]\\n\",\n      \"✗ [7]\\n\",\n      \"✗ [15]\\n\",\n      \"✗ [31]\\n\",\n      \"✗ [63]\\n\",\n      \"✗ [127]\\n\",\n      \"✗ [255]\\n\",\n      \"✓ [511]\\n\",\n      \"✗ []\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [1]\\n\",\n      \"✗ [3]\\n\",\n      \"✗ [7]\\n\",\n      \"✗ [15]\\n\",\n      \"✗ [31]\\n\",\n      \"✗ [63]\\n\",\n      \"✗ [127]\\n\",\n      \"✗ [255]\\n\",\n      \"✗ [383]\\n\",\n      \"✗ [447]\\n\",\n      \"✗ [479]\\n\",\n      \"✗ [495]\\n\",\n      \"✓ [503]\\n\",\n      \"✗ []\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [1]\\n\",\n      \"✗ [3]\\n\",\n      \"✗ [7]\\n\",\n      \"✗ [15]\\n\",\n      \"✗ [31]\\n\",\n      \"✗ [63]\\n\",\n      \"✗ [127]\\n\",\n      \"✗ [255]\\n\",\n      \"✗ [379]\\n\",\n      \"✗ [441]\\n\",\n      \"✗ [472]\\n\",\n      \"✗ [487]\\n\",\n      \"✗ [495]\\n\",\n      \"✗ [499]\\n\",\n      \"✓ [501]\\n\",\n      \"✗ []\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [1]\\n\",\n      \"✗ [3]\\n\",\n      \"✗ [7]\\n\",\n      \"✗ [15]\\n\",\n      \"✗ [31]\\n\",\n      \"✗ [63]\\n\",\n      \"✗ [127]\\n\",\n      \"✗ [255]\\n\",\n      \"✗ [378]\\n\",\n      \"✗ [439]\\n\",\n      \"✗ [470]\\n\",\n      \"✗ [485]\\n\",\n      \"✗ [493]\\n\",\n      \"✗ [497]\\n\",\n      \"✗ [499]\\n\",\n      \"✓ [500]\\n\",\n      \"✗ []\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [1]\\n\",\n      \"✗ [3]\\n\",\n      \"✗ [7]\\n\",\n      \"✗ [15]\\n\",\n      \"✗ [31]\\n\",\n      \"✗ [63]\\n\",\n      \"✗ [127]\\n\",\n      \"✗ [255]\\n\",\n      \"✗ [378]\\n\",\n      \"✗ [439]\\n\",\n      \"✗ [469]\\n\",\n      \"✗ [484]\\n\",\n      \"✗ [492]\\n\",\n      \"✗ [496]\\n\",\n      \"✗ [498]\\n\",\n      \"✗ [499]\\n\",\n      \"\\n\",\n      \"4 shrinks with 79 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace([1000], lambda x: sum(x) >= 500, partial(greedy_shrink, shrink=shrink3))\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"This now runs in a much more reasonable number of function calls.\\n\",\n    \"\\n\",\n    \"Now we want to look at how to reduce the number of elements in the list more efficiently. We're currently making the same mistake we did with n umbers. Only reducing one at a time.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 12,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2, 2]\\n\",\n      \"✓ [2, 2, 2]\\n\",\n      \"✓ [2, 2]\\n\",\n      \"✗ [2]\\n\",\n      \"✗ [0, 2]\\n\",\n      \"✓ [1, 2]\\n\",\n      \"✗ [2]\\n\",\n      \"✗ [0, 2]\\n\",\n      \"✗ [1]\\n\",\n      \"✗ [1, 0]\\n\",\n      \"✗ [1, 1]\\n\",\n      \"\\n\",\n      \"19 shrinks with 26 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace([2] * 20, lambda x: sum(x) >= 3, partial(greedy_shrink, shrink=shrink3))\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"We won't try too hard here, because typically our lists are not *that* long. We will just attempt to start by finding a shortish initial prefix that demonstrates the behaviour:\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 13,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"def shrink_to_prefix(ls):\\n\",\n    \"    i = 1\\n\",\n    \"    while i < len(ls):\\n\",\n    \"        yield ls[:i]\\n\",\n    \"        i *= 2\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"def delete_individual_elements(ls):\\n\",\n    \"    for i in range(len(ls)):\\n\",\n    \"        s = list(ls)\\n\",\n    \"        del s[i]\\n\",\n    \"        yield list(s)\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"def shrink_individual_elements(ls):\\n\",\n    \"    for i in range(len(ls)):\\n\",\n    \"        for x in shrink_integer(ls[i]):\\n\",\n    \"            s = list(ls)\\n\",\n    \"            s[i] = x\\n\",\n    \"            yield s\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"def shrink4(ls):\\n\",\n    \"    yield from shrink_to_prefix(ls)\\n\",\n    \"    yield from delete_individual_elements(ls)\\n\",\n    \"    yield from shrink_individual_elements(ls)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 14,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [2]\\n\",\n      \"✓ [2, 2]\\n\",\n      \"✗ [2]\\n\",\n      \"✗ [2]\\n\",\n      \"✗ [2]\\n\",\n      \"✗ [0, 2]\\n\",\n      \"✓ [1, 2]\\n\",\n      \"✗ [1]\\n\",\n      \"✗ [2]\\n\",\n      \"✗ [1]\\n\",\n      \"✗ [0, 2]\\n\",\n      \"✗ [1, 0]\\n\",\n      \"✗ [1, 1]\\n\",\n      \"\\n\",\n      \"2 shrinks with 13 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace([2] * 20, lambda x: sum(x) >= 3, partial(greedy_shrink, shrink=shrink4))\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"The problem we now want to address is the fact that when we're shrinking elements we're only shrinking them one at a time. This means that even though we're only O(log(k)) in each element, we're O(log(k)^n) in the whole list where n is the length of the list. For even very modest k this is bad.\\n\",\n    \"\\n\",\n    \"In general we may not be able to fix this, but in practice for a lot of common structures we can exploit similarity to try to do simultaneous shrinking.\\n\",\n    \"\\n\",\n    \"Here is our starting example: We start and finish with all identical values. We would like to be able to shortcut through a lot of the uninteresting intermediate examples somehow.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 15,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [20, 20, 20, 20, 20, 20, 20]\\n\",\n      \"✗ [20]\\n\",\n      \"✗ [20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✓ [20, 20, 20, 20, 20, 20]\\n\",\n      \"✗ [20]\\n\",\n      \"✗ [20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✓ [20, 20, 20, 20, 20]\\n\",\n      \"✗ [20]\\n\",\n      \"✗ [20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✗ [0, 20, 20, 20, 20]\\n\",\n      \"✗ [1, 20, 20, 20, 20]\\n\",\n      \"✗ [3, 20, 20, 20, 20]\\n\",\n      \"✓ [7, 20, 20, 20, 20]\\n\",\n      \"✗ [7]\\n\",\n      \"✗ [7, 20]\\n\",\n      \"✗ [7, 20, 20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✗ [7, 20, 20, 20]\\n\",\n      \"✗ [7, 20, 20, 20]\\n\",\n      \"✗ [7, 20, 20, 20]\\n\",\n      \"✗ [7, 20, 20, 20]\\n\",\n      \"✗ [0, 20, 20, 20, 20]\\n\",\n      \"✗ [1, 20, 20, 20, 20]\\n\",\n      \"✗ [3, 20, 20, 20, 20]\\n\",\n      \"✓ [5, 20, 20, 20, 20]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 20]\\n\",\n      \"✗ [5, 20, 20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✗ [5, 20, 20, 20]\\n\",\n      \"✗ [5, 20, 20, 20]\\n\",\n      \"✗ [5, 20, 20, 20]\\n\",\n      \"✗ [5, 20, 20, 20]\\n\",\n      \"✗ [0, 20, 20, 20, 20]\\n\",\n      \"✗ [1, 20, 20, 20, 20]\\n\",\n      \"✗ [3, 20, 20, 20, 20]\\n\",\n      \"✗ [4, 20, 20, 20, 20]\\n\",\n      \"✗ [5, 0, 20, 20, 20]\\n\",\n      \"✗ [5, 1, 20, 20, 20]\\n\",\n      \"✗ [5, 3, 20, 20, 20]\\n\",\n      \"✓ [5, 7, 20, 20, 20]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 7]\\n\",\n      \"✗ [5, 7, 20, 20]\\n\",\n      \"✗ [7, 20, 20, 20]\\n\",\n      \"✗ [5, 20, 20, 20]\\n\",\n      \"✗ [5, 7, 20, 20]\\n\",\n      \"✗ [5, 7, 20, 20]\\n\",\n      \"✗ [5, 7, 20, 20]\\n\",\n      \"✗ [0, 7, 20, 20, 20]\\n\",\n      \"✗ [1, 7, 20, 20, 20]\\n\",\n      \"✗ [3, 7, 20, 20, 20]\\n\",\n      \"✗ [4, 7, 20, 20, 20]\\n\",\n      \"✗ [5, 0, 20, 20, 20]\\n\",\n      \"✗ [5, 1, 20, 20, 20]\\n\",\n      \"✗ [5, 3, 20, 20, 20]\\n\",\n      \"✓ [5, 5, 20, 20, 20]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 20, 20]\\n\",\n      \"✗ [5, 20, 20, 20]\\n\",\n      \"✗ [5, 20, 20, 20]\\n\",\n      \"✗ [5, 5, 20, 20]\\n\",\n      \"✗ [5, 5, 20, 20]\\n\",\n      \"✗ [5, 5, 20, 20]\\n\",\n      \"✗ [0, 5, 20, 20, 20]\\n\",\n      \"✗ [1, 5, 20, 20, 20]\\n\",\n      \"✗ [3, 5, 20, 20, 20]\\n\",\n      \"✗ [4, 5, 20, 20, 20]\\n\",\n      \"✗ [5, 0, 20, 20, 20]\\n\",\n      \"✗ [5, 1, 20, 20, 20]\\n\",\n      \"✗ [5, 3, 20, 20, 20]\\n\",\n      \"✗ [5, 4, 20, 20, 20]\\n\",\n      \"✗ [5, 5, 0, 20, 20]\\n\",\n      \"✗ [5, 5, 1, 20, 20]\\n\",\n      \"✗ [5, 5, 3, 20, 20]\\n\",\n      \"✓ [5, 5, 7, 20, 20]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 7, 20]\\n\",\n      \"✗ [5, 7, 20, 20]\\n\",\n      \"✗ [5, 7, 20, 20]\\n\",\n      \"✗ [5, 5, 20, 20]\\n\",\n      \"✗ [5, 5, 7, 20]\\n\",\n      \"✗ [5, 5, 7, 20]\\n\",\n      \"✗ [0, 5, 7, 20, 20]\\n\",\n      \"✗ [1, 5, 7, 20, 20]\\n\",\n      \"✗ [3, 5, 7, 20, 20]\\n\",\n      \"✗ [4, 5, 7, 20, 20]\\n\",\n      \"✗ [5, 0, 7, 20, 20]\\n\",\n      \"✗ [5, 1, 7, 20, 20]\\n\",\n      \"✗ [5, 3, 7, 20, 20]\\n\",\n      \"✗ [5, 4, 7, 20, 20]\\n\",\n      \"✗ [5, 5, 0, 20, 20]\\n\",\n      \"✗ [5, 5, 1, 20, 20]\\n\",\n      \"✗ [5, 5, 3, 20, 20]\\n\",\n      \"✓ [5, 5, 5, 20, 20]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 20]\\n\",\n      \"✗ [5, 5, 20, 20]\\n\",\n      \"✗ [5, 5, 20, 20]\\n\",\n      \"✗ [5, 5, 20, 20]\\n\",\n      \"✗ [5, 5, 5, 20]\\n\",\n      \"✗ [5, 5, 5, 20]\\n\",\n      \"✗ [0, 5, 5, 20, 20]\\n\",\n      \"✗ [1, 5, 5, 20, 20]\\n\",\n      \"✗ [3, 5, 5, 20, 20]\\n\",\n      \"✗ [4, 5, 5, 20, 20]\\n\",\n      \"✗ [5, 0, 5, 20, 20]\\n\",\n      \"✗ [5, 1, 5, 20, 20]\\n\",\n      \"✗ [5, 3, 5, 20, 20]\\n\",\n      \"✗ [5, 4, 5, 20, 20]\\n\",\n      \"✗ [5, 5, 0, 20, 20]\\n\",\n      \"✗ [5, 5, 1, 20, 20]\\n\",\n      \"✗ [5, 5, 3, 20, 20]\\n\",\n      \"✗ [5, 5, 4, 20, 20]\\n\",\n      \"✗ [5, 5, 5, 0, 20]\\n\",\n      \"✗ [5, 5, 5, 1, 20]\\n\",\n      \"✗ [5, 5, 5, 3, 20]\\n\",\n      \"✓ [5, 5, 5, 7, 20]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 7]\\n\",\n      \"✗ [5, 5, 7, 20]\\n\",\n      \"✗ [5, 5, 7, 20]\\n\",\n      \"✗ [5, 5, 7, 20]\\n\",\n      \"✗ [5, 5, 5, 20]\\n\",\n      \"✗ [5, 5, 5, 7]\\n\",\n      \"✗ [0, 5, 5, 7, 20]\\n\",\n      \"✗ [1, 5, 5, 7, 20]\\n\",\n      \"✗ [3, 5, 5, 7, 20]\\n\",\n      \"✗ [4, 5, 5, 7, 20]\\n\",\n      \"✗ [5, 0, 5, 7, 20]\\n\",\n      \"✗ [5, 1, 5, 7, 20]\\n\",\n      \"✗ [5, 3, 5, 7, 20]\\n\",\n      \"✗ [5, 4, 5, 7, 20]\\n\",\n      \"✗ [5, 5, 0, 7, 20]\\n\",\n      \"✗ [5, 5, 1, 7, 20]\\n\",\n      \"✗ [5, 5, 3, 7, 20]\\n\",\n      \"✗ [5, 5, 4, 7, 20]\\n\",\n      \"✗ [5, 5, 5, 0, 20]\\n\",\n      \"✗ [5, 5, 5, 1, 20]\\n\",\n      \"✗ [5, 5, 5, 3, 20]\\n\",\n      \"✓ [5, 5, 5, 5, 20]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 20]\\n\",\n      \"✗ [5, 5, 5, 20]\\n\",\n      \"✗ [5, 5, 5, 20]\\n\",\n      \"✗ [5, 5, 5, 20]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [0, 5, 5, 5, 20]\\n\",\n      \"✗ [1, 5, 5, 5, 20]\\n\",\n      \"✗ [3, 5, 5, 5, 20]\\n\",\n      \"✗ [4, 5, 5, 5, 20]\\n\",\n      \"✗ [5, 0, 5, 5, 20]\\n\",\n      \"✗ [5, 1, 5, 5, 20]\\n\",\n      \"✗ [5, 3, 5, 5, 20]\\n\",\n      \"✗ [5, 4, 5, 5, 20]\\n\",\n      \"✗ [5, 5, 0, 5, 20]\\n\",\n      \"✗ [5, 5, 1, 5, 20]\\n\",\n      \"✗ [5, 5, 3, 5, 20]\\n\",\n      \"✗ [5, 5, 4, 5, 20]\\n\",\n      \"✗ [5, 5, 5, 0, 20]\\n\",\n      \"✗ [5, 5, 5, 1, 20]\\n\",\n      \"✗ [5, 5, 5, 3, 20]\\n\",\n      \"✗ [5, 5, 5, 4, 20]\\n\",\n      \"✗ [5, 5, 5, 5, 0]\\n\",\n      \"✗ [5, 5, 5, 5, 1]\\n\",\n      \"✗ [5, 5, 5, 5, 3]\\n\",\n      \"✓ [5, 5, 5, 5, 7]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 7]\\n\",\n      \"✗ [5, 5, 5, 7]\\n\",\n      \"✗ [5, 5, 5, 7]\\n\",\n      \"✗ [5, 5, 5, 7]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [0, 5, 5, 5, 7]\\n\",\n      \"✗ [1, 5, 5, 5, 7]\\n\",\n      \"✗ [3, 5, 5, 5, 7]\\n\",\n      \"✗ [4, 5, 5, 5, 7]\\n\",\n      \"✗ [5, 0, 5, 5, 7]\\n\",\n      \"✗ [5, 1, 5, 5, 7]\\n\",\n      \"✗ [5, 3, 5, 5, 7]\\n\",\n      \"✗ [5, 4, 5, 5, 7]\\n\",\n      \"✗ [5, 5, 0, 5, 7]\\n\",\n      \"✗ [5, 5, 1, 5, 7]\\n\",\n      \"✗ [5, 5, 3, 5, 7]\\n\",\n      \"✗ [5, 5, 4, 5, 7]\\n\",\n      \"✗ [5, 5, 5, 0, 7]\\n\",\n      \"✗ [5, 5, 5, 1, 7]\\n\",\n      \"✗ [5, 5, 5, 3, 7]\\n\",\n      \"✗ [5, 5, 5, 4, 7]\\n\",\n      \"✗ [5, 5, 5, 5, 0]\\n\",\n      \"✗ [5, 5, 5, 5, 1]\\n\",\n      \"✗ [5, 5, 5, 5, 3]\\n\",\n      \"✓ [5, 5, 5, 5, 5]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [0, 5, 5, 5, 5]\\n\",\n      \"✗ [1, 5, 5, 5, 5]\\n\",\n      \"✗ [3, 5, 5, 5, 5]\\n\",\n      \"✗ [4, 5, 5, 5, 5]\\n\",\n      \"✗ [5, 0, 5, 5, 5]\\n\",\n      \"✗ [5, 1, 5, 5, 5]\\n\",\n      \"✗ [5, 3, 5, 5, 5]\\n\",\n      \"✗ [5, 4, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 0, 5, 5]\\n\",\n      \"✗ [5, 5, 1, 5, 5]\\n\",\n      \"✗ [5, 5, 3, 5, 5]\\n\",\n      \"✗ [5, 5, 4, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 0, 5]\\n\",\n      \"✗ [5, 5, 5, 1, 5]\\n\",\n      \"✗ [5, 5, 5, 3, 5]\\n\",\n      \"✗ [5, 5, 5, 4, 5]\\n\",\n      \"✗ [5, 5, 5, 5, 0]\\n\",\n      \"✗ [5, 5, 5, 5, 1]\\n\",\n      \"✗ [5, 5, 5, 5, 3]\\n\",\n      \"✗ [5, 5, 5, 5, 4]\\n\",\n      \"\\n\",\n      \"12 shrinks with 236 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace(\\n\",\n    \"    [20] * 7,\\n\",\n    \"    lambda x: len([t for t in x if t >= 5]) >= 5,\\n\",\n    \"    partial(greedy_shrink, shrink=shrink4),\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 16,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"def shrink_shared(ls):\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    Look for all sets of shared indices and try to perform a simultaneous shrink on\\n\",\n    \"    their value, replacing all of them at once.\\n\",\n    \"\\n\",\n    \"    In actual Hypothesis we also try replacing only subsets of the values when there\\n\",\n    \"    are more than two shared values, but we won't worry about that here.\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    shared_indices = {}\\n\",\n    \"    for i in range(len(ls)):\\n\",\n    \"        shared_indices.setdefault(ls[i], []).append(i)\\n\",\n    \"    for sharing in shared_indices.values():\\n\",\n    \"        if len(sharing) > 1:\\n\",\n    \"            for v in shrink_integer(ls[sharing[0]]):\\n\",\n    \"                s = list(ls)\\n\",\n    \"                for i in sharing:\\n\",\n    \"                    s[i] = v\\n\",\n    \"                yield s\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"def shrink5(ls):\\n\",\n    \"    yield from shrink_to_prefix(ls)\\n\",\n    \"    yield from delete_individual_elements(ls)\\n\",\n    \"    yield from shrink_shared(ls)\\n\",\n    \"    yield from shrink_individual_elements(ls)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 17,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [20, 20, 20, 20, 20, 20, 20]\\n\",\n      \"✗ [20]\\n\",\n      \"✗ [20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✓ [20, 20, 20, 20, 20, 20]\\n\",\n      \"✗ [20]\\n\",\n      \"✗ [20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✓ [20, 20, 20, 20, 20]\\n\",\n      \"✗ [20]\\n\",\n      \"✗ [20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✗ [20, 20, 20, 20]\\n\",\n      \"✗ [0, 0, 0, 0, 0]\\n\",\n      \"✗ [1, 1, 1, 1, 1]\\n\",\n      \"✗ [3, 3, 3, 3, 3]\\n\",\n      \"✓ [7, 7, 7, 7, 7]\\n\",\n      \"✗ [7]\\n\",\n      \"✗ [7, 7]\\n\",\n      \"✗ [7, 7, 7, 7]\\n\",\n      \"✗ [7, 7, 7, 7]\\n\",\n      \"✗ [7, 7, 7, 7]\\n\",\n      \"✗ [7, 7, 7, 7]\\n\",\n      \"✗ [7, 7, 7, 7]\\n\",\n      \"✗ [7, 7, 7, 7]\\n\",\n      \"✗ [0, 0, 0, 0, 0]\\n\",\n      \"✗ [1, 1, 1, 1, 1]\\n\",\n      \"✗ [3, 3, 3, 3, 3]\\n\",\n      \"✓ [5, 5, 5, 5, 5]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [0, 0, 0, 0, 0]\\n\",\n      \"✗ [1, 1, 1, 1, 1]\\n\",\n      \"✗ [3, 3, 3, 3, 3]\\n\",\n      \"✗ [4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 5, 5, 5, 5]\\n\",\n      \"✗ [1, 5, 5, 5, 5]\\n\",\n      \"✗ [3, 5, 5, 5, 5]\\n\",\n      \"✗ [4, 5, 5, 5, 5]\\n\",\n      \"✗ [5, 0, 5, 5, 5]\\n\",\n      \"✗ [5, 1, 5, 5, 5]\\n\",\n      \"✗ [5, 3, 5, 5, 5]\\n\",\n      \"✗ [5, 4, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 0, 5, 5]\\n\",\n      \"✗ [5, 5, 1, 5, 5]\\n\",\n      \"✗ [5, 5, 3, 5, 5]\\n\",\n      \"✗ [5, 5, 4, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 0, 5]\\n\",\n      \"✗ [5, 5, 5, 1, 5]\\n\",\n      \"✗ [5, 5, 5, 3, 5]\\n\",\n      \"✗ [5, 5, 5, 4, 5]\\n\",\n      \"✗ [5, 5, 5, 5, 0]\\n\",\n      \"✗ [5, 5, 5, 5, 1]\\n\",\n      \"✗ [5, 5, 5, 5, 3]\\n\",\n      \"✗ [5, 5, 5, 5, 4]\\n\",\n      \"\\n\",\n      \"4 shrinks with 64 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace(\\n\",\n    \"    [20] * 7,\\n\",\n    \"    lambda x: len([t for t in x if t >= 5]) >= 5,\\n\",\n    \"    partial(greedy_shrink, shrink=shrink5),\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"This achieves the desired result. We rapidly progress through all of the intermediate stages. We do still have to perform individual shrinks at the end unfortunately (this is unavoidable), but the size of the elements is much smaller now so it takes less time.\\n\",\n    \"\\n\",\n    \"Unfortunately while this solves the problem in this case it's almost useless, because unless you find yourself in the exact right starting position it never does anything.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 18,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [20, 21, 22, 23, 24, 25, 26]\\n\",\n      \"✗ [20]\\n\",\n      \"✗ [20, 21]\\n\",\n      \"✗ [20, 21, 22, 23]\\n\",\n      \"✓ [21, 22, 23, 24, 25, 26]\\n\",\n      \"✗ [21]\\n\",\n      \"✗ [21, 22]\\n\",\n      \"✗ [21, 22, 23, 24]\\n\",\n      \"✓ [22, 23, 24, 25, 26]\\n\",\n      \"✗ [22]\\n\",\n      \"✗ [22, 23]\\n\",\n      \"✗ [22, 23, 24, 25]\\n\",\n      \"✗ [23, 24, 25, 26]\\n\",\n      \"✗ [22, 24, 25, 26]\\n\",\n      \"✗ [22, 23, 25, 26]\\n\",\n      \"✗ [22, 23, 24, 26]\\n\",\n      \"✗ [22, 23, 24, 25]\\n\",\n      \"✗ [0, 23, 24, 25, 26]\\n\",\n      \"✗ [1, 23, 24, 25, 26]\\n\",\n      \"✗ [3, 23, 24, 25, 26]\\n\",\n      \"✓ [7, 23, 24, 25, 26]\\n\",\n      \"✗ [7]\\n\",\n      \"✗ [7, 23]\\n\",\n      \"✗ [7, 23, 24, 25]\\n\",\n      \"✗ [23, 24, 25, 26]\\n\",\n      \"✗ [7, 24, 25, 26]\\n\",\n      \"✗ [7, 23, 25, 26]\\n\",\n      \"✗ [7, 23, 24, 26]\\n\",\n      \"✗ [7, 23, 24, 25]\\n\",\n      \"✗ [0, 23, 24, 25, 26]\\n\",\n      \"✗ [1, 23, 24, 25, 26]\\n\",\n      \"✗ [3, 23, 24, 25, 26]\\n\",\n      \"✓ [5, 23, 24, 25, 26]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 23]\\n\",\n      \"✗ [5, 23, 24, 25]\\n\",\n      \"✗ [23, 24, 25, 26]\\n\",\n      \"✗ [5, 24, 25, 26]\\n\",\n      \"✗ [5, 23, 25, 26]\\n\",\n      \"✗ [5, 23, 24, 26]\\n\",\n      \"✗ [5, 23, 24, 25]\\n\",\n      \"✗ [0, 23, 24, 25, 26]\\n\",\n      \"✗ [1, 23, 24, 25, 26]\\n\",\n      \"✗ [3, 23, 24, 25, 26]\\n\",\n      \"✗ [4, 23, 24, 25, 26]\\n\",\n      \"✗ [5, 0, 24, 25, 26]\\n\",\n      \"✗ [5, 1, 24, 25, 26]\\n\",\n      \"✗ [5, 3, 24, 25, 26]\\n\",\n      \"✓ [5, 7, 24, 25, 26]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 7]\\n\",\n      \"✗ [5, 7, 24, 25]\\n\",\n      \"✗ [7, 24, 25, 26]\\n\",\n      \"✗ [5, 24, 25, 26]\\n\",\n      \"✗ [5, 7, 25, 26]\\n\",\n      \"✗ [5, 7, 24, 26]\\n\",\n      \"✗ [5, 7, 24, 25]\\n\",\n      \"✗ [0, 7, 24, 25, 26]\\n\",\n      \"✗ [1, 7, 24, 25, 26]\\n\",\n      \"✗ [3, 7, 24, 25, 26]\\n\",\n      \"✗ [4, 7, 24, 25, 26]\\n\",\n      \"✗ [5, 0, 24, 25, 26]\\n\",\n      \"✗ [5, 1, 24, 25, 26]\\n\",\n      \"✗ [5, 3, 24, 25, 26]\\n\",\n      \"✓ [5, 5, 24, 25, 26]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 24, 25]\\n\",\n      \"✗ [5, 24, 25, 26]\\n\",\n      \"✗ [5, 24, 25, 26]\\n\",\n      \"✗ [5, 5, 25, 26]\\n\",\n      \"✗ [5, 5, 24, 26]\\n\",\n      \"✗ [5, 5, 24, 25]\\n\",\n      \"✗ [0, 0, 24, 25, 26]\\n\",\n      \"✗ [1, 1, 24, 25, 26]\\n\",\n      \"✗ [3, 3, 24, 25, 26]\\n\",\n      \"✗ [4, 4, 24, 25, 26]\\n\",\n      \"✗ [0, 5, 24, 25, 26]\\n\",\n      \"✗ [1, 5, 24, 25, 26]\\n\",\n      \"✗ [3, 5, 24, 25, 26]\\n\",\n      \"✗ [4, 5, 24, 25, 26]\\n\",\n      \"✗ [5, 0, 24, 25, 26]\\n\",\n      \"✗ [5, 1, 24, 25, 26]\\n\",\n      \"✗ [5, 3, 24, 25, 26]\\n\",\n      \"✗ [5, 4, 24, 25, 26]\\n\",\n      \"✗ [5, 5, 0, 25, 26]\\n\",\n      \"✗ [5, 5, 1, 25, 26]\\n\",\n      \"✗ [5, 5, 3, 25, 26]\\n\",\n      \"✓ [5, 5, 7, 25, 26]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 7, 25]\\n\",\n      \"✗ [5, 7, 25, 26]\\n\",\n      \"✗ [5, 7, 25, 26]\\n\",\n      \"✗ [5, 5, 25, 26]\\n\",\n      \"✗ [5, 5, 7, 26]\\n\",\n      \"✗ [5, 5, 7, 25]\\n\",\n      \"✗ [0, 0, 7, 25, 26]\\n\",\n      \"✗ [1, 1, 7, 25, 26]\\n\",\n      \"✗ [3, 3, 7, 25, 26]\\n\",\n      \"✗ [4, 4, 7, 25, 26]\\n\",\n      \"✗ [0, 5, 7, 25, 26]\\n\",\n      \"✗ [1, 5, 7, 25, 26]\\n\",\n      \"✗ [3, 5, 7, 25, 26]\\n\",\n      \"✗ [4, 5, 7, 25, 26]\\n\",\n      \"✗ [5, 0, 7, 25, 26]\\n\",\n      \"✗ [5, 1, 7, 25, 26]\\n\",\n      \"✗ [5, 3, 7, 25, 26]\\n\",\n      \"✗ [5, 4, 7, 25, 26]\\n\",\n      \"✗ [5, 5, 0, 25, 26]\\n\",\n      \"✗ [5, 5, 1, 25, 26]\\n\",\n      \"✗ [5, 5, 3, 25, 26]\\n\",\n      \"✓ [5, 5, 5, 25, 26]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 25]\\n\",\n      \"✗ [5, 5, 25, 26]\\n\",\n      \"✗ [5, 5, 25, 26]\\n\",\n      \"✗ [5, 5, 25, 26]\\n\",\n      \"✗ [5, 5, 5, 26]\\n\",\n      \"✗ [5, 5, 5, 25]\\n\",\n      \"✗ [0, 0, 0, 25, 26]\\n\",\n      \"✗ [1, 1, 1, 25, 26]\\n\",\n      \"✗ [3, 3, 3, 25, 26]\\n\",\n      \"✗ [4, 4, 4, 25, 26]\\n\",\n      \"✗ [0, 5, 5, 25, 26]\\n\",\n      \"✗ [1, 5, 5, 25, 26]\\n\",\n      \"✗ [3, 5, 5, 25, 26]\\n\",\n      \"✗ [4, 5, 5, 25, 26]\\n\",\n      \"✗ [5, 0, 5, 25, 26]\\n\",\n      \"✗ [5, 1, 5, 25, 26]\\n\",\n      \"✗ [5, 3, 5, 25, 26]\\n\",\n      \"✗ [5, 4, 5, 25, 26]\\n\",\n      \"✗ [5, 5, 0, 25, 26]\\n\",\n      \"✗ [5, 5, 1, 25, 26]\\n\",\n      \"✗ [5, 5, 3, 25, 26]\\n\",\n      \"✗ [5, 5, 4, 25, 26]\\n\",\n      \"✗ [5, 5, 5, 0, 26]\\n\",\n      \"✗ [5, 5, 5, 1, 26]\\n\",\n      \"✗ [5, 5, 5, 3, 26]\\n\",\n      \"✓ [5, 5, 5, 7, 26]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 7]\\n\",\n      \"✗ [5, 5, 7, 26]\\n\",\n      \"✗ [5, 5, 7, 26]\\n\",\n      \"✗ [5, 5, 7, 26]\\n\",\n      \"✗ [5, 5, 5, 26]\\n\",\n      \"✗ [5, 5, 5, 7]\\n\",\n      \"✗ [0, 0, 0, 7, 26]\\n\",\n      \"✗ [1, 1, 1, 7, 26]\\n\",\n      \"✗ [3, 3, 3, 7, 26]\\n\",\n      \"✗ [4, 4, 4, 7, 26]\\n\",\n      \"✗ [0, 5, 5, 7, 26]\\n\",\n      \"✗ [1, 5, 5, 7, 26]\\n\",\n      \"✗ [3, 5, 5, 7, 26]\\n\",\n      \"✗ [4, 5, 5, 7, 26]\\n\",\n      \"✗ [5, 0, 5, 7, 26]\\n\",\n      \"✗ [5, 1, 5, 7, 26]\\n\",\n      \"✗ [5, 3, 5, 7, 26]\\n\",\n      \"✗ [5, 4, 5, 7, 26]\\n\",\n      \"✗ [5, 5, 0, 7, 26]\\n\",\n      \"✗ [5, 5, 1, 7, 26]\\n\",\n      \"✗ [5, 5, 3, 7, 26]\\n\",\n      \"✗ [5, 5, 4, 7, 26]\\n\",\n      \"✗ [5, 5, 5, 0, 26]\\n\",\n      \"✗ [5, 5, 5, 1, 26]\\n\",\n      \"✗ [5, 5, 5, 3, 26]\\n\",\n      \"✓ [5, 5, 5, 5, 26]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 26]\\n\",\n      \"✗ [5, 5, 5, 26]\\n\",\n      \"✗ [5, 5, 5, 26]\\n\",\n      \"✗ [5, 5, 5, 26]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [0, 0, 0, 0, 26]\\n\",\n      \"✗ [1, 1, 1, 1, 26]\\n\",\n      \"✗ [3, 3, 3, 3, 26]\\n\",\n      \"✗ [4, 4, 4, 4, 26]\\n\",\n      \"✗ [0, 5, 5, 5, 26]\\n\",\n      \"✗ [1, 5, 5, 5, 26]\\n\",\n      \"✗ [3, 5, 5, 5, 26]\\n\",\n      \"✗ [4, 5, 5, 5, 26]\\n\",\n      \"✗ [5, 0, 5, 5, 26]\\n\",\n      \"✗ [5, 1, 5, 5, 26]\\n\",\n      \"✗ [5, 3, 5, 5, 26]\\n\",\n      \"✗ [5, 4, 5, 5, 26]\\n\",\n      \"✗ [5, 5, 0, 5, 26]\\n\",\n      \"✗ [5, 5, 1, 5, 26]\\n\",\n      \"✗ [5, 5, 3, 5, 26]\\n\",\n      \"✗ [5, 5, 4, 5, 26]\\n\",\n      \"✗ [5, 5, 5, 0, 26]\\n\",\n      \"✗ [5, 5, 5, 1, 26]\\n\",\n      \"✗ [5, 5, 5, 3, 26]\\n\",\n      \"✗ [5, 5, 5, 4, 26]\\n\",\n      \"✗ [5, 5, 5, 5, 0]\\n\",\n      \"✗ [5, 5, 5, 5, 1]\\n\",\n      \"✗ [5, 5, 5, 5, 3]\\n\",\n      \"✓ [5, 5, 5, 5, 7]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 7]\\n\",\n      \"✗ [5, 5, 5, 7]\\n\",\n      \"✗ [5, 5, 5, 7]\\n\",\n      \"✗ [5, 5, 5, 7]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [0, 0, 0, 0, 7]\\n\",\n      \"✗ [1, 1, 1, 1, 7]\\n\",\n      \"✗ [3, 3, 3, 3, 7]\\n\",\n      \"✗ [4, 4, 4, 4, 7]\\n\",\n      \"✗ [0, 5, 5, 5, 7]\\n\",\n      \"✗ [1, 5, 5, 5, 7]\\n\",\n      \"✗ [3, 5, 5, 5, 7]\\n\",\n      \"✗ [4, 5, 5, 5, 7]\\n\",\n      \"✗ [5, 0, 5, 5, 7]\\n\",\n      \"✗ [5, 1, 5, 5, 7]\\n\",\n      \"✗ [5, 3, 5, 5, 7]\\n\",\n      \"✗ [5, 4, 5, 5, 7]\\n\",\n      \"✗ [5, 5, 0, 5, 7]\\n\",\n      \"✗ [5, 5, 1, 5, 7]\\n\",\n      \"✗ [5, 5, 3, 5, 7]\\n\",\n      \"✗ [5, 5, 4, 5, 7]\\n\",\n      \"✗ [5, 5, 5, 0, 7]\\n\",\n      \"✗ [5, 5, 5, 1, 7]\\n\",\n      \"✗ [5, 5, 5, 3, 7]\\n\",\n      \"✗ [5, 5, 5, 4, 7]\\n\",\n      \"✗ [5, 5, 5, 5, 0]\\n\",\n      \"✗ [5, 5, 5, 5, 1]\\n\",\n      \"✗ [5, 5, 5, 5, 3]\\n\",\n      \"✓ [5, 5, 5, 5, 5]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [0, 0, 0, 0, 0]\\n\",\n      \"✗ [1, 1, 1, 1, 1]\\n\",\n      \"✗ [3, 3, 3, 3, 3]\\n\",\n      \"✗ [4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 5, 5, 5, 5]\\n\",\n      \"✗ [1, 5, 5, 5, 5]\\n\",\n      \"✗ [3, 5, 5, 5, 5]\\n\",\n      \"✗ [4, 5, 5, 5, 5]\\n\",\n      \"✗ [5, 0, 5, 5, 5]\\n\",\n      \"✗ [5, 1, 5, 5, 5]\\n\",\n      \"✗ [5, 3, 5, 5, 5]\\n\",\n      \"✗ [5, 4, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 0, 5, 5]\\n\",\n      \"✗ [5, 5, 1, 5, 5]\\n\",\n      \"✗ [5, 5, 3, 5, 5]\\n\",\n      \"✗ [5, 5, 4, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 0, 5]\\n\",\n      \"✗ [5, 5, 5, 1, 5]\\n\",\n      \"✗ [5, 5, 5, 3, 5]\\n\",\n      \"✗ [5, 5, 5, 4, 5]\\n\",\n      \"✗ [5, 5, 5, 5, 0]\\n\",\n      \"✗ [5, 5, 5, 5, 1]\\n\",\n      \"✗ [5, 5, 5, 5, 3]\\n\",\n      \"✗ [5, 5, 5, 5, 4]\\n\",\n      \"\\n\",\n      \"12 shrinks with 264 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace(\\n\",\n    \"    [20 + i for i in range(7)],\\n\",\n    \"    lambda x: len([t for t in x if t >= 5]) >= 5,\\n\",\n    \"    partial(greedy_shrink, shrink=shrink5),\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"So what we're going to try to do is to try a simplification first which *creates* that exact right starting condition. Further it's one that will be potentially very useful even if we don't actually have the situation where we have shared shrinks.\\n\",\n    \"\\n\",\n    \"What we're going to do is we're going to use values from the list to act as evidence for how complex things need to be. Starting from the smallest, we'll try capping the array at each individual value and see what happens.\\n\",\n    \"\\n\",\n    \"As well as being potentially a very rapid shrink, this creates lists with lots of duplicates, which enables the simultaneous shrinking to shine.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 19,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"def replace_with_simpler(ls):\\n\",\n    \"    if not ls:\\n\",\n    \"        return\\n\",\n    \"    values = set(ls)\\n\",\n    \"    values.remove(max(ls))\\n\",\n    \"    values = sorted(values)\\n\",\n    \"    for v in values:\\n\",\n    \"        yield [min(v, l) for l in ls]\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"def shrink6(ls):\\n\",\n    \"    yield from shrink_to_prefix(ls)\\n\",\n    \"    yield from delete_individual_elements(ls)\\n\",\n    \"    yield from replace_with_simpler(ls)\\n\",\n    \"    yield from shrink_shared(ls)\\n\",\n    \"    yield from shrink_individual_elements(ls)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 20,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [20, 21, 22, 23, 24, 25, 26]\\n\",\n      \"✗ [20]\\n\",\n      \"✗ [20, 21]\\n\",\n      \"✗ [20, 21, 22, 23]\\n\",\n      \"✓ [21, 22, 23, 24, 25, 26]\\n\",\n      \"✗ [21]\\n\",\n      \"✗ [21, 22]\\n\",\n      \"✗ [21, 22, 23, 24]\\n\",\n      \"✓ [22, 23, 24, 25, 26]\\n\",\n      \"✗ [22]\\n\",\n      \"✗ [22, 23]\\n\",\n      \"✗ [22, 23, 24, 25]\\n\",\n      \"✗ [23, 24, 25, 26]\\n\",\n      \"✗ [22, 24, 25, 26]\\n\",\n      \"✗ [22, 23, 25, 26]\\n\",\n      \"✗ [22, 23, 24, 26]\\n\",\n      \"✗ [22, 23, 24, 25]\\n\",\n      \"✓ [22, 22, 22, 22, 22]\\n\",\n      \"✗ [22]\\n\",\n      \"✗ [22, 22]\\n\",\n      \"✗ [22, 22, 22, 22]\\n\",\n      \"✗ [22, 22, 22, 22]\\n\",\n      \"✗ [22, 22, 22, 22]\\n\",\n      \"✗ [22, 22, 22, 22]\\n\",\n      \"✗ [22, 22, 22, 22]\\n\",\n      \"✗ [22, 22, 22, 22]\\n\",\n      \"✗ [0, 0, 0, 0, 0]\\n\",\n      \"✗ [1, 1, 1, 1, 1]\\n\",\n      \"✗ [3, 3, 3, 3, 3]\\n\",\n      \"✓ [7, 7, 7, 7, 7]\\n\",\n      \"✗ [7]\\n\",\n      \"✗ [7, 7]\\n\",\n      \"✗ [7, 7, 7, 7]\\n\",\n      \"✗ [7, 7, 7, 7]\\n\",\n      \"✗ [7, 7, 7, 7]\\n\",\n      \"✗ [7, 7, 7, 7]\\n\",\n      \"✗ [7, 7, 7, 7]\\n\",\n      \"✗ [7, 7, 7, 7]\\n\",\n      \"✗ [0, 0, 0, 0, 0]\\n\",\n      \"✗ [1, 1, 1, 1, 1]\\n\",\n      \"✗ [3, 3, 3, 3, 3]\\n\",\n      \"✓ [5, 5, 5, 5, 5]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✗ [0, 0, 0, 0, 0]\\n\",\n      \"✗ [1, 1, 1, 1, 1]\\n\",\n      \"✗ [3, 3, 3, 3, 3]\\n\",\n      \"✗ [4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 5, 5, 5, 5]\\n\",\n      \"✗ [1, 5, 5, 5, 5]\\n\",\n      \"✗ [3, 5, 5, 5, 5]\\n\",\n      \"✗ [4, 5, 5, 5, 5]\\n\",\n      \"✗ [5, 0, 5, 5, 5]\\n\",\n      \"✗ [5, 1, 5, 5, 5]\\n\",\n      \"✗ [5, 3, 5, 5, 5]\\n\",\n      \"✗ [5, 4, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 0, 5, 5]\\n\",\n      \"✗ [5, 5, 1, 5, 5]\\n\",\n      \"✗ [5, 5, 3, 5, 5]\\n\",\n      \"✗ [5, 5, 4, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 0, 5]\\n\",\n      \"✗ [5, 5, 5, 1, 5]\\n\",\n      \"✗ [5, 5, 5, 3, 5]\\n\",\n      \"✗ [5, 5, 5, 4, 5]\\n\",\n      \"✗ [5, 5, 5, 5, 0]\\n\",\n      \"✗ [5, 5, 5, 5, 1]\\n\",\n      \"✗ [5, 5, 5, 5, 3]\\n\",\n      \"✗ [5, 5, 5, 5, 4]\\n\",\n      \"\\n\",\n      \"5 shrinks with 73 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace(\\n\",\n    \"    [20 + i for i in range(7)],\\n\",\n    \"    lambda x: len([t for t in x if t >= 5]) >= 5,\\n\",\n    \"    partial(greedy_shrink, shrink=shrink6),\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"Now we're going to start looking at some numbers.\\n\",\n    \"\\n\",\n    \"What we'll do is we'll generate 1000 random lists satisfying some predicate, and then simplify them down to the smallest possible examples satisfying those predicates. This lets us verify that these aren't just cherry-picked examples and our methods help in the general case. We fix the set of examples per predicate so that we're comparing like for like.\\n\",\n    \"\\n\",\n    \"A more proper statistical treatment would probably be a good idea.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 21,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"from collections import OrderedDict\\n\",\n    \"\\n\",\n    \"conditions = OrderedDict(\\n\",\n    \"    [\\n\",\n    \"        (\\\"length >= 2\\\", lambda xs: len(xs) >= 2),\\n\",\n    \"        (\\\"sum >= 500\\\", lambda xs: sum(xs) >= 500),\\n\",\n    \"        (\\\"sum >= 3\\\", lambda xs: sum(xs) >= 3),\\n\",\n    \"        (\\\"At least 10 by 5\\\", lambda xs: len([t for t in xs if t >= 5]) >= 10),\\n\",\n    \"    ]\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 22,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"[17861213645196285187,\\n\",\n       \" 15609796832515195084,\\n\",\n       \" 8808697621832673046,\\n\",\n       \" 1013319847337885109,\\n\",\n       \" 1252281976438780211,\\n\",\n       \" 15526909770962854196,\\n\",\n       \" 2065337703776048239,\\n\",\n       \" 11654092230944134701,\\n\",\n       \" 5554896851708700201,\\n\",\n       \" 17485190250805381572,\\n\",\n       \" 7700396730246958474,\\n\",\n       \" 402840882133605445,\\n\",\n       \" 5303116940477413125,\\n\",\n       \" 7459257850255946545,\\n\",\n       \" 10349184495871650178,\\n\",\n       \" 4361155591615075311,\\n\",\n       \" 15194020468024244632,\\n\",\n       \" 14428821588688846242,\\n\",\n       \" 5754975712549869618,\\n\",\n       \" 13740966788951413307,\\n\",\n       \" 15209704957418077856,\\n\",\n       \" 12562588328524673262,\\n\",\n       \" 8415556016795311987,\\n\",\n       \" 3993098291779210741,\\n\",\n       \" 16874756914619597640,\\n\",\n       \" 7932421182532982309,\\n\",\n       \" 1080869529149674704,\\n\",\n       \" 13878842261614060122,\\n\",\n       \" 229976195287031921,\\n\",\n       \" 8378461140013520338,\\n\",\n       \" 6189522326946191255,\\n\",\n       \" 16684625600934047114,\\n\",\n       \" 12533448641134015292,\\n\",\n       \" 10459192142175991903,\\n\",\n       \" 15688511015570391481,\\n\",\n       \" 3091340728247101611,\\n\",\n       \" 4034760776171697910,\\n\",\n       \" 6258572097778886531,\\n\",\n       \" 13555449085571665140,\\n\",\n       \" 6727488149749641424,\\n\",\n       \" 7125107819562430884,\\n\",\n       \" 1557872425804423698,\\n\",\n       \" 4810250441100696888,\\n\",\n       \" 10500486959813930693,\\n\",\n       \" 841300069403644975,\\n\",\n       \" 9278626999406014662,\\n\",\n       \" 17219731431761688449,\\n\",\n       \" 15650446646901259126,\\n\",\n       \" 8683172055034528265,\\n\",\n       \" 5138373693056086816,\\n\",\n       \" 4055877702343936882,\\n\",\n       \" 5696765901584750542,\\n\",\n       \" 7133363948804979946,\\n\",\n       \" 988518370429658551,\\n\",\n       \" 16302597472193523184,\\n\",\n       \" 579078764159525857,\\n\",\n       \" 10678347012503400890,\\n\",\n       \" 8433836779160269996,\\n\",\n       \" 13884258181758870664,\\n\",\n       \" 13594877609651310055]\"\n      ]\n     },\n     \"execution_count\": 22,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"import random\\n\",\n    \"\\n\",\n    \"N_EXAMPLES = 1000\\n\",\n    \"\\n\",\n    \"datasets = {}\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"def gen_list(rnd):\\n\",\n    \"    return [random.getrandbits(64) for _ in range(random.randint(0, 100))]\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"def dataset_for(condition):\\n\",\n    \"    if condition in datasets:\\n\",\n    \"        return datasets[condition]\\n\",\n    \"    constraint = conditions[condition]\\n\",\n    \"    dataset = []\\n\",\n    \"    rnd = random.Random(condition)\\n\",\n    \"    while len(dataset) < N_EXAMPLES:\\n\",\n    \"        ls = gen_list(rnd)\\n\",\n    \"        if constraint(ls):\\n\",\n    \"            dataset.append(ls)\\n\",\n    \"    datasets[condition] = dataset\\n\",\n    \"    return dataset\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"dataset_for(\\\"sum >= 3\\\")[1]\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 23,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"13\"\n      ]\n     },\n     \"execution_count\": 23,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"# In order to avoid run-away cases where things will take basically forever\\n\",\n    \"# we cap at 5000 as \\\"you've taken too long. Stop it\\\". Because we're only ever\\n\",\n    \"# showing the worst case scenario we'll just display this as > 5000 if we ever\\n\",\n    \"# hit it and it won't distort statistics.\\n\",\n    \"MAX_COUNT = 5000\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"class MaximumCountExceeded(Exception):\\n\",\n    \"    pass\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"def call_counts(condition, simplifier):\\n\",\n    \"    constraint = conditions[condition]\\n\",\n    \"    dataset = dataset_for(condition)\\n\",\n    \"    counts = []\\n\",\n    \"\\n\",\n    \"    for ex in dataset:\\n\",\n    \"        counter = 0\\n\",\n    \"\\n\",\n    \"        def run_and_count(ls):\\n\",\n    \"            nonlocal counter\\n\",\n    \"            counter += 1\\n\",\n    \"            if counter > MAX_COUNT:\\n\",\n    \"                raise MaximumCountExceeded\\n\",\n    \"            return constraint(ls)\\n\",\n    \"\\n\",\n    \"        try:\\n\",\n    \"            simplifier(ex, run_and_count)\\n\",\n    \"            counts.append(counter)\\n\",\n    \"        except MaximumCountExceeded:\\n\",\n    \"            counts.append(MAX_COUNT + 1)\\n\",\n    \"            break\\n\",\n    \"    return counts\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"def worst_case(condition, simplifier):\\n\",\n    \"    return max(call_counts(condition, simplifier))\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"worst_case(\\\"length >= 2\\\", partial(greedy_shrink, shrink=shrink6))\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 24,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"from IPython.display import HTML\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"def compare_simplifiers(named_simplifiers):\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    Given a list of (name, simplifier) pairs, output a table comparing\\n\",\n    \"    the worst case performance of each on our current set of examples.\\n\",\n    \"    \\\"\\\"\\\"\\n\",\n    \"    html_fragments = []\\n\",\n    \"    html_fragments.append(\\\"<table>\\\\n<thead>\\\\n<tr>\\\")\\n\",\n    \"    header = [\\\"Condition\\\"]\\n\",\n    \"    header.extend(name for name, _ in named_simplifiers)\\n\",\n    \"    for h in header:\\n\",\n    \"        html_fragments.append(\\\"<th>%s</th>\\\" % (h,))\\n\",\n    \"    html_fragments.append(\\\"</tr>\\\\n</thead>\\\\n<tbody>\\\")\\n\",\n    \"\\n\",\n    \"    for name in conditions:\\n\",\n    \"        bits = [name.replace(\\\">\\\", \\\"&gt;\\\")]\\n\",\n    \"        for _, simplifier in named_simplifiers:\\n\",\n    \"            value = worst_case(name, simplifier)\\n\",\n    \"            if value <= MAX_COUNT:\\n\",\n    \"                bits.append(str(value))\\n\",\n    \"            else:\\n\",\n    \"                bits.append(\\\" &gt; %d\\\" % (MAX_COUNT,))\\n\",\n    \"        html_fragments.append(\\\"<tr>  \\\")\\n\",\n    \"        html_fragments.append(\\\" \\\".join(\\\"<td>%s</td>\\\" % (b,) for b in bits))\\n\",\n    \"        html_fragments.append(\\\"</tr>\\\")\\n\",\n    \"    html_fragments.append(\\\"</tbody>\\\\n</table>\\\")\\n\",\n    \"    return HTML(\\\"\\\\n\\\".join(html_fragments))\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 25,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/html\": [\n       \"<table>\\n\",\n       \"<thead>\\n\",\n       \"<tr>\\n\",\n       \"<th>Condition</th>\\n\",\n       \"<th>2</th>\\n\",\n       \"<th>3</th>\\n\",\n       \"<th>4</th>\\n\",\n       \"<th>5</th>\\n\",\n       \"<th>6</th>\\n\",\n       \"</tr>\\n\",\n       \"</thead>\\n\",\n       \"<tbody>\\n\",\n       \"<tr>  \\n\",\n       \"<td>length &gt;= 2</td> <td>106</td> <td>105</td> <td>13</td> <td>13</td> <td>13</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>sum &gt;= 500</td> <td>1102</td> <td>178</td> <td>80</td> <td>80</td> <td>80</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>sum &gt;= 3</td> <td>108</td> <td>107</td> <td>9</td> <td>9</td> <td>9</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>At least 10 by 5</td> <td>535</td> <td>690</td> <td>809</td> <td>877</td> <td>144</td>\\n\",\n       \"</tr>\\n\",\n       \"</tbody>\\n\",\n       \"</table>\"\n      ],\n      \"text/plain\": [\n       \"<IPython.core.display.HTML object>\"\n      ]\n     },\n     \"execution_count\": 25,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"compare_simplifiers(\\n\",\n    \"    [\\n\",\n    \"        (f.__name__[-1], partial(greedy_shrink, shrink=f))\\n\",\n    \"        for f in [shrink2, shrink3, shrink4, shrink5, shrink6]\\n\",\n    \"    ]\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"So you can see from the above table, the iterations 2 through 5 were a little ambiguous ion that they helped a lot in the cases they were designed to help with but hurt in other cases. 6 however is clearly the best of the lot, being no worse than any of the others on any of the cases and often significantly better.\\n\",\n    \"\\n\",\n    \"Rather than continuing to refine our shrink further, we instead look to improvements to how we use shrinking. We'll start by noting a simple optimization: If you look at our traces above, we often checked the same example twice. We're only interested in deterministic conditions, so this isn't useful to do. So we'll start by simply pruning out all duplicates. This should have exactly the same set and order of successful shrinks but will avoid a bunch of redundant work.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 26,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"def greedy_shrink_with_dedupe(ls, constraint, shrink):\\n\",\n    \"    seen = set()\\n\",\n    \"    while True:\\n\",\n    \"        for s in shrink(ls):\\n\",\n    \"            key = tuple(s)\\n\",\n    \"            if key in seen:\\n\",\n    \"                continue\\n\",\n    \"            seen.add(key)\\n\",\n    \"            if constraint(s):\\n\",\n    \"                ls = s\\n\",\n    \"                break\\n\",\n    \"        else:\\n\",\n    \"            return ls\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 27,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/html\": [\n       \"<table>\\n\",\n       \"<thead>\\n\",\n       \"<tr>\\n\",\n       \"<th>Condition</th>\\n\",\n       \"<th>Normal</th>\\n\",\n       \"<th>Deduped</th>\\n\",\n       \"</tr>\\n\",\n       \"</thead>\\n\",\n       \"<tbody>\\n\",\n       \"<tr>  \\n\",\n       \"<td>length &gt;= 2</td> <td>13</td> <td>6</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>sum &gt;= 500</td> <td>80</td> <td>35</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>sum &gt;= 3</td> <td>9</td> <td>6</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>At least 10 by 5</td> <td>144</td> <td>107</td>\\n\",\n       \"</tr>\\n\",\n       \"</tbody>\\n\",\n       \"</table>\"\n      ],\n      \"text/plain\": [\n       \"<IPython.core.display.HTML object>\"\n      ]\n     },\n     \"execution_count\": 27,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"compare_simplifiers(\\n\",\n    \"    [\\n\",\n    \"        (\\\"Normal\\\", partial(greedy_shrink, shrink=shrink6)),\\n\",\n    \"        (\\\"Deduped\\\", partial(greedy_shrink_with_dedupe, shrink=shrink6)),\\n\",\n    \"    ]\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"As expected, this is a significant improvement in some cases. It is logically impossible that it could ever make things worse, but it's nice that it makes it better.\\n\",\n    \"\\n\",\n    \"So far we've only looked at things where the interaction between elements was fairly light - the sum cases the values of other elements mattered a bit, but shrinking an integer could never enable other shrinks. Let's look at one where this is not the case: Where our condition is that we have at least 10 distinct elements.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 28,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [100, 101, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [100]\\n\",\n      \"✗ [100, 101]\\n\",\n      \"✗ [100, 101, 102, 103]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 107]\\n\",\n      \"✗ [101, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [100, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [100, 101, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [100, 101, 102, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [100, 101, 102, 103, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 106, 107, 108, 109]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 107, 108, 109]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 108, 109]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 107, 109]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 107, 108]\\n\",\n      \"✗ [100, 100, 100, 100, 100, 100, 100, 100, 100, 100]\\n\",\n      \"✗ [100, 101, 101, 101, 101, 101, 101, 101, 101, 101]\\n\",\n      \"✗ [100, 101, 102, 102, 102, 102, 102, 102, 102, 102]\\n\",\n      \"✗ [100, 101, 102, 103, 103, 103, 103, 103, 103, 103]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 104, 104, 104, 104, 104]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 105, 105, 105, 105]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 106, 106, 106]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 107, 107, 107]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 107, 108, 108]\\n\",\n      \"✓ [0, 101, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 101]\\n\",\n      \"✗ [0, 101, 102, 103]\\n\",\n      \"✗ [0, 101, 102, 103, 104, 105, 106, 107]\\n\",\n      \"✗ [101, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 101, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 101, 102, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 101, 102, 103, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 101, 102, 103, 104, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 101, 102, 103, 104, 105, 107, 108, 109]\\n\",\n      \"✗ [0, 101, 102, 103, 104, 105, 106, 108, 109]\\n\",\n      \"✗ [0, 101, 102, 103, 104, 105, 106, 107, 109]\\n\",\n      \"✗ [0, 101, 102, 103, 104, 105, 106, 107, 108]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 101, 101, 101, 101, 101, 101, 101, 101, 101]\\n\",\n      \"✗ [0, 101, 102, 102, 102, 102, 102, 102, 102, 102]\\n\",\n      \"✗ [0, 101, 102, 103, 103, 103, 103, 103, 103, 103]\\n\",\n      \"✗ [0, 101, 102, 103, 104, 104, 104, 104, 104, 104]\\n\",\n      \"✗ [0, 101, 102, 103, 104, 105, 105, 105, 105, 105]\\n\",\n      \"✗ [0, 101, 102, 103, 104, 105, 106, 106, 106, 106]\\n\",\n      \"✗ [0, 101, 102, 103, 104, 105, 106, 107, 107, 107]\\n\",\n      \"✗ [0, 101, 102, 103, 104, 105, 106, 107, 108, 108]\\n\",\n      \"✗ [0, 0, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 102, 103]\\n\",\n      \"✗ [0, 1, 102, 103, 104, 105, 106, 107]\\n\",\n      \"✗ [1, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 102, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 102, 103, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 102, 103, 104, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 102, 103, 104, 105, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 102, 103, 104, 105, 106, 108, 109]\\n\",\n      \"✗ [0, 1, 102, 103, 104, 105, 106, 107, 109]\\n\",\n      \"✗ [0, 1, 102, 103, 104, 105, 106, 107, 108]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 102, 102, 102, 102, 102, 102, 102, 102]\\n\",\n      \"✗ [0, 1, 102, 103, 103, 103, 103, 103, 103, 103]\\n\",\n      \"✗ [0, 1, 102, 103, 104, 104, 104, 104, 104, 104]\\n\",\n      \"✗ [0, 1, 102, 103, 104, 105, 105, 105, 105, 105]\\n\",\n      \"✗ [0, 1, 102, 103, 104, 105, 106, 106, 106, 106]\\n\",\n      \"✗ [0, 1, 102, 103, 104, 105, 106, 107, 107, 107]\\n\",\n      \"✗ [0, 1, 102, 103, 104, 105, 106, 107, 108, 108]\\n\",\n      \"✗ [0, 0, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 3, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 3, 103]\\n\",\n      \"✗ [0, 1, 3, 103, 104, 105, 106, 107]\\n\",\n      \"✗ [1, 3, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 3, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 103, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 103, 104, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 103, 104, 105, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 103, 104, 105, 106, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 103, 104, 105, 106, 107, 109]\\n\",\n      \"✗ [0, 1, 3, 103, 104, 105, 106, 107, 108]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 3, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 3, 103, 103, 103, 103, 103, 103, 103]\\n\",\n      \"✗ [0, 1, 3, 103, 104, 104, 104, 104, 104, 104]\\n\",\n      \"✗ [0, 1, 3, 103, 104, 105, 105, 105, 105, 105]\\n\",\n      \"✗ [0, 1, 3, 103, 104, 105, 106, 106, 106, 106]\\n\",\n      \"✗ [0, 1, 3, 103, 104, 105, 106, 107, 107, 107]\\n\",\n      \"✗ [0, 1, 3, 103, 104, 105, 106, 107, 108, 108]\\n\",\n      \"✗ [0, 0, 3, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 103]\\n\",\n      \"✗ [0, 1, 2, 103, 104, 105, 106, 107]\\n\",\n      \"✗ [1, 2, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 2, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 103, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 103, 104, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 103, 104, 105, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 103, 104, 105, 106, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 103, 104, 105, 106, 107, 109]\\n\",\n      \"✗ [0, 1, 2, 103, 104, 105, 106, 107, 108]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 103, 103, 103, 103, 103, 103, 103]\\n\",\n      \"✗ [0, 1, 2, 103, 104, 104, 104, 104, 104, 104]\\n\",\n      \"✗ [0, 1, 2, 103, 104, 105, 105, 105, 105, 105]\\n\",\n      \"✗ [0, 1, 2, 103, 104, 105, 106, 106, 106, 106]\\n\",\n      \"✗ [0, 1, 2, 103, 104, 105, 106, 107, 107, 107]\\n\",\n      \"✗ [0, 1, 2, 103, 104, 105, 106, 107, 108, 108]\\n\",\n      \"✗ [0, 0, 2, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 104, 105, 106, 107]\\n\",\n      \"✗ [1, 2, 3, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 2, 3, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 104, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 104, 105, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 104, 105, 106, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 104, 105, 106, 107, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 104, 105, 106, 107, 108]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 104, 104, 104, 104, 104, 104]\\n\",\n      \"✗ [0, 1, 2, 3, 104, 105, 105, 105, 105, 105]\\n\",\n      \"✗ [0, 1, 2, 3, 104, 105, 106, 106, 106, 106]\\n\",\n      \"✗ [0, 1, 2, 3, 104, 105, 106, 107, 107, 107]\\n\",\n      \"✗ [0, 1, 2, 3, 104, 105, 106, 107, 108, 108]\\n\",\n      \"✗ [0, 0, 2, 3, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 7, 105, 106, 107]\\n\",\n      \"✗ [1, 2, 3, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 2, 3, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 7, 105, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 7, 105, 106, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 7, 105, 106, 107, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 7, 105, 106, 107, 108]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 7, 7, 7, 7, 7, 7]\\n\",\n      \"✗ [0, 1, 2, 3, 7, 105, 105, 105, 105, 105]\\n\",\n      \"✗ [0, 1, 2, 3, 7, 105, 106, 106, 106, 106]\\n\",\n      \"✗ [0, 1, 2, 3, 7, 105, 106, 107, 107, 107]\\n\",\n      \"✗ [0, 1, 2, 3, 7, 105, 106, 107, 108, 108]\\n\",\n      \"✗ [0, 0, 2, 3, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 105, 106, 107]\\n\",\n      \"✗ [1, 2, 3, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 2, 3, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 105, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 105, 106, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 105, 106, 107, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 105, 106, 107, 108]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 105, 105, 105, 105, 105]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 105, 106, 106, 106, 106]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 105, 106, 107, 107, 107]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 105, 106, 107, 108, 108]\\n\",\n      \"✗ [0, 0, 2, 3, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 105, 106, 107]\\n\",\n      \"✗ [1, 2, 3, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 2, 3, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 105, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 105, 106, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 105, 106, 107, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 105, 106, 107, 108]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 105, 105, 105, 105, 105]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 105, 106, 106, 106, 106]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 105, 106, 107, 107, 107]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 105, 106, 107, 108, 108]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 7, 106, 107]\\n\",\n      \"✗ [1, 2, 3, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 2, 3, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 7, 106, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 7, 106, 107, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 7, 106, 107, 108]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 7, 7, 7, 7, 7]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 7, 106, 106, 106, 106]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 7, 106, 107, 107, 107]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 7, 106, 107, 108, 108]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 106, 107]\\n\",\n      \"✗ [1, 2, 3, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 2, 3, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 106, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 106, 107, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 106, 107, 108]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 106, 106, 106, 106]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 106, 107, 107, 107]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 106, 107, 108, 108]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 107]\\n\",\n      \"✗ [1, 2, 3, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 2, 3, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 107, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 107, 108]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 7, 7, 7]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 107, 107, 107]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 107, 108, 108]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 107]\\n\",\n      \"✗ [1, 2, 3, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 2, 3, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 107, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 107, 108]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 6, 6]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 107, 107, 107]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 107, 108, 108]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7]\\n\",\n      \"✗ [1, 2, 3, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 2, 3, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 3, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 108]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 6, 6]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 7]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 108, 108]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 0, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 1, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 3, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7]\\n\",\n      \"✗ [1, 2, 3, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 2, 3, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 3, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 15]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 6, 6]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 7]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 15, 15]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 0, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 1, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 3, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7]\\n\",\n      \"✗ [1, 2, 3, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 2, 3, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 3, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 11]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 6, 6]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 7]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 11, 11]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 0, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 1, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 3, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7]\\n\",\n      \"✗ [1, 2, 3, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 2, 3, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 3, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 9]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 6, 6]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 7]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 9, 9]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 0, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 1, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 3, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7]\\n\",\n      \"✗ [1, 2, 3, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 2, 3, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 3, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 6, 6]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 7]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 8]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 0, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 1, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 3, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 6, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 0]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 1]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 7]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7]\\n\",\n      \"✗ [1, 2, 3, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 2, 3, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 3, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 6, 6]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 7]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 8]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 0, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 1, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 3, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 6, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 0]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 1]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 7]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7]\\n\",\n      \"✗ [1, 2, 3, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 2, 3, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 3, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 6, 6]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 7]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 8]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 0, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 1, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 3, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 6, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 0]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 1]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 7]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 1]\\n\",\n      \"✗ [0, 1, 2, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7]\\n\",\n      \"✗ [1, 2, 3, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 2, 3, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 3, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8]\\n\",\n      \"✗ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"✗ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\\n\",\n      \"✗ [0, 1, 2, 2, 2, 2, 2, 2, 2, 2]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 3, 3, 3, 3, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 4, 4, 4, 4]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 6, 6]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 7]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 8]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 0, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 1, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 3, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 6, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 0]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 1]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 7]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 8]\\n\",\n      \"\\n\",\n      \"20 shrinks with 848 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace(\\n\",\n    \"    [100 + i for i in range(10)],\\n\",\n    \"    lambda x: len(set(x)) >= 10,\\n\",\n    \"    partial(greedy_shrink, shrink=shrink6),\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"This does not do very well at all.\\n\",\n    \"\\n\",\n    \"The reason it doesn't is that we keep trying useless shrinks. e.g. none of the shrinks done by shrink\\\\_to\\\\_prefix, replace\\\\_with\\\\_simpler or shrink\\\\_shared will ever do anything useful here.\\n\",\n    \"\\n\",\n    \"So let's switch to an approach where we try shrink types until they stop working and then we move on to the next type:\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 29,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"def multicourse_shrink1(ls, constraint):\\n\",\n    \"    seen = set()\\n\",\n    \"    for shrink in [\\n\",\n    \"        shrink_to_prefix,\\n\",\n    \"        replace_with_simpler,\\n\",\n    \"        shrink_shared,\\n\",\n    \"        shrink_individual_elements,\\n\",\n    \"    ]:\\n\",\n    \"        while True:\\n\",\n    \"            for s in shrink(ls):\\n\",\n    \"                key = tuple(s)\\n\",\n    \"                if key in seen:\\n\",\n    \"                    continue\\n\",\n    \"                seen.add(key)\\n\",\n    \"                if constraint(s):\\n\",\n    \"                    ls = s\\n\",\n    \"                    break\\n\",\n    \"            else:\\n\",\n    \"                break\\n\",\n    \"    return ls\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 30,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [100, 101, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [100]\\n\",\n      \"✗ [100, 101]\\n\",\n      \"✗ [100, 101, 102, 103]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 107]\\n\",\n      \"✗ [100, 100, 100, 100, 100, 100, 100, 100, 100, 100]\\n\",\n      \"✗ [100, 101, 101, 101, 101, 101, 101, 101, 101, 101]\\n\",\n      \"✗ [100, 101, 102, 102, 102, 102, 102, 102, 102, 102]\\n\",\n      \"✗ [100, 101, 102, 103, 103, 103, 103, 103, 103, 103]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 104, 104, 104, 104, 104]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 105, 105, 105, 105]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 106, 106, 106]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 107, 107, 107]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 107, 108, 108]\\n\",\n      \"✓ [0, 101, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 0, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 3, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 0, 3, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 0, 2, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 0, 2, 3, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 0, 2, 3, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 0, 2, 3, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 7, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 7, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 0, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 1, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 3, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 15, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 15, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 11, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 11, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 9, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 9, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 6, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 0]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 1]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 7]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 8, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 0, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 1, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 3, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 6, 15]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 15]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 8, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 0, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 1, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 3, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 6, 11]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 11]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 0, 2, 3, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 0, 3, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 1, 3, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 0, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 1, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 2, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 0, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 1, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 3, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 6, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 8]\\n\",\n      \"\\n\",\n      \"20 shrinks with 318 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace(\\n\",\n    \"    [100 + i for i in range(10)], lambda x: len(set(x)) >= 10, multicourse_shrink1\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 31,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"conditions[\\\"10 distinct elements\\\"] = lambda xs: len(set(xs)) >= 10\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 32,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/html\": [\n       \"<table>\\n\",\n       \"<thead>\\n\",\n       \"<tr>\\n\",\n       \"<th>Condition</th>\\n\",\n       \"<th>Single pass</th>\\n\",\n       \"<th>Multi pass</th>\\n\",\n       \"</tr>\\n\",\n       \"</thead>\\n\",\n       \"<tbody>\\n\",\n       \"<tr>  \\n\",\n       \"<td>length &gt;= 2</td> <td>6</td> <td>4</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>sum &gt;= 500</td> <td>35</td> <td>34</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>sum &gt;= 3</td> <td>6</td> <td>5</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>At least 10 by 5</td> <td>107</td> <td>58</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>10 distinct elements</td> <td>623</td> <td>320</td>\\n\",\n       \"</tr>\\n\",\n       \"</tbody>\\n\",\n       \"</table>\"\n      ],\n      \"text/plain\": [\n       \"<IPython.core.display.HTML object>\"\n      ]\n     },\n     \"execution_count\": 32,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"compare_simplifiers(\\n\",\n    \"    [\\n\",\n    \"        (\\\"Single pass\\\", partial(greedy_shrink_with_dedupe, shrink=shrink6)),\\n\",\n    \"        (\\\"Multi pass\\\", multicourse_shrink1),\\n\",\n    \"    ]\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"So that helped, but not as much as we'd have liked. It's saved us about half the calls, when really we wanted to save 90% of the calls.\\n\",\n    \"\\n\",\n    \"We're on the right track though. The problem is not that our solution isn't good, it's that it didn't go far enough: We're *still* making an awful lot of useless calls. The problem is that each time we shrink the element at index i we try shrinking the elements at indexes 0 through i - 1, and this will never work. So what we want to do is to break shrinking elements into a separate shrinker for each index:\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 33,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"def simplify_index(i):\\n\",\n    \"    def accept(ls):\\n\",\n    \"        if i >= len(ls):\\n\",\n    \"            return\\n\",\n    \"        for v in shrink_integer(ls[i]):\\n\",\n    \"            s = list(ls)\\n\",\n    \"            s[i] = v\\n\",\n    \"            yield s\\n\",\n    \"\\n\",\n    \"    return accept\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"def shrinkers_for(ls):\\n\",\n    \"    yield shrink_to_prefix\\n\",\n    \"    yield delete_individual_elements\\n\",\n    \"    yield replace_with_simpler\\n\",\n    \"    yield shrink_shared\\n\",\n    \"    for i in range(len(ls)):\\n\",\n    \"        yield simplify_index(i)\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"def multicourse_shrink2(ls, constraint):\\n\",\n    \"    seen = set()\\n\",\n    \"    for shrink in shrinkers_for(ls):\\n\",\n    \"        while True:\\n\",\n    \"            for s in shrink(ls):\\n\",\n    \"                key = tuple(s)\\n\",\n    \"                if key in seen:\\n\",\n    \"                    continue\\n\",\n    \"                seen.add(key)\\n\",\n    \"                if constraint(s):\\n\",\n    \"                    ls = s\\n\",\n    \"                    break\\n\",\n    \"            else:\\n\",\n    \"                break\\n\",\n    \"    return ls\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 34,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [100, 101, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [100]\\n\",\n      \"✗ [100, 101]\\n\",\n      \"✗ [100, 101, 102, 103]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 107]\\n\",\n      \"✗ [101, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [100, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [100, 101, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [100, 101, 102, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [100, 101, 102, 103, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 106, 107, 108, 109]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 107, 108, 109]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 108, 109]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 107, 109]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 107, 108]\\n\",\n      \"✗ [100, 100, 100, 100, 100, 100, 100, 100, 100, 100]\\n\",\n      \"✗ [100, 101, 101, 101, 101, 101, 101, 101, 101, 101]\\n\",\n      \"✗ [100, 101, 102, 102, 102, 102, 102, 102, 102, 102]\\n\",\n      \"✗ [100, 101, 102, 103, 103, 103, 103, 103, 103, 103]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 104, 104, 104, 104, 104]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 105, 105, 105, 105]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 106, 106, 106]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 107, 107, 107]\\n\",\n      \"✗ [100, 101, 102, 103, 104, 105, 106, 107, 108, 108]\\n\",\n      \"✓ [0, 101, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 0, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 102, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 0, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 1, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 3, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 103, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 0, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 1, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 2, 104, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 0, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 1, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 3, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 7, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 5, 105, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 105, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 0, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 1, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 3, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 7, 106, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 4, 106, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 0, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 1, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 3, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 7, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 5, 107, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 107, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 0, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 1, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 3, 108, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 5, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 6, 108, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 0, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 1, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 3, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 7, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 15, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 11, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 9, 109]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 8, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 6, 109]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 0]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 1]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 3]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 7]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 8, 15]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 8, 11]\\n\",\n      \"✓ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\\n\",\n      \"✗ [0, 1, 2, 3, 4, 5, 6, 7, 8, 8]\\n\",\n      \"\\n\",\n      \"20 shrinks with 75 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace(\\n\",\n    \"    [100 + i for i in range(10)], lambda x: len(set(x)) >= 10, multicourse_shrink2\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"This worked great! It saved us a huge number of function calls.\\n\",\n    \"\\n\",\n    \"Unfortunately it's wrong. Actually the previous one was wrong too, but this one is more obviously wrong. The problem is that shrinking later elements can unlock more shrinks for earlier elements and we'll never be able to benefit from that here:\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 35,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [101, 100]\\n\",\n      \"✗ [101]\\n\",\n      \"✗ [100]\\n\",\n      \"✗ [100, 100]\\n\",\n      \"✗ [0, 100]\\n\",\n      \"✗ [1, 100]\\n\",\n      \"✗ [3, 100]\\n\",\n      \"✗ [7, 100]\\n\",\n      \"✗ [15, 100]\\n\",\n      \"✗ [31, 100]\\n\",\n      \"✗ [63, 100]\\n\",\n      \"✗ [82, 100]\\n\",\n      \"✗ [91, 100]\\n\",\n      \"✗ [96, 100]\\n\",\n      \"✗ [98, 100]\\n\",\n      \"✗ [99, 100]\\n\",\n      \"✓ [101, 0]\\n\",\n      \"\\n\",\n      \"1 shrinks with 16 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace([101, 100], lambda x: len(x) >= 2 and x[0] > x[1], multicourse_shrink2)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"Armed with this example we can also show an example where the previous one is wrong because a later simplification unlocks an earlier one because shrinking values allows us to delete more elements:\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 36,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [5, 5, 5, 5, 5, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✓ [5, 5, 5, 5, 5, 5, 5, 5]\\n\",\n      \"✓ [0, 0, 0, 0, 0, 0, 0, 0]\\n\",\n      \"\\n\",\n      \"2 shrinks with 5 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace([5] * 10, lambda x: x and len(x) > max(x), multicourse_shrink1)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 37,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"conditions[\\\"First > Second\\\"] = lambda xs: len(xs) >= 2 and xs[0] > xs[1]\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 38,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"# Note: We modify this to mask off the high bits because otherwise the probability of\\n\",\n    \"# hitting the condition at random is too low.\\n\",\n    \"conditions[\\\"Size > max & 63\\\"] = lambda xs: xs and len(xs) > (max(xs) & 63)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"So what we'll try doing is iterating this to a fixed point and see what happens:\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 39,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"def multicourse_shrink3(ls, constraint):\\n\",\n    \"    seen = set()\\n\",\n    \"    while True:\\n\",\n    \"        old_ls = ls\\n\",\n    \"        for shrink in shrinkers_for(ls):\\n\",\n    \"            while True:\\n\",\n    \"                for s in shrink(ls):\\n\",\n    \"                    key = tuple(s)\\n\",\n    \"                    if key in seen:\\n\",\n    \"                        continue\\n\",\n    \"                    seen.add(key)\\n\",\n    \"                    if constraint(s):\\n\",\n    \"                        ls = s\\n\",\n    \"                        break\\n\",\n    \"                else:\\n\",\n    \"                    break\\n\",\n    \"        if ls == old_ls:\\n\",\n    \"            return ls\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 40,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [101, 100]\\n\",\n      \"✗ [101]\\n\",\n      \"✗ [100]\\n\",\n      \"✗ [100, 100]\\n\",\n      \"✗ [0, 100]\\n\",\n      \"✗ [1, 100]\\n\",\n      \"✗ [3, 100]\\n\",\n      \"✗ [7, 100]\\n\",\n      \"✗ [15, 100]\\n\",\n      \"✗ [31, 100]\\n\",\n      \"✗ [63, 100]\\n\",\n      \"✗ [82, 100]\\n\",\n      \"✗ [91, 100]\\n\",\n      \"✗ [96, 100]\\n\",\n      \"✗ [98, 100]\\n\",\n      \"✗ [99, 100]\\n\",\n      \"✓ [101, 0]\\n\",\n      \"✗ [0]\\n\",\n      \"✗ [0, 0]\\n\",\n      \"✓ [1, 0]\\n\",\n      \"✗ [1]\\n\",\n      \"\\n\",\n      \"2 shrinks with 20 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace([101, 100], lambda xs: len(xs) >= 2 and xs[0] > xs[1], multicourse_shrink3)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 41,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [5, 5, 5, 5, 5, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✓ [5, 5, 5, 5, 5, 5, 5, 5]\\n\",\n      \"✓ [5, 5, 5, 5, 5, 5, 5]\\n\",\n      \"✓ [5, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5, 5]\\n\",\n      \"✓ [0, 0, 0, 0, 0, 0]\\n\",\n      \"✓ [0]\\n\",\n      \"✗ []\\n\",\n      \"\\n\",\n      \"5 shrinks with 10 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace([5] * 10, lambda x: x and len(x) > max(x), multicourse_shrink3)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"So that worked. Yay!\\n\",\n    \"\\n\",\n    \"Lets compare how this does to our single pass implementation.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 42,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/html\": [\n       \"<table>\\n\",\n       \"<thead>\\n\",\n       \"<tr>\\n\",\n       \"<th>Condition</th>\\n\",\n       \"<th>Single pass</th>\\n\",\n       \"<th>Multi pass</th>\\n\",\n       \"</tr>\\n\",\n       \"</thead>\\n\",\n       \"<tbody>\\n\",\n       \"<tr>  \\n\",\n       \"<td>length &gt;= 2</td> <td>6</td> <td>6</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>sum &gt;= 500</td> <td>35</td> <td>35</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>sum &gt;= 3</td> <td>6</td> <td>6</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>At least 10 by 5</td> <td>107</td> <td>73</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>10 distinct elements</td> <td>623</td> <td>131</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>First &gt; Second</td> <td>1481</td> <td>1445</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>Size &gt; max & 63</td> <td>600</td> <td> &gt; 5000</td>\\n\",\n       \"</tr>\\n\",\n       \"</tbody>\\n\",\n       \"</table>\"\n      ],\n      \"text/plain\": [\n       \"<IPython.core.display.HTML object>\"\n      ]\n     },\n     \"execution_count\": 42,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"compare_simplifiers(\\n\",\n    \"    [\\n\",\n    \"        (\\\"Single pass\\\", partial(greedy_shrink_with_dedupe, shrink=shrink6)),\\n\",\n    \"        (\\\"Multi pass\\\", multicourse_shrink3),\\n\",\n    \"    ]\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"So the answer is generally favourably but *ouch* that last one.\\n\",\n    \"\\n\",\n    \"What's happening there is that because later shrinks are opening up potentially very large improvements accessible to the lower shrinks, the original greedy algorithm can exploit that much better, while the multi pass algorithm spends a lot of time in the later stages with their incremental shrinks.\\n\",\n    \"\\n\",\n    \"Lets see another similar example before we try to fix this:\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 43,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"import hashlib\\n\",\n    \"\\n\",\n    \"conditions[\\\"Messy\\\"] = (\\n\",\n    \"    lambda xs: hashlib.md5(repr(xs).encode(\\\"utf-8\\\")).hexdigest()[0] == \\\"0\\\"\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 44,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/html\": [\n       \"<table>\\n\",\n       \"<thead>\\n\",\n       \"<tr>\\n\",\n       \"<th>Condition</th>\\n\",\n       \"<th>Single pass</th>\\n\",\n       \"<th>Multi pass</th>\\n\",\n       \"</tr>\\n\",\n       \"</thead>\\n\",\n       \"<tbody>\\n\",\n       \"<tr>  \\n\",\n       \"<td>length &gt;= 2</td> <td>6</td> <td>6</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>sum &gt;= 500</td> <td>35</td> <td>35</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>sum &gt;= 3</td> <td>6</td> <td>6</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>At least 10 by 5</td> <td>107</td> <td>73</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>10 distinct elements</td> <td>623</td> <td>131</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>First &gt; Second</td> <td>1481</td> <td>1445</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>Size &gt; max & 63</td> <td>600</td> <td> &gt; 5000</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>Messy</td> <td>1032</td> <td> &gt; 5000</td>\\n\",\n       \"</tr>\\n\",\n       \"</tbody>\\n\",\n       \"</table>\"\n      ],\n      \"text/plain\": [\n       \"<IPython.core.display.HTML object>\"\n      ]\n     },\n     \"execution_count\": 44,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"compare_simplifiers(\\n\",\n    \"    [\\n\",\n    \"        (\\\"Single pass\\\", partial(greedy_shrink_with_dedupe, shrink=shrink6)),\\n\",\n    \"        (\\\"Multi pass\\\", multicourse_shrink3),\\n\",\n    \"    ]\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"This one is a bit different in that the problem is not that the structure is one we're ill suited to exploiting, it's that there is no structure at all so we have no hope of exploiting it. Literally any change at all will unlock earlier shrinks we could have done.\\n\",\n    \"\\n\",\n    \"What we're going to try to do is hybridize the two approaches. If we notice we're performing an awful lot of shrinks we can take that as a hint that we should be trying again from earlier stages.\\n\",\n    \"\\n\",\n    \"Here is our first approach. We simply restart the whole process every five shrinks:\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 45,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"MAX_SHRINKS_PER_RUN = 2\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"def multicourse_shrink4(ls, constraint):\\n\",\n    \"    seen = set()\\n\",\n    \"    while True:\\n\",\n    \"        old_ls = ls\\n\",\n    \"        shrinks_this_run = 0\\n\",\n    \"        for shrink in shrinkers_for(ls):\\n\",\n    \"            while shrinks_this_run < MAX_SHRINKS_PER_RUN:\\n\",\n    \"                for s in shrink(ls):\\n\",\n    \"                    key = tuple(s)\\n\",\n    \"                    if key in seen:\\n\",\n    \"                        continue\\n\",\n    \"                    seen.add(key)\\n\",\n    \"                    if constraint(s):\\n\",\n    \"                        shrinks_this_run += 1\\n\",\n    \"                        ls = s\\n\",\n    \"                        break\\n\",\n    \"                else:\\n\",\n    \"                    break\\n\",\n    \"        if ls == old_ls:\\n\",\n    \"            return ls\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 46,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/html\": [\n       \"<table>\\n\",\n       \"<thead>\\n\",\n       \"<tr>\\n\",\n       \"<th>Condition</th>\\n\",\n       \"<th>Single pass</th>\\n\",\n       \"<th>Multi pass</th>\\n\",\n       \"<th>Multi pass with restart</th>\\n\",\n       \"</tr>\\n\",\n       \"</thead>\\n\",\n       \"<tbody>\\n\",\n       \"<tr>  \\n\",\n       \"<td>length &gt;= 2</td> <td>6</td> <td>6</td> <td>6</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>sum &gt;= 500</td> <td>35</td> <td>35</td> <td>35</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>sum &gt;= 3</td> <td>6</td> <td>6</td> <td>6</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>At least 10 by 5</td> <td>107</td> <td>73</td> <td>90</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>10 distinct elements</td> <td>623</td> <td>131</td> <td>396</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>First &gt; Second</td> <td>1481</td> <td>1445</td> <td>1463</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>Size &gt; max & 63</td> <td>600</td> <td> &gt; 5000</td> <td> &gt; 5000</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>Messy</td> <td>1032</td> <td> &gt; 5000</td> <td>1423</td>\\n\",\n       \"</tr>\\n\",\n       \"</tbody>\\n\",\n       \"</table>\"\n      ],\n      \"text/plain\": [\n       \"<IPython.core.display.HTML object>\"\n      ]\n     },\n     \"execution_count\": 46,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"compare_simplifiers(\\n\",\n    \"    [\\n\",\n    \"        (\\\"Single pass\\\", partial(greedy_shrink_with_dedupe, shrink=shrink6)),\\n\",\n    \"        (\\\"Multi pass\\\", multicourse_shrink3),\\n\",\n    \"        (\\\"Multi pass with restart\\\", multicourse_shrink4),\\n\",\n    \"    ]\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"That works OK, but it's pretty unsatisfying as it loses us most of the benefits of the multi pass shrinking - we're now at most twice as good as the greedy one.\\n\",\n    \"\\n\",\n    \"So what we're going to do is bet on the multi pass working and then gradually degrade to the greedy algorithm as it fails to work.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 47,\n   \"metadata\": {\n    \"collapsed\": true\n   },\n   \"outputs\": [],\n   \"source\": [\n    \"def multicourse_shrink5(ls, constraint):\\n\",\n    \"    seen = set()\\n\",\n    \"    max_shrinks_per_run = 10\\n\",\n    \"    while True:\\n\",\n    \"        shrinks_this_run = 0\\n\",\n    \"        for shrink in shrinkers_for(ls):\\n\",\n    \"            while shrinks_this_run < max_shrinks_per_run:\\n\",\n    \"                for s in shrink(ls):\\n\",\n    \"                    key = tuple(s)\\n\",\n    \"                    if key in seen:\\n\",\n    \"                        continue\\n\",\n    \"                    seen.add(key)\\n\",\n    \"                    if constraint(s):\\n\",\n    \"                        shrinks_this_run += 1\\n\",\n    \"                        ls = s\\n\",\n    \"                        break\\n\",\n    \"                else:\\n\",\n    \"                    break\\n\",\n    \"        if max_shrinks_per_run > 1:\\n\",\n    \"            max_shrinks_per_run -= 2\\n\",\n    \"        if not shrinks_this_run:\\n\",\n    \"            return ls\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 48,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"✓ [5, 5, 5, 5, 5, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [5]\\n\",\n      \"✗ [5, 5]\\n\",\n      \"✗ [5, 5, 5, 5]\\n\",\n      \"✓ [5, 5, 5, 5, 5, 5, 5, 5]\\n\",\n      \"✓ [5, 5, 5, 5, 5, 5, 5]\\n\",\n      \"✓ [5, 5, 5, 5, 5, 5]\\n\",\n      \"✗ [5, 5, 5, 5, 5]\\n\",\n      \"✓ [0, 0, 0, 0, 0, 0]\\n\",\n      \"✓ [0]\\n\",\n      \"✗ []\\n\",\n      \"\\n\",\n      \"5 shrinks with 10 function calls\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"show_trace([5] * 10, lambda x: x and len(x) > max(x), multicourse_shrink5)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 49,\n   \"metadata\": {\n    \"collapsed\": false\n   },\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/html\": [\n       \"<table>\\n\",\n       \"<thead>\\n\",\n       \"<tr>\\n\",\n       \"<th>Condition</th>\\n\",\n       \"<th>Single pass</th>\\n\",\n       \"<th>Multi pass</th>\\n\",\n       \"<th>Multi pass with restart</th>\\n\",\n       \"<th>Multi pass with variable restart</th>\\n\",\n       \"</tr>\\n\",\n       \"</thead>\\n\",\n       \"<tbody>\\n\",\n       \"<tr>  \\n\",\n       \"<td>length &gt;= 2</td> <td>6</td> <td>6</td> <td>6</td> <td>6</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>sum &gt;= 500</td> <td>35</td> <td>35</td> <td>35</td> <td>35</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>sum &gt;= 3</td> <td>6</td> <td>6</td> <td>6</td> <td>6</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>At least 10 by 5</td> <td>107</td> <td>73</td> <td>90</td> <td>73</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>10 distinct elements</td> <td>623</td> <td>131</td> <td>396</td> <td>212</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>First &gt; Second</td> <td>1481</td> <td>1445</td> <td>1463</td> <td>1168</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>Size &gt; max & 63</td> <td>600</td> <td> &gt; 5000</td> <td> &gt; 5000</td> <td>1002</td>\\n\",\n       \"</tr>\\n\",\n       \"<tr>  \\n\",\n       \"<td>Messy</td> <td>1032</td> <td> &gt; 5000</td> <td>1423</td> <td>824</td>\\n\",\n       \"</tr>\\n\",\n       \"</tbody>\\n\",\n       \"</table>\"\n      ],\n      \"text/plain\": [\n       \"<IPython.core.display.HTML object>\"\n      ]\n     },\n     \"execution_count\": 49,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"compare_simplifiers(\\n\",\n    \"    [\\n\",\n    \"        (\\\"Single pass\\\", partial(greedy_shrink_with_dedupe, shrink=shrink6)),\\n\",\n    \"        (\\\"Multi pass\\\", multicourse_shrink3),\\n\",\n    \"        (\\\"Multi pass with restart\\\", multicourse_shrink4),\\n\",\n    \"        (\\\"Multi pass with variable restart\\\", multicourse_shrink5),\\n\",\n    \"    ]\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"This is now more or less the current state of the art (it's actually a bit different from the Hypothesis state of the art at the time of this writing. I'm planning to merge some of the things I figured out in the course of writing this back in). We've got something that is able to adaptively take advantage of structure where it is present, but degrades reasonably gracefully back to the more aggressive version that works better in unstructured examples.\\n\",\n    \"\\n\",\n    \"Surprisingly, on some examples it seems to even be best of all of them. I think that's more coincidence than truth though.\"\n   ]\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"Python 3\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.4.3\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 0\n}\n"
  },
  {
    "path": "paper.bib",
    "content": "@inproceedings{DBLP:conf/icfp/ClaessenH00,\n  author    = {Koen Claessen and\n               John Hughes},\n  title     = {QuickCheck: a lightweight tool for random testing of {H}askell programs},\n  booktitle = {{Proceedings of the Fifth ACM SIGPLAN International Conference\n               on Functional Programming (ICFP '00)}},\n  pages     = {268--279},\n  year      = {2000},\n  crossref  = {DBLP:conf/icfp/2000},\n  url       = {https://doi.org/10.1145/351240.351266},\n  doi       = {10.1145/351240.351266},\n  timestamp = {Tue, 06 Nov 2018 16:59:25 +0100},\n  biburl    = {https://dblp.org/rec/bib/conf/icfp/ClaessenH00},\n  bibsource = {dblp computer science bibliography, https://dblp.org}\n}\n\n@proceedings{DBLP:conf/icfp/2000,\n  editor    = {Martin Odersky and\n               Philip Wadler},\n  title     = {{Proceedings of the Fifth ACM SIGPLAN International Conference\n               on Functional Programming (ICFP '00)}},\n  publisher = {{ACM}},\n  year      = {2000},\n  isbn      = {1-58113-202-6},\n  timestamp = {Tue, 11 Jun 2013 13:51:25 +0200},\n  biburl    = {https://dblp.org/rec/bib/conf/icfp/2000},\n  bibsource = {dblp computer science bibliography, https://dblp.org}\n}\n\n@inproceedings{DBLP:conf/erlang/ArtsHJW06,\n  author    = {Thomas Arts and\n               John Hughes and\n               Joakim Johansson and\n               Ulf T. Wiger},\n  title     = {Testing telecoms software with quviq {QuickCheck}},\n  booktitle = {{Proceedings of the 2006 ACM SIGPLAN Workshop on Erlang}},\n  pages     = {2--10},\n  year      = {2006},\n  crossref  = {DBLP:conf/erlang/2006},\n  url       = {https://doi.org/10.1145/1159789.1159792},\n  doi       = {10.1145/1159789.1159792},\n  timestamp = {Tue, 06 Nov 2018 16:59:37 +0100},\n  biburl    = {https://dblp.org/rec/bib/conf/erlang/ArtsHJW06},\n  bibsource = {dblp computer science bibliography, https://dblp.org}\n}\n\n@proceedings{DBLP:conf/erlang/2006,\n  editor    = {Marc Feeley and\n               Philip W. Trinder},\n  title     = {{Proceedings of the 2006 ACM SIGPLAN Workshop on Erlang}},\n  publisher = {{ACM}},\n  year      = {2006},\n  isbn      = {1-59593-490-1},\n  timestamp = {Wed, 02 Apr 2008 10:59:25 +0200},\n  biburl    = {https://dblp.org/rec/bib/conf/erlang/2006},\n  bibsource = {dblp computer science bibliography, https://dblp.org}\n}\n\n@misc{PraiseOfPBT,\n  title = {In Praise of Property-Based Testing},\n  howpublished = {\\url{https://increment.com/testing/in-praise-of-property-based-testing/}},\n  year={2019},\n  author={David R. MacIver},\n}\n\n@article{DBLP:journals/tse/ZellerH02,\n  author    = {Andreas Zeller and\n               Ralf Hildebrandt},\n  title     = {Simplifying and Isolating Failure-Inducing Input},\n  journal   = {{IEEE} Trans. Software Eng.},\n  volume    = {28},\n  number    = {2},\n  pages     = {183--200},\n  year      = {2002},\n  url       = {https://doi.org/10.1109/32.988498},\n  doi       = {10.1109/32.988498},\n  timestamp = {Wed, 14 Nov 2018 10:49:20 +0100},\n  biburl    = {https://dblp.org/rec/bib/journals/tse/ZellerH02},\n  bibsource = {dblp computer science bibliography, https://dblp.org}\n}\n\n@inproceedings{DBLP:conf/pldi/RegehrCCEEY12,\n  author    = {John Regehr and\n               Yang Chen and\n               Pascal Cuoq and\n               Eric Eide and\n               Chucky Ellison and\n               Xuejun Yang},\n  title     = {Test-case reduction for {C} compiler bugs},\n  booktitle = {{ACM SIGPLAN Conference on Programming Language Design and Implementation,\n               (PLDI '12)}},\n  pages     = {335--346},\n  year      = {2012},\n  crossref  = {DBLP:conf/pldi/2012},\n  url       = {https://doi.org/10.1145/2254064.2254104},\n  doi       = {10.1145/2254064.2254104},\n  timestamp = {Wed, 14 Nov 2018 10:54:59 +0100},\n  biburl    = {https://dblp.org/rec/bib/conf/pldi/RegehrCCEEY12},\n  bibsource = {dblp computer science bibliography, https://dblp.org}\n}\n\n@proceedings{DBLP:conf/pldi/2012,\n  editor    = {Jan Vitek and\n               Haibo Lin and\n               Frank Tip},\n  title     = {{ACM SIGPLAN Conference on Programming Language Design and Implementation,\n               (PLDI '12)}},\n  publisher = {{ACM}},\n  year      = {2012},\n  url       = {http://dl.acm.org/citation.cfm?id=2254064},\n  isbn      = {978-1-4503-1205-9},\n  timestamp = {Tue, 12 Jun 2012 19:17:55 +0200},\n  biburl    = {https://dblp.org/rec/bib/conf/pldi/2012},\n  bibsource = {dblp computer science bibliography, https://dblp.org}\n}\n\n\n@article{astropy:2013,\nAdsnote = {Provided by the SAO/NASA Astrophysics Data System},\nAdsurl = {http://adsabs.harvard.edu/abs/2013A%26A...558A..33A},\nArchiveprefix = {arXiv},\nAuthor = {{Astropy Collaboration} and {Robitaille}, T.~P. and {Tollerud}, E.~J. and {Greenfield}, P. and {Droettboom}, M. and {Bray}, E. and {Aldcroft}, T. and {Davis}, M. and {Ginsburg}, A. and {Price-Whelan}, A.~M. and {Kerzendorf}, W.~E. and {Conley}, A. and {Crighton}, N. and {Barbary}, K. and {Muna}, D. and {Ferguson}, H. and {Grollier}, F. and {Parikh}, M.~M. and {Nair}, P.~H. and {Unther}, H.~M. and {Deil}, C. and {Woillez}, J. and {Conseil}, S. and {Kramer}, R. and {Turner}, J.~E.~H. and {Singer}, L. and {Fox}, R. and {Weaver}, B.~A. and {Zabalza}, V. and {Edwards}, Z.~I. and {Azalee Bostroem}, K. and {Burke}, D.~J. and {Casey}, A.~R. and {Crawford}, S.~M. and {Dencheva}, N. and {Ely}, J. and {Jenness}, T. and {Labrie}, K. and {Lim}, P.~L. and {Pierfederici}, F. and {Pontzen}, A. and {Ptak}, A. and {Refsdal}, B. and {Servillat}, M. and {Streicher}, O.},\nDoi = {10.1051/0004-6361/201322068},\nEid = {A33},\nEprint = {1307.6212},\nJournal = {\\aap},\nKeywords = {methods: data analysis, methods: miscellaneous, virtual observatory tools},\nMonth = oct,\nPages = {A33},\nPrimaryclass = {astro-ph.IM},\nTitle = {{Astropy: A community Python package for astronomy}},\nVolume = 558,\nYear = 2013,\nBdsk-Url-1 = {https://dx.doi.org/10.1051/0004-6361/201322068}}\n\n@article{astropy:2018,\nAdsnote = {Provided by the SAO/NASA Astrophysics Data System},\nAdsurl = {https://ui.adsabs.harvard.edu/#abs/2018AJ....156..123T},\nAuthor = {{Price-Whelan}, A.~M. and {Sip{\\H{o}}cz}, B.~M. and {G{\\\"u}nther}, H.~M. and {Lim}, P.~L. and {Crawford}, S.~M. and {Conseil}, S. and {Shupe}, D.~L. and {Craig}, M.~W. and {Dencheva}, N. and {Ginsburg}, A. and {VanderPlas}, J.~T. and {Bradley}, L.~D. and {P{\\'e}rez-Su{\\'a}rez}, D. and {de Val-Borro}, M. and {Paper Contributors}, (Primary and {Aldcroft}, T.~L. and {Cruz}, K.~L. and {Robitaille}, T.~P. and {Tollerud}, E.~J. and {Coordination Committee}, (Astropy and {Ardelean}, C. and {Babej}, T. and {Bach}, Y.~P. and {Bachetti}, M. and {Bakanov}, A.~V. and {Bamford}, S.~P. and {Barentsen}, G. and {Barmby}, P. and {Baumbach}, A. and {Berry}, K.~L. and {Biscani}, F. and {Boquien}, M. and {Bostroem}, K.~A. and {Bouma}, L.~G. and {Brammer}, G.~B. and {Bray}, E.~M. and {Breytenbach}, H. and {Buddelmeijer}, H. and {Burke}, D.~J. and {Calderone}, G. and {Cano Rodr{\\'\\i}guez}, J.~L. and {Cara}, M. and {Cardoso}, J.~V.~M. and {Cheedella}, S. and {Copin}, Y. and {Corrales}, L. and {Crichton}, D. and {D{\\textquoteright}Avella}, D. and {Deil}, C. and {Depagne}, {\\'E}. and {Dietrich}, J.~P. and {Donath}, A. and {Droettboom}, M. and {Earl}, N. and {Erben}, T. and {Fabbro}, S. and {Ferreira}, L.~A. and {Finethy}, T. and {Fox}, R.~T. and {Garrison}, L.~H. and {Gibbons}, S.~L.~J. and {Goldstein}, D.~A. and {Gommers}, R. and {Greco}, J.~P. and {Greenfield}, P. and {Groener}, A.~M. and {Grollier}, F. and {Hagen}, A. and {Hirst}, P. and {Homeier}, D. and {Horton}, A.~J. and {Hosseinzadeh}, G. and {Hu}, L. and {Hunkeler}, J.~S. and {Ivezi{\\'c}}, {\\v{Z}}. and {Jain}, A. and {Jenness}, T. and {Kanarek}, G. and {Kendrew}, S. and {Kern}, N.~S. and {Kerzendorf}, W.~E. and {Khvalko}, A. and {King}, J. and {Kirkby}, D. and {Kulkarni}, A.~M. and {Kumar}, A. and {Lee}, A. and {Lenz}, D. and {Littlefair}, S.~P. and {Ma}, Z. and {Macleod}, D.~M. and {Mastropietro}, M. and {McCully}, C. and {Montagnac}, S. and {Morris}, B.~M. and {Mueller}, M. and {Mumford}, S.~J. and {Muna}, D. and {Murphy}, N.~A. and {Nelson}, S. and {Nguyen}, G.~H. and {Ninan}, J.~P. and {N{\\\"o}the}, M. and {Ogaz}, S. and {Oh}, S. and {Parejko}, J.~K. and {Parley}, N. and {Pascual}, S. and {Patil}, R. and {Patil}, A.~A. and {Plunkett}, A.~L. and {Prochaska}, J.~X. and {Rastogi}, T. and {Reddy Janga}, V. and {Sabater}, J. and {Sakurikar}, P. and {Seifert}, M. and {Sherbert}, L.~E. and {Sherwood-Taylor}, H. and {Shih}, A.~Y. and {Sick}, J. and {Silbiger}, M.~T. and {Singanamalla}, S. and {Singer}, L.~P. and {Sladen}, P.~H. and {Sooley}, K.~A. and {Sornarajah}, S. and {Streicher}, O. and {Teuben}, P. and {Thomas}, S.~W. and {Tremblay}, G.~R. and {Turner}, J.~E.~H. and {Terr{\\'o}n}, V. and {van Kerkwijk}, M.~H. and {de la Vega}, A. and {Watkins}, L.~L. and {Weaver}, B.~A. and {Whitmore}, J.~B. and {Woillez}, J. and {Zabalza}, V. and {Contributors}, (Astropy},\nDoi = {10.3847/1538-3881/aabc4f},\nEid = {123},\nJournal = {\\aj},\nKeywords = {methods: data analysis, methods: miscellaneous, methods: statistical, reference systems, Astrophysics - Instrumentation and Methods for Astrophysics},\nMonth = Sep,\nPages = {123},\nPrimaryclass = {astro-ph.IM},\nTitle = {{The Astropy Project: Building an Open-science Project and Status of the v2.0 Core Package}},\nVolume = {156},\nYear = 2018,\nBdsk-Url-1 = {https://doi.org/10.3847/1538-3881/aabc4f}}\n\n@article{DBLP:journals/cse/WaltCV11,\n  author    = {St{\\'{e}}fan van der Walt and\n               S. Chris Colbert and\n               Ga{\\\"{e}}l Varoquaux},\n  title     = {The {NumPy} Array: {A} Structure for Efficient Numerical Computation},\n  journal   = {Computing in Science and Engineering},\n  volume    = {13},\n  number    = {2},\n  pages     = {22--30},\n  year      = {2011},\n  url       = {https://doi.org/10.1109/MCSE.2011.37},\n  doi       = {10.1109/MCSE.2011.37},\n  timestamp = {Wed, 14 Nov 2018 10:48:31 +0100},\n  biburl    = {https://dblp.org/rec/bib/journals/cse/WaltCV11},\n  bibsource = {dblp computer science bibliography, https://dblp.org}\n}\n\n@inproceedings{DBLP:conf/issta/LoscherS17,\n  author    = {Andreas L{\\\"{o}}scher and\n               Konstantinos Sagonas},\n  title     = {Targeted property-based testing},\n  booktitle = {{Proceedings of the 26th ACM SIGSOFT International Symposium on\n               Software Testing and Analysis}},\n  pages     = {46--56},\n  year      = {2017},\n  crossref  = {DBLP:conf/issta/2017},\n  url       = {https://doi.org/10.1145/3092703.3092711},\n  doi       = {10.1145/3092703.3092711},\n  timestamp = {Wed, 25 Sep 2019 18:08:21 +0200},\n  biburl    = {https://dblp.org/rec/bib/conf/issta/LoscherS17},\n  bibsource = {dblp computer science bibliography, https://dblp.org}\n}\n\n@proceedings{DBLP:conf/issta/2017,\n  editor    = {Tevfik Bultan and\n               Koushik Sen},\n  title     = {{Proceedings of the 26th ACM SIGSOFT International Symposium on\n               Software Testing and Analysis}},\n  publisher = {{ACM}},\n  year      = {2017},\n  url       = {https://doi.org/10.1145/3092703},\n  doi       = {10.1145/3092703},\n  isbn      = {978-1-4503-5076-1},\n  timestamp = {Tue, 06 Nov 2018 16:57:30 +0100},\n  biburl    = {https://dblp.org/rec/bib/conf/issta/2017},\n  bibsource = {dblp computer science bibliography, https://dblp.org}\n}\n\n\n"
  },
  {
    "path": "paper.md",
    "content": "---\ntitle: 'Hypothesis: A new approach to property-based testing'\ndate: 1 November 2019\nbibliography: paper.bib\ntags:\n    - Python\n    - testing\n    - test-case reduction\n    - test-case generation\n    - property-based testing\nauthors:\n    - name: David R. MacIver\n      orcid: 0000-0002-8635-3223\n      affiliation: 1\n    - name: Zac Hatfield-Dodds\n      orcid: 0000-0002-8646-8362\n      affiliation: 2\n    - name: many other contributors\n      affiliation: 3\naffiliations:\n    - name: Imperial College London\n      index: 1\n    - name: Australian National University\n      index: 2\n    - name: Various\n      index: 3\n---\n\n# Summary\n\n*Property-based testing* is a style of testing popularised by the QuickCheck family of libraries,\nfirst in Haskell [@DBLP:conf/icfp/ClaessenH00] and later in Erlang [@DBLP:conf/erlang/ArtsHJW06],\nwhich integrates generated test cases into existing software testing workflows:\nInstead of tests that provide examples of a single concrete behaviour,\ntests specify properties that hold for a wide range of inputs,\nwhich the testing library then attempts to generate test cases to refute.\nFor a general introduction to property-based testing, see [@PraiseOfPBT].\n\nHypothesis is a mature and widely used property-based testing library for Python.\nIt has over 100,000 downloads per week^[https://pypistats.org/packages/hypothesis], thousands of open source projects use it^[https://github.com/HypothesisWorks/hypothesis/network/dependents],\nand in 2018 more than 4% of Python users surveyed by the PSF reported using it^[https://www.jetbrains.com/research/python-developers-survey-2018/].\nIt will be of interest both to researchers using Python for developing scientific software,\nand to software testing researchers as a platform for research in its own right.\n\n# Hypothesis for Testing Scientific Software\n\nPython has a rich and thriving ecosystem of scientific software, and Hypothesis is helpful for ensuring its correctness.\nAny researcher who tests their software in Python can benefit from these facilities,\nbut it is particularly useful for improving the correctness foundational libraries on which the scientific software ecosystem is built.\nFor example, it has found bugs in astropy [@astropy:2018]^[e.g. https://github.com/astropy/astropy/pull/9328, https://github.com/astropy/astropy/pull/9532] and numpy [@DBLP:journals/cse/WaltCV11]^[e.g. https://github.com/numpy/numpy/issues/10930, https://github.com/numpy/numpy/issues/13089, https://github.com/numpy/numpy/issues/14239].\n\nAdditionally, Hypothesis is easily extensible, and has a number of third-party extensions for specific research applications.\nFor example, hypothesis-networkx^[https://pypi.org/project/hypothesis-networkx/] generates graph data structures,\nand hypothesis-bio^[https://pypi.org/project/hypothesis-bio/] generates formats suitable for bioinformatics.\nAs it is used by more researchers, the number of research applications will only increase.\n\nBy lowering the barrier to effective testing, Hypothesis makes testing of research software written in Python much more compelling,\nand has the potential to significantly improve the quality of the associated scientific research as a result.\n\n# Hypothesis for Software Testing Research\n\nHypothesis is a powerful platform for software testing research,\nboth because of the wide array of software that can be easily tested with it,\nand because it has a novel implementation that solves a major difficulty faced by prior software testing research.\n\nMuch of software testing research boils down to variants on the following problem:\nGiven some interestingness condition (e.g., that it triggers a bug in some software),\nhow do we generate a \"good\" test case that satisfies that condition?\n\nParticular sub-problems of this are:\n\n1. How do we generate test cases that satisfy difficult interestingness conditions?\n2. How do we ensure we generate only valid test cases? (the *test-case validity problem* - see @DBLP:conf/pldi/RegehrCCEEY12)\n3. How do we generate human readable test cases?\n\nTraditionally property-based testing has adopted random test-case generation to find interesting test cases,\nfollowed by test-case reduction (see @DBLP:conf/pldi/RegehrCCEEY12, @DBLP:journals/tse/ZellerH02) to turn them into more human readable ones,\nrequiring the users to manually specify a *validity oracle* (a predicate that identifies if an arbitrary test case is valid) to avoid invalid test cases.\n\nThe chief limitations of this from a user's point of view are:\n\n* Writing correct validity oracles is difficult and annoying.\n* Random generation, while often much better than hand-written examples, is not especially good at satisfying difficult properties.\n* Writing test-case reducers that work well for your problem domain is a specialised skill that few people have or want to acquire.\n\nThe chief limitation from a researcher's point of view is that trying to improve on random generation's ability to find bugs will typically require modification of existing tests to support new ways of generating data,\nand typically these modifications are significantly more complex than writing the random generator would have been.\nUsers are rarely going to be willing to undertake the work themselves,\nwhich leaves researchers in the unfortunate position of having to put in a significant amount of work per project to understand how to test it.\n\nHypothesis avoids both of these problems by using a single universal representation for test cases.\nEnsuring that test cases produced from this format are valid is relatively easy, no more difficult than ensuring that randomly generated tests cases are valid,\nand improvements to the generation process can operate solely on this universal representation rather than requiring adapting to each test.\n\nCurrently Hypothesis uses this format to support two major use cases:\n\n1. It is the basis of its approach to test-case reduction, allowing it to support more powerful test-case reduction than is found in most property-based testing libraries with no user intervention.\n2. It supports Targeted Property-Based Testing [@DBLP:conf/issta/LoscherS17], which uses a score to guide testing towards a particular goal (e.g., maximising an error term). In the original implementation this would require custom mutation operators per test,\n   but in Hypothesis this mutation is transparent to the user and they need only specify the goal.\n\nThe internal format is flexible and contains rich information about the structure of generated test cases,\nso it is likely future versions of the software will see other features built on top of it,\nand we hope researchers will use it as a vehicle to explore other interesting possibilities for test-case generation.\n\n# References\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[tool.ruff]\nline-length = 88\ntarget-version = \"py310\"\n\n[tool.ruff.per-file-target-version]\n\"test_typealias_py312.py\" = \"py312\"\n\n[tool.ruff.lint]\nselect = [\n    \"ASYNC\",  # flake8-async\n    \"B\",      # flake8-bugbear\n    \"C4\",     # flake8-comprehensions\n    \"COM\",    # flake8-commas\n    \"DJ\",     # flake8-django\n    \"E\",      # pycodestyle\n    \"F\",      # Pyflakes\n    \"FBT\",    # flake8-boolean-trap\n    \"FLY\",    # flynt\n    \"G\",      # flake8-logging-format\n    \"INT\",    # flake8-gettext\n    \"ISC\",    # flake8-implicit-str-concat\n    \"NPY\",    # NumPy-specific rules\n    \"PD\",     # pandas-vet\n    \"PIE\",    # flake8-pie\n    \"PLE\",    # Pylint errors\n    \"PT\",     # flake8-pytest-style\n    \"RET504\", # flake8-return\n    \"RSE\",    # flake8-raise\n    \"SIM\",    # flake8-simplify\n    \"T10\",    # flake8-debugger\n    \"TID\",    # flake8-tidy-imports\n    \"UP\",     # pyupgrade\n    \"W\",      # pycodestyle\n    \"YTT\",    # flake8-2020\n    \"RUF\",    # Ruff-specific rules\n]\nignore = [\n    \"B008\",\n    \"B018\",\n    \"C408\",\n    \"C420\",\n    \"COM812\",\n    \"DJ007\",\n    \"DJ008\",\n    # \"line too long\". ruff uses tool.ruff.line-length both for this rule, and for `ruff format`.\n    # We want ruff format to match black's 88 line length, so we set tool.ruff.line-length = 88. But\n    # this is a formatter suggestion, not a rule, so we also disable the E501 lint.\n    \"E501\",\n    \"E721\",\n    \"E731\",\n    \"E741\",\n    \"FBT001\",\n    \"FBT003\",\n    \"PD011\",\n    \"PIE790\",  # See https://github.com/astral-sh/ruff/issues/10538\n    \"PT001\",\n    \"PT003\",\n    \"PT006\",\n    \"PT007\",\n    \"PT009\",\n    \"PT011\",\n    \"PT012\",\n    \"PT013\",\n    \"PT015\",\n    \"PT017\",\n    \"PT019\",\n    \"PT023\",\n    \"PT027\",\n    \"PT031\",\n    \"RUF001\",  # don't break our tests by rewriting confusables\n    \"RUF005\",\n    \"RUF017\",\n    \"RUF028\",  # we use fmt: off for black as well as ruff, with differing semantics\n    \"SIM102\",\n    \"SIM105\",\n    \"SIM108\",\n    \"SIM114\",\n    \"SIM300\",\n    \"SIM905\",\n    \"UP031\",\n    \"UP037\",\n]\n\n[tool.ruff.lint.per-file-ignores]\n\"hypothesis-python/src/hypothesis/core.py\" = [\"B030\", \"B904\"]\n\"hypothesis-python/src/hypothesis/internal/compat.py\" = [\"F401\"]\n\"hypothesis-python/tests/nocover/test_imports.py\" = [\"F403\", \"F405\"]\n\"hypothesis-python/tests/numpy/test_randomness.py\" = [\"NPY002\"]\n\"hypothesis-python/src/hypothesis/internal/conjecture/*\" = [\"B023\"]\n\"hypothesis-python/tests/conjecture/test_data_tree.py\" = [\"B023\"]\n\n[tool.mypy]\npython_version = \"3.14\"\nplatform = \"linux\"\n\nallow_redefinition = true\ndisallow_untyped_decorators = true\ndisallow_incomplete_defs = true\nno_implicit_optional = true\nno_implicit_reexport = true\n\nfollow_imports = \"silent\"\nignore_missing_imports = true\n\nstrict_equality = true\nwarn_no_return = true\nwarn_unused_ignores = true\nwarn_unused_configs = true\nwarn_redundant_casts = true\n\ndisable_error_code = \"annotation-unchecked\"\n\n# pytest 9 added support for [tool.pytest], which we should move to when pytest 9\n# is the oldest one we support.\n[tool.pytest.ini_options]\n# -rfEX :: Print a summary of failures, errors, and xpasses (xfails that pass).\naddopts = \"-rfEX --strict-markers --tb=native -p pytester -p no:legacypath --runpytest=subprocess --durations=20 --durations-min=1.0\"\nxfail_strict = true\nfilterwarnings = [\n    \"error\",\n    # https://github.com/pandas-dev/pandas/issues/41199\n    \"default:Creating a LegacyVersion has been deprecated and will be removed in the next major release:DeprecationWarning\",\n    \"default:distutils Version classes are deprecated\\\\. Use packaging\\\\.version instead:DeprecationWarning\",\n    # https://github.com/pandas-dev/pandas/issues/32056 (?)\n    \"default:numpy\\\\.ufunc size changed, may indicate binary incompatibility\\\\. Expected 216 from C header, got 232 from PyObject:RuntimeWarning\",\n    # https://github.com/pandas-dev/pandas/issues/34848\n    \"default:`np\\\\.bool` is a deprecated alias for the builtin `bool`:DeprecationWarning\",\n    \"default:`np\\\\.complex` is a deprecated alias for the builtin `complex`:DeprecationWarning\",\n    \"default:`np\\\\.object` is a deprecated alias for the builtin `object`:DeprecationWarning\",\n    # pytest-cov can't see into subprocesses; we'll see <100% covered if this is an issue\n    \"ignore:Module hypothesis.* was previously imported, but not measured\",\n    \"ignore:CrosshairPrimitiveProvider.realize does not have the for_failure parameter\",\n]\n"
  },
  {
    "path": "requirements/coverage.in",
    "content": "annotated-types\nblack\nclick\ndpcontracts\nfakeredis\nlark\nlibcst\nnumpy\npandas\npyarrow  # Silence warning from Pandas >=2.2, <3 - see https://github.com/pandas-dev/pandas/issues/54466\npytest-cov\npython-dateutil\npytz\ntyping-extensions\nwatchdog\n-r test.in\n"
  },
  {
    "path": "requirements/coverage.txt",
    "content": "#\n# This file is autogenerated by pip-compile with Python 3.14\n# by the following command:\n#\n#    ./build.sh upgrade-requirements\n#\nannotated-types==0.7.0\n    # via -r requirements/coverage.in\nblack==26.3.1\n    # via -r requirements/coverage.in\nclick==8.3.1\n    # via\n    #   -r requirements/coverage.in\n    #   black\ncoverage[toml]==7.13.4\n    # via pytest-cov\ndpcontracts==0.6.0\n    # via -r requirements/coverage.in\nexecnet==2.1.2\n    # via pytest-xdist\nfakeredis==2.34.1\n    # via -r requirements/coverage.in\niniconfig==2.3.0\n    # via pytest\nlark==1.3.1\n    # via -r requirements/coverage.in\nlibcst==1.8.6\n    # via -r requirements/coverage.in\nmypy-extensions==1.1.0\n    # via black\nnumpy==2.4.3\n    # via\n    #   -r requirements/coverage.in\n    #   pandas\npackaging==26.0\n    # via\n    #   black\n    #   pytest\npandas==3.0.1\n    # via -r requirements/coverage.in\npathspec==1.0.4\n    # via black\npexpect==4.9.0\n    # via -r requirements/test.in\nplatformdirs==4.9.4\n    # via black\npluggy==1.6.0\n    # via\n    #   pytest\n    #   pytest-cov\nptyprocess==0.7.0\n    # via pexpect\npyarrow==23.0.1\n    # via -r requirements/coverage.in\npygments==2.19.2\n    # via pytest\npytest==9.0.2\n    # via\n    #   -r requirements/test.in\n    #   pytest-cov\n    #   pytest-xdist\npytest-cov==7.0.0\n    # via -r requirements/coverage.in\npytest-xdist==3.8.0\n    # via -r requirements/test.in\npython-dateutil==2.9.0.post0\n    # via\n    #   -r requirements/coverage.in\n    #   pandas\npytokens==0.4.1\n    # via black\npytz==2026.1.post1\n    # via -r requirements/coverage.in\npyyaml==6.0.3\n    # via libcst\nredis==7.3.0\n    # via fakeredis\nsix==1.17.0\n    # via python-dateutil\nsortedcontainers==2.4.0\n    # via\n    #   fakeredis\n    #   hypothesis (hypothesis-python/pyproject.toml)\ntyping-extensions==4.15.0\n    # via -r requirements/coverage.in\nwatchdog==6.0.0\n    # via -r requirements/coverage.in\n"
  },
  {
    "path": "requirements/crosshair.in",
    "content": "crosshair-tool\nhypothesis-crosshair\n-r test.in\n"
  },
  {
    "path": "requirements/crosshair.txt",
    "content": "#\n# This file is autogenerated by pip-compile with Python 3.14\n# by the following command:\n#\n#    ./build.sh upgrade-requirements\n#\nattrs==25.4.0\n    # via\n    #   cattrs\n    #   lsprotocol\n    #   pygls\ncattrs==26.1.0\n    # via\n    #   lsprotocol\n    #   pygls\ncrosshair-tool==0.0.102\n    # via\n    #   -r requirements/crosshair.in\n    #   hypothesis-crosshair\nexecnet==2.1.2\n    # via pytest-xdist\nhypothesis==6.151.9\n    # via hypothesis-crosshair\nhypothesis-crosshair==0.0.27\n    # via -r requirements/crosshair.in\nimportlib-metadata==8.7.1\n    # via crosshair-tool\nimportlib-resources==6.5.2\n    # via typeshed-client\niniconfig==2.3.0\n    # via pytest\nlsprotocol==2025.0.0\n    # via pygls\nmypy-extensions==1.1.0\n    # via typing-inspect\npackaging==26.0\n    # via\n    #   crosshair-tool\n    #   pytest\npexpect==4.9.0\n    # via -r requirements/test.in\npluggy==1.6.0\n    # via pytest\nptyprocess==0.7.0\n    # via pexpect\npygls==2.0.1\n    # via crosshair-tool\npygments==2.19.2\n    # via pytest\npytest==9.0.2\n    # via\n    #   -r requirements/test.in\n    #   pytest-xdist\npytest-xdist==3.8.0\n    # via -r requirements/test.in\nsortedcontainers==2.4.0\n    # via\n    #   hypothesis\n    #   hypothesis (hypothesis-python/pyproject.toml)\ntypeshed-client==2.9.0\n    # via crosshair-tool\ntyping-extensions==4.15.0\n    # via\n    #   cattrs\n    #   crosshair-tool\n    #   typeshed-client\n    #   typing-inspect\ntyping-inspect==0.9.0\n    # via crosshair-tool\nz3-solver==4.16.0.0\n    # via crosshair-tool\nzipp==3.23.0\n    # via importlib-metadata\n"
  },
  {
    "path": "requirements/fuzzing.in",
    "content": "hypofuzz\n-r coverage.in\n"
  },
  {
    "path": "requirements/fuzzing.txt",
    "content": "#\n# This file is autogenerated by pip-compile with Python 3.14\n# by the following command:\n#\n#    ./build.sh upgrade-requirements\n#\nannotated-types==0.7.0\n    # via -r requirements/coverage.in\nanyio==4.12.1\n    # via starlette\nattrs==25.4.0\n    # via\n    #   outcome\n    #   trio\nblack==26.3.1\n    # via\n    #   -r requirements/coverage.in\n    #   hypofuzz\n    #   hypothesis\nclick==8.3.1\n    # via\n    #   -r requirements/coverage.in\n    #   black\n    #   hypothesis\ncoverage[toml]==7.13.4\n    # via\n    #   hypofuzz\n    #   pytest-cov\ndpcontracts==0.6.0\n    # via -r requirements/coverage.in\nexecnet==2.1.2\n    # via pytest-xdist\nfakeredis==2.34.1\n    # via -r requirements/coverage.in\nh11==0.16.0\n    # via\n    #   hypercorn\n    #   wsproto\nh2==4.3.0\n    # via hypercorn\nhpack==4.1.0\n    # via h2\nhypercorn==0.18.0\n    # via hypofuzz\nhyperframe==6.1.0\n    # via h2\nhypofuzz==25.11.1\n    # via -r requirements/fuzzing.in\nhypothesis[cli,watchdog]==6.151.9\n    # via hypofuzz\nidna==3.11\n    # via\n    #   anyio\n    #   trio\niniconfig==2.3.0\n    # via pytest\nlark==1.3.1\n    # via -r requirements/coverage.in\nlibcst==1.8.6\n    # via\n    #   -r requirements/coverage.in\n    #   hypofuzz\nmarkdown-it-py==4.0.0\n    # via rich\nmdurl==0.1.2\n    # via markdown-it-py\nmypy-extensions==1.1.0\n    # via black\nnumpy==2.4.3\n    # via\n    #   -r requirements/coverage.in\n    #   pandas\noutcome==1.3.0.post0\n    # via trio\npackaging==26.0\n    # via\n    #   black\n    #   pytest\npandas==3.0.1\n    # via -r requirements/coverage.in\npathspec==1.0.4\n    # via black\npexpect==4.9.0\n    # via -r requirements/test.in\nplatformdirs==4.9.4\n    # via black\npluggy==1.6.0\n    # via\n    #   pytest\n    #   pytest-cov\npriority==2.0.0\n    # via hypercorn\npsutil==7.2.2\n    # via hypofuzz\nptyprocess==0.7.0\n    # via pexpect\npyarrow==23.0.1\n    # via -r requirements/coverage.in\npygments==2.19.2\n    # via\n    #   pytest\n    #   rich\npytest==9.0.2\n    # via\n    #   -r requirements/test.in\n    #   hypofuzz\n    #   pytest-cov\n    #   pytest-xdist\npytest-cov==7.0.0\n    # via -r requirements/coverage.in\npytest-xdist==3.8.0\n    # via -r requirements/test.in\npython-dateutil==2.9.0.post0\n    # via\n    #   -r requirements/coverage.in\n    #   pandas\npytokens==0.4.1\n    # via black\npytz==2026.1.post1\n    # via -r requirements/coverage.in\npyyaml==6.0.3\n    # via libcst\nredis==7.3.0\n    # via fakeredis\nrich==14.3.3\n    # via hypothesis\nsix==1.17.0\n    # via python-dateutil\nsniffio==1.3.1\n    # via trio\nsortedcontainers==2.4.0\n    # via\n    #   fakeredis\n    #   hypothesis\n    #   hypothesis (hypothesis-python/pyproject.toml)\n    #   trio\nstarlette==0.52.1\n    # via hypofuzz\ntrio==0.33.0\n    # via hypofuzz\ntyping-extensions==4.15.0\n    # via -r requirements/coverage.in\nwatchdog==6.0.0\n    # via\n    #   -r requirements/coverage.in\n    #   hypothesis\nwsproto==1.3.2\n    # via hypercorn\n"
  },
  {
    "path": "requirements/test.in",
    "content": "pexpect\npytest\npytest-xdist\n"
  },
  {
    "path": "requirements/test.txt",
    "content": "#\n# This file is autogenerated by pip-compile with Python 3.14\n# by the following command:\n#\n#    ./build.sh upgrade-requirements\n#\nexecnet==2.1.2\n    # via pytest-xdist\niniconfig==2.3.0\n    # via pytest\npackaging==26.0\n    # via pytest\npexpect==4.9.0\n    # via -r requirements/test.in\npluggy==1.6.0\n    # via pytest\nptyprocess==0.7.0\n    # via pexpect\npygments==2.19.2\n    # via pytest\npytest==9.0.2\n    # via\n    #   -r requirements/test.in\n    #   pytest-xdist\npytest-xdist==3.8.0\n    # via -r requirements/test.in\nsortedcontainers==2.4.0\n    # via hypothesis (hypothesis-python/pyproject.toml)\n"
  },
  {
    "path": "requirements/tools.in",
    "content": "codespell\ncoverage\ndjango\ndpcontracts\nipython\nlark\nlibcst\nmypy\nnumpy\npelican[markdown]\npip-tools\npyright\npython-dateutil\nrequests\nrestructuredtext-lint\nruff\nshed==2024.1.1\nsphinx\nsphinx-autobuild\nsphinx-codeautolink\nsphinx-jsonschema\nfuro\nsphinx-selective-exclude\ntox\ntwine\ntypes-click\ntypes-pytz\ntypes-redis\ntyping-extensions\nwatchdog # for typing\nbuild\nsortedcontainers-stubs # for typing\nattrs # for typing\ntomli # for update_pyproject_toml\n-r test.in\n"
  },
  {
    "path": "requirements/tools.txt",
    "content": "#\n# This file is autogenerated by pip-compile with Python 3.14\n# by the following command:\n#\n#    ./build.sh upgrade-requirements\n#\naccessible-pygments==0.0.5\n    # via furo\nalabaster==1.0.0\n    # via sphinx\nanyio==4.12.1\n    # via\n    #   starlette\n    #   watchfiles\nasgiref==3.11.1\n    # via django\nasttokens==3.0.1\n    # via stack-data\nattrs==25.4.0\n    # via -r requirements/tools.in\nautoflake==2.3.3\n    # via shed\nbabel==2.18.0\n    # via sphinx\nbeautifulsoup4==4.14.3\n    # via\n    #   furo\n    #   sphinx-codeautolink\nblack==26.3.1\n    # via shed\nblinker==1.9.0\n    # via pelican\nbuild==1.4.0\n    # via\n    #   -r requirements/tools.in\n    #   pip-tools\ncachetools==7.0.5\n    # via tox\ncertifi==2026.2.25\n    # via requests\ncffi==2.0.0\n    # via cryptography\ncharset-normalizer==3.4.5\n    # via requests\nclick==8.3.1\n    # via\n    #   black\n    #   pip-tools\n    #   uvicorn\ncodespell==2.4.2\n    # via -r requirements/tools.in\ncolorama==0.4.6\n    # via\n    #   sphinx-autobuild\n    #   tox\ncom2ann==0.3.0\n    # via shed\ncoverage==7.13.4\n    # via -r requirements/tools.in\ncryptography==46.0.5\n    # via\n    #   secretstorage\n    #   types-pyopenssl\n    #   types-redis\ndecorator==5.2.1\n    # via ipython\ndistlib==0.4.0\n    # via virtualenv\ndjango==6.0.3\n    # via -r requirements/tools.in\ndocutils==0.22.4\n    # via\n    #   pelican\n    #   readme-renderer\n    #   restructuredtext-lint\n    #   sphinx\n    #   sphinx-jsonschema\ndpcontracts==0.6.0\n    # via -r requirements/tools.in\nexecnet==2.1.2\n    # via pytest-xdist\nexecuting==2.2.1\n    # via stack-data\nfeedgenerator==2.2.1\n    # via pelican\nfilelock==3.25.2\n    # via\n    #   python-discovery\n    #   tox\n    #   virtualenv\nfuro==2025.12.19\n    # via -r requirements/tools.in\nh11==0.16.0\n    # via uvicorn\nid==1.6.1\n    # via twine\nidna==3.11\n    # via\n    #   anyio\n    #   requests\nimagesize==2.0.0\n    # via sphinx\niniconfig==2.3.0\n    # via pytest\nipython==9.11.0\n    # via -r requirements/tools.in\nipython-pygments-lexers==1.1.1\n    # via ipython\nisort==8.0.1\n    # via shed\njaraco-classes==3.4.0\n    # via keyring\njaraco-context==6.1.1\n    # via keyring\njaraco-functools==4.4.0\n    # via keyring\njedi==0.19.2\n    # via ipython\njeepney==0.9.0\n    # via\n    #   keyring\n    #   secretstorage\njinja2==3.1.6\n    # via\n    #   pelican\n    #   sphinx\njsonpointer==3.0.0\n    # via sphinx-jsonschema\nkeyring==25.7.0\n    # via twine\nlark==1.3.1\n    # via -r requirements/tools.in\nlibcst==1.8.6\n    # via\n    #   -r requirements/tools.in\n    #   shed\nlibrt==0.8.1\n    # via mypy\nmarkdown==3.10.2\n    # via pelican\nmarkdown-it-py==4.0.0\n    # via rich\nmarkupsafe==3.0.3\n    # via jinja2\nmatplotlib-inline==0.2.1\n    # via ipython\nmdurl==0.1.2\n    # via markdown-it-py\nmore-itertools==10.8.0\n    # via\n    #   jaraco-classes\n    #   jaraco-functools\nmypy==1.19.1\n    # via -r requirements/tools.in\nmypy-extensions==1.1.0\n    # via\n    #   black\n    #   mypy\nnh3==0.3.3\n    # via readme-renderer\nnodeenv==1.10.0\n    # via pyright\nnumpy==2.4.3\n    # via -r requirements/tools.in\nordered-set==4.1.0\n    # via pelican\npackaging==26.0\n    # via\n    #   black\n    #   build\n    #   pyproject-api\n    #   pytest\n    #   sphinx\n    #   tox\n    #   twine\n    #   wheel\nparso==0.8.6\n    # via jedi\npathspec==1.0.4\n    # via\n    #   black\n    #   mypy\npelican[markdown]==4.11.0.post0\n    # via -r requirements/tools.in\npexpect==4.9.0\n    # via\n    #   -r requirements/test.in\n    #   ipython\npip-tools==7.5.3\n    # via -r requirements/tools.in\nplatformdirs==4.9.4\n    # via\n    #   black\n    #   python-discovery\n    #   tox\n    #   virtualenv\npluggy==1.6.0\n    # via\n    #   pytest\n    #   tox\nprompt-toolkit==3.0.52\n    # via ipython\nptyprocess==0.7.0\n    # via pexpect\npure-eval==0.2.3\n    # via stack-data\npycparser==3.0\n    # via cffi\npyflakes==3.4.0\n    # via autoflake\npygments==2.18.0\n    # via\n    #   accessible-pygments\n    #   furo\n    #   ipython\n    #   ipython-pygments-lexers\n    #   pelican\n    #   pytest\n    #   readme-renderer\n    #   rich\n    #   sphinx\npyproject-api==1.10.0\n    # via tox\npyproject-hooks==1.2.0\n    # via\n    #   build\n    #   pip-tools\npyright==1.1.408\n    # via -r requirements/tools.in\npytest==9.0.2\n    # via\n    #   -r requirements/test.in\n    #   pytest-xdist\npytest-xdist==3.8.0\n    # via -r requirements/test.in\npython-dateutil==2.9.0.post0\n    # via\n    #   -r requirements/tools.in\n    #   pelican\npython-discovery==1.1.3\n    # via virtualenv\npytokens==0.4.1\n    # via black\npyupgrade==3.21.2\n    # via shed\npyyaml==6.0.3\n    # via\n    #   libcst\n    #   sphinx-jsonschema\nreadme-renderer==44.0\n    # via twine\nrequests==2.32.5\n    # via\n    #   -r requirements/tools.in\n    #   requests-toolbelt\n    #   sphinx\n    #   sphinx-jsonschema\n    #   twine\nrequests-toolbelt==1.0.0\n    # via twine\nrestructuredtext-lint==2.0.2\n    # via -r requirements/tools.in\nrfc3986==2.0.0\n    # via twine\nrich==14.3.3\n    # via\n    #   pelican\n    #   twine\nroman-numerals==4.1.0\n    # via sphinx\nruff==0.15.6\n    # via -r requirements/tools.in\nsecretstorage==3.5.0\n    # via keyring\nshed==2024.1.1\n    # via -r requirements/tools.in\nsix==1.17.0\n    # via python-dateutil\nsnowballstemmer==3.0.1\n    # via sphinx\nsortedcontainers==2.4.0\n    # via\n    #   hypothesis (hypothesis-python/pyproject.toml)\n    #   sortedcontainers-stubs\nsortedcontainers-stubs==2.4.3\n    # via -r requirements/tools.in\nsoupsieve==2.8.3\n    # via beautifulsoup4\nsphinx==9.1.0\n    # via\n    #   -r requirements/tools.in\n    #   furo\n    #   sphinx-autobuild\n    #   sphinx-basic-ng\n    #   sphinx-codeautolink\nsphinx-autobuild==2025.8.25\n    # via -r requirements/tools.in\nsphinx-basic-ng==1.0.0b2\n    # via furo\nsphinx-codeautolink==0.17.5\n    # via -r requirements/tools.in\nsphinx-jsonschema==1.19.2\n    # via -r requirements/tools.in\nsphinx-selective-exclude==1.0.3\n    # via -r requirements/tools.in\nsphinxcontrib-applehelp==2.0.0\n    # via sphinx\nsphinxcontrib-devhelp==2.0.0\n    # via sphinx\nsphinxcontrib-htmlhelp==2.1.0\n    # via sphinx\nsphinxcontrib-jsmath==1.0.1\n    # via sphinx\nsphinxcontrib-qthelp==2.0.0\n    # via sphinx\nsphinxcontrib-serializinghtml==2.0.0\n    # via sphinx\nsqlparse==0.5.5\n    # via django\nstack-data==0.6.3\n    # via ipython\nstarlette==0.52.1\n    # via sphinx-autobuild\ntokenize-rt==6.2.0\n    # via pyupgrade\ntomli==2.4.0\n    # via -r requirements/tools.in\ntomli-w==1.2.0\n    # via tox\ntox==4.49.1\n    # via -r requirements/tools.in\ntraitlets==5.14.3\n    # via\n    #   ipython\n    #   matplotlib-inline\ntwine==6.2.0\n    # via -r requirements/tools.in\ntypes-cffi==1.17.0.20260307\n    # via types-pyopenssl\ntypes-click==7.1.8\n    # via -r requirements/tools.in\ntypes-pyopenssl==24.1.0.20240722\n    # via types-redis\ntypes-pytz==2026.1.1.20260304\n    # via -r requirements/tools.in\ntypes-redis==4.6.0.20241004\n    # via -r requirements/tools.in\ntypes-setuptools==82.0.0.20260210\n    # via types-cffi\ntyping-extensions==4.15.0\n    # via\n    #   -r requirements/tools.in\n    #   beautifulsoup4\n    #   mypy\n    #   pyright\n    #   sortedcontainers-stubs\nunidecode==1.4.0\n    # via pelican\nurllib3==2.6.3\n    # via\n    #   id\n    #   requests\n    #   twine\nuvicorn==0.41.0\n    # via sphinx-autobuild\nvirtualenv==21.2.0\n    # via tox\nwatchdog==6.0.0\n    # via -r requirements/tools.in\nwatchfiles==1.1.1\n    # via\n    #   pelican\n    #   sphinx-autobuild\nwcwidth==0.6.0\n    # via prompt-toolkit\nwebsockets==16.0\n    # via sphinx-autobuild\nwheel==0.46.3\n    # via pip-tools\n\n# The following packages are considered to be unsafe in a requirements file:\npip==26.0.1\n    # via pip-tools\nsetuptools==82.0.1\n    # via pip-tools\n"
  },
  {
    "path": "tooling/README.md",
    "content": "# Hypothesis Build Tooling\n\nThis is a piece of software for managing Hypothesis's build tasks, releases,\netc. It's very Hypothesis specific, though it may become less so in the future.\n"
  },
  {
    "path": "tooling/codespell-dict.txt",
    "content": "sipport->support\nstratgy->strategy\n"
  },
  {
    "path": "tooling/codespell-ignore.txt",
    "content": "aas\nassertIn\nCopin\ncrate\ndamon\nnd\nned\nnin\nstrat\ntread\nrouge\ntey\ntham\ndatas\n"
  },
  {
    "path": "tooling/scripts/common.sh",
    "content": "#!/usr/bin/env bash\n\n# This file is not really a script but is intended for sourcing from other\n# scripts so that they can share a common set of paths conveniently.\n\nset -o errexit\nset -o nounset\n\nHERE=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\nROOT=\"$(git -C \"$HERE\" rev-parse --show-toplevel)\"\n\nexport ROOT\nexport BUILD_RUNTIMES=${BUILD_RUNTIMES:-$HOME/.cache/hypothesis-build-runtimes}\nexport BASE=\"$BUILD_RUNTIMES\"\nexport PYENV=\"$BASE/pyenv\"\nexport SNAKEPIT=\"$BASE/python-versions/\"\n\nexport XDG_CACHE_HOME=\"$BUILD_RUNTIMES/.cache\"\n\n# Note: Deliberately ignoring BUILD_RUNTIMES configuration because we don't\n# want this to go in cache, because it takes up a huge amount of space and\n# slows everything down!\nexport VIRTUALENVS=\"${TMPDIR:-/tmp}/.hypothesis-runtimes/virtualenvs/\"\n\npythonloc() {\n    VERSION=\"$1\"\n    echo \"$SNAKEPIT/$VERSION\"\n}\n"
  },
  {
    "path": "tooling/scripts/ensure-python.sh",
    "content": "#!/usr/bin/env bash\n\nif [ -n \"${CI:-}\" ] ; then echo \"::group::Ensure Python\" ; fi\n\nset -o errexit\nset -o nounset\nset -x\n\nHERE=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n\n# shellcheck source=tooling/scripts/common.sh\nsource \"$HERE/common.sh\"\n\n# This is to guard against multiple builds in parallel. The various installers will tend\n# to stomp all over each other if you do this and they haven't previously successfully\n# succeeded. We use a lock file to block progress so only one install runs at a time.\n# This script should be pretty fast once files are cached, so the loss of concurrency\n# is not a major problem.\n# This should be using the lockfile command, but that's not available on the\n# containerized travis and we can't install it without sudo.\n# It is unclear if this is actually useful. I was seeing behaviour that suggested\n# concurrent runs of the installer, but I can't seem to find any evidence of this lock\n# ever not being acquired.\n\nVERSION=\"$1\"\nTARGET=$(pythonloc \"$VERSION\")\n\nif [ ! -e \"$TARGET/bin/python\" ] ; then\n    mkdir -p \"$BASE\"\n\n    LOCKFILE=\"$BASE/.install-lockfile\"\n    while true; do\n      if mkdir \"$LOCKFILE\" 2>/dev/null; then\n        echo \"Successfully acquired installer.\"\n        break\n      else\n        echo \"Failed to acquire lock. Is another installer running? Waiting a bit.\"\n      fi\n\n      sleep $(( ( RANDOM % 10 ) + 1 )).$(( RANDOM % 100 ))s\n\n      if (( $(date '+%s') > 300 + $(stat --format=%X \"$LOCKFILE\") )); then\n        echo \"We've waited long enough\"\n        rm -rf \"$LOCKFILE\"\n      fi\n    done\n    trap 'rm -rf $LOCKFILE' EXIT\n\n\n    if [ ! -d \"$PYENV/.git\" ]; then\n      rm -rf \"$PYENV\"\n      git clone https://github.com/pyenv/pyenv.git \"$PYENV\"\n    else\n      back=$PWD\n      cd \"$PYENV\"\n      git fetch || echo \"Update failed to complete. Ignoring\"\n      git reset --hard origin/master\n      cd \"$back\"\n    fi\n\n    # See if installing all of these will fix our build issues...\n    if (command -v apt-get >/dev/null 2>&1) && { [ -n \"${GITHUB_ACTIONS-}\" ] || [ -n \"${CODESPACES-}\" ] ; }; then\n      sudo apt-get update\n      sudo apt-get install -y \\\n        build-essential \\\n        libbz2-dev \\\n        libffi-dev \\\n        libgdbm-dev \\\n        libgdbm-compat-dev \\\n        liblzma-dev \\\n        libncurses5-dev \\\n        libreadline-dev \\\n        libsqlite3-dev \\\n        libssl-dev \\\n        tk-dev \\\n        uuid-dev \\\n        zlib1g-dev\n    fi\n\n    for _ in $(seq 5); do\n        if OUTPUT=$(\"$BASE/pyenv/plugins/python-build/bin/python-build\" \"$VERSION\" \"$TARGET\" 2>&1); then\n            exit 0\n        fi\n        if echo \"$OUTPUT\" | grep -q \"definition not found\"; then\n            echo \"Python version $VERSION is no longer available.\"\n            echo \"Please run 'make upgrade-requirements' to update to the latest version.\"\n            exit 1\n        fi\n        echo \"Command failed. For a possible solution, visit\"\n        echo \"https://github.com/pyenv/pyenv/wiki#suggested-build-environment.\"\n        echo \"Retrying...\"\n        sleep $(( ( RANDOM % 10 )  + 1 )).$(( RANDOM % 100 ))s\n    done\nfi\n\nif [ -n \"${CI:-}\" ] ; then echo \"::endgroup::\" ; fi\n"
  },
  {
    "path": "tooling/scripts/tool-hash.py",
    "content": "#!/usr/bin/env python\n\n# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport hashlib\nimport sys\n\nif __name__ == \"__main__\":\n    print(hashlib.sha384(sys.stdin.read().encode()).hexdigest()[:10])\n"
  },
  {
    "path": "tooling/setup.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\n\nimport setuptools\n\n\ndef local_file(name):\n    return os.path.relpath(os.path.join(os.path.dirname(__file__), name))\n\n\nSOURCE = local_file(\"src\")\nREADME = local_file(\"README.md\")\n\nsetuptools.setup(\n    name=\"hypothesis-tooling\",\n    # We don't actually ship this, it just has a setup.py for convenience.\n    version=\"0.0.0\",\n    author=\"David R. MacIver\",\n    author_email=\"david@drmaciver.com\",\n    packages=setuptools.find_packages(SOURCE),\n    package_dir={\"\": SOURCE},\n    url=\"https://github.com/HypothesisWorks/hypothesis-python/tree/master/tooling\",\n    license=\"MPL v2\",\n    description=\"A library for property-based testing\",\n    python_requires=\">=3.7\",\n    long_description=open(README).read(),  # noqa\n)\n"
  },
  {
    "path": "tooling/src/hypothesistooling/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport shlex\nimport subprocess\nfrom pathlib import Path\n\n\ndef current_branch():\n    return (\n        subprocess.check_output([\"git\", \"rev-parse\", \"--abbrev-ref\", \"HEAD\"])\n        .decode(\"ascii\")\n        .strip()\n    )\n\n\ndef tags():\n    result = [\n        t.decode(\"ascii\") for t in subprocess.check_output([\"git\", \"tag\"]).split(b\"\\n\")\n    ]\n    assert len(set(result)) == len(result)\n    return set(result)\n\n\nROOT = Path(\n    subprocess.check_output(\n        [\"git\", \"-C\", os.path.dirname(__file__), \"rev-parse\", \"--show-toplevel\"]\n    )\n    .decode(\"ascii\")\n    .strip()\n)\nREPO_TESTS = ROOT / \"whole_repo_tests\"\n\n\ndef hash_for_name(name):\n    return subprocess.check_output([\"git\", \"rev-parse\", name]).decode(\"ascii\").strip()\n\n\ndef is_ancestor(a, b):\n    check = subprocess.call([\"git\", \"merge-base\", \"--is-ancestor\", a, b])\n    assert 0 <= check <= 1\n    return check == 0\n\n\ndef merge_base(a, b):\n    return subprocess.check_output([\"git\", \"merge-base\", a, b]).strip()\n\n\ndef point_of_divergence():\n    return merge_base(\"HEAD\", \"origin/master\")\n\n\ndef has_changes(files):\n    command = [\n        \"git\",\n        \"diff\",\n        \"--no-patch\",\n        \"--exit-code\",\n        point_of_divergence(),\n        \"HEAD\",\n        \"--\",\n        *files,\n    ]\n    return subprocess.call(command) != 0\n\n\ndef has_uncommitted_changes(filename):\n    return subprocess.call([\"git\", \"diff\", \"--exit-code\", filename]) != 0\n\n\ndef last_committer():\n    out, _ = subprocess.Popen(\n        [\"git\", \"log\", \"-1\", \"--pretty=format:%an\"],\n        stdout=subprocess.PIPE,\n        universal_newlines=True,\n    ).communicate()\n    return out\n\n\ndef git(*args):\n    subprocess.check_call((\"git\", *args))\n\n\nTOOLING_COMMITTER_NAME = \"CI on behalf of the Hypothesis team\"\n\n\ndef configure_git():\n    git(\"config\", \"user.name\", TOOLING_COMMITTER_NAME)\n    git(\"config\", \"user.email\", \"david@drmaciver.com\")\n\n\ndef create_tag(tagname):\n    assert tagname not in tags()\n    git(\"tag\", tagname)\n\n\ndef push_tag(tagname):\n    assert_can_release()\n    subprocess.check_call([\"git\", \"push\", \"origin\", shlex.quote(tagname)])\n    subprocess.check_call([\"git\", \"push\", \"origin\", \"HEAD:master\"])\n\n\ndef assert_can_release():\n    assert not IS_PULL_REQUEST, \"Cannot release from pull requests\"\n\n\ndef modified_files():\n    files = set()\n    for command in [\n        [\n            \"git\",\n            \"diff\",\n            \"--name-only\",\n            \"--diff-filter=d\",\n            point_of_divergence(),\n            \"HEAD\",\n        ],\n        [\"git\", \"diff\", \"--name-only\"],\n    ]:\n        diff_output = subprocess.check_output(command).decode(\"ascii\")\n        for l in diff_output.split(\"\\n\"):\n            filepath = l.strip()\n            if filepath and os.path.exists(filepath):\n                files.add(Path(filepath))\n    return files\n\n\ndef all_files() -> list[Path]:\n    return [\n        Path(f)\n        for f in subprocess.check_output([\"git\", \"ls-files\"])\n        .decode(\"ascii\")\n        .splitlines()\n        if os.path.exists(f)\n    ]\n\n\ndef changed_files_from_master():\n    \"\"\"Returns a list of files which have changed between a branch and master.\"\"\"\n    files = set()\n    command = [\"git\", \"diff\", \"--name-only\", \"HEAD\", \"master\"]\n    diff_output = subprocess.check_output(command).decode(\"ascii\")\n    for line in diff_output.splitlines():\n        filepath = line.strip()\n        if filepath:\n            files.add(filepath)\n    return files\n\n\nIS_PULL_REQUEST = os.environ.get(\"GITHUB_REF\", \"\").startswith(\"refs/pull/\")\n\n\ndef all_projects():\n    import hypothesistooling.projects.hypothesispython as hp\n\n    return [hp]\n"
  },
  {
    "path": "tooling/src/hypothesistooling/__main__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport pathlib\nimport re\nimport subprocess\nimport sys\nfrom datetime import date\nfrom pathlib import Path\nfrom textwrap import indent\n\nimport requests\nfrom coverage.config import CoverageConfig\n\nimport hypothesistooling as tools\nimport hypothesistooling.projects.hypothesispython as hp\nfrom hypothesistooling import installers as install, releasemanagement as rm\nfrom hypothesistooling.scripts import pip_tool\n\nTASKS = {}\nBUILD_FILES = tuple(\n    os.path.join(tools.ROOT, f)\n    for f in [\"tooling\", \"requirements\", \".github\", \"hypothesis-python/tox.ini\"]\n)\nTODAY = date.today().isoformat()\n\n\ndef task(if_changed=()):\n    if not isinstance(if_changed, tuple):\n        if_changed = (if_changed,)\n\n    def accept(fn):\n        def wrapped(*args, **kwargs):\n            if if_changed and tools.IS_PULL_REQUEST:\n                if not tools.has_changes(if_changed + BUILD_FILES):\n                    changed = \", \".join(map(str, if_changed))\n                    print(f\"Skipping task due to no changes in {changed}\")\n                    return\n            fn(*args, **kwargs)\n\n        wrapped.__name__ = fn.__name__\n        name = fn.__name__.replace(\"_\", \"-\")\n        if name != \"<lambda>\":\n            TASKS[name] = wrapped\n        return wrapped\n\n    return accept\n\n\n@task()\ndef check_installed():\n    \"\"\"No-op task that can be used to test for a successful install (so we\n    don't fail to run if a previous install failed midway).\"\"\"\n\n\ndef codespell(*files):\n    pip_tool(\n        \"codespell\",\n        \"--check-hidden\",\n        \"--check-filenames\",\n        \"--ignore-words=./tooling/codespell-ignore.txt\",\n        # passing a custom --dictionary disables the default dictionary by default.\n        # Add it back in with --dictionary=-.\n        \"--dictionary=-\",\n        \"--dictionary=./tooling/codespell-dict.txt\",\n        \"--skip=__pycache__,.mypy_cache,.venv,.git,tlds-alpha-by-domain.txt\",\n        *files,\n    )\n\n\n@task()\ndef lint():\n    pip_tool(\"ruff\", \"check\", \".\")\n    codespell(*(p for p in tools.all_files() if not p.name.endswith(\"by-domain.txt\")))\n\n    failed = False\n\n    matches = subprocess.run(\n        r\"git grep -En '@(dataclasses\\.)?dataclass\\(.*\\)' \"\n        \"| grep -Ev 'frozen=.*slots=|slots=.*frozen='\",\n        shell=True,\n        capture_output=True,\n        text=True,\n    ).stdout\n    if matches:\n        print(\"\\nAll dataclass decorators must pass slots= and frozen= arguments:\")\n        print(indent(matches, \"    \"))\n        failed = True\n\n    matches = subprocess.run(\n        r\"git grep -nP '\\b(the|as|a|to|because|user|test|about|from|only)\\s+\\1\\b'\",\n        shell=True,\n        capture_output=True,\n        text=True,\n    ).stdout\n    if matches:\n        print(\"\\nFound duplicate words:\")\n        print(indent(matches, \"    \"))\n        failed = True\n\n    if failed:\n        sys.exit(1)\n\n\ndef do_release(package):\n    if not package.has_release():\n        print(f\"No release for {package.__name__}\")\n        return\n\n    os.chdir(package.BASE_DIR)\n\n    print(\"Updating changelog and version\")\n    package.update_changelog_and_version()\n\n    print(\"Committing changes\")\n    rm.commit_pending_release(package)\n\n    print(\"Building distribution\")\n    package.build_distribution()\n\n    print(\"Looks good to release!\")\n\n    tag_name = package.tag_name()\n\n    print(f\"Creating tag {tag_name}\")\n    tools.create_tag(tag_name)\n    tools.push_tag(tag_name)\n\n    print(\"Uploading distribution\")\n    package.upload_distribution()\n\n\n@task()\ndef deploy():\n    HEAD = tools.hash_for_name(\"HEAD\")\n    MASTER = tools.hash_for_name(\"origin/master\")\n\n    print(\"Current head:  \", HEAD)\n    print(\"Current master:\", MASTER)\n\n    if not tools.is_ancestor(HEAD, MASTER):\n        print(\"Not deploying due to not being on master\")\n        sys.exit(0)\n\n    if \"TWINE_PASSWORD\" not in os.environ:\n        print(\"Running without access to secure variables, so no deployment\")\n        sys.exit(0)\n\n    tools.configure_git()\n\n    for project in tools.all_projects():\n        do_release(project)\n\n    sys.exit(0)\n\n\n# See https://www.linuxfoundation.org/blog/copyright-notices-in-open-source-software-projects/\nHEADER = \"\"\"\n# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\"\"\".strip()\n\n# this pattern is copied from shed\n# https://github.com/Zac-HD/shed/blob/6471da71c5b5cc443443ef5ed072799db275e7c0/src/shed/__init__.py#L297\nrst_pattern = re.compile(\n    r\"(?P<before>\"\n    r\"^(?P<indent> *)\\.\\. \"\n    r\"(?P<block>jupyter-execute::|\"\n    r\"invisible-code-block: python|\"  # magic rst comment for Sybil doctests\n    r\"(code|code-block|sourcecode|ipython):: (python|py|sage|python3|py3|numpy))\\n\"\n    r\"((?P=indent) +:.*\\n)*\"\n    r\"\\n*\"\n    r\")\"\n    r\"(?P<code>(^((?P=indent) +.*)?\\n)+)\",\n    flags=re.MULTILINE,\n)\n\n\ndef remove_consecutive_newlines_in_rst(path: Path):\n    # replace 2+ empty lines in `.. code-block:: python` blocks with just one empty\n    # line\n    content = path.read_text()\n    processed_content = rst_pattern.sub(\n        lambda m: m[\"before\"] + re.sub(r\"\\n{3,}\", \"\\n\\n\", m[\"code\"]), content\n    )\n    if processed_content != content:\n        path.write_text(processed_content)\n\n\n@task()\ndef format():\n    changed = tools.modified_files()\n\n    format_all = os.environ.get(\"FORMAT_ALL\", \"\").lower() == \"true\"\n    if \"requirements/tools.txt\" in changed:\n        # We've changed the tools, which includes a lot of our formatting\n        # logic, so we need to rerun formatters.\n        format_all = True\n\n    paths = tools.all_files() if format_all else changed\n\n    doc_paths_to_format = [p for p in sorted(paths) if p.suffix in {\".rst\", \".md\"}]\n    paths_to_format = [p for p in sorted(paths) if p.suffix == \".py\"]\n\n    if not (paths_to_format or doc_paths_to_format):\n        return\n\n    # .coveragerc lists several regex patterns to treat as nocover pragmas, and\n    # we want to find (and delete) cases where # pragma: no cover is redundant.\n    def warn(msg):\n        raise Exception(msg)\n\n    config = CoverageConfig()\n    config.from_file(os.path.join(hp.BASE_DIR, \".coveragerc\"), warn=warn, our_file=True)\n    pattern = \"|\".join(l for l in config.exclude_list if \"pragma\" not in l)\n    unused_pragma_pattern = re.compile(f\"(({pattern}).*)  # pragma: no (branch|cover)\")\n    last_header_line = HEADER.splitlines()[-1].rstrip()\n\n    for p in paths_to_format:\n        lines = []\n        with open(p, encoding=\"utf-8\") as fp:\n            shebang = None\n            first = True\n            in_header = True\n            for l in fp:\n                if first:\n                    first = False\n                    if l[:2] == \"#!\":\n                        shebang = l\n                        continue\n                elif in_header and l.rstrip() == last_header_line:\n                    in_header = False\n                    lines = []\n                else:\n                    lines.append(unused_pragma_pattern.sub(r\"\\1\", l))\n\n        source = \"\".join(lines).strip()\n        with open(p, \"w\", encoding=\"utf-8\") as fp:\n            if shebang is not None:\n                fp.write(shebang)\n                fp.write(\"\\n\")\n            fp.write(HEADER)\n            if source:\n                fp.write(\"\\n\\n\")\n                fp.write(source)\n            fp.write(\"\\n\")\n\n    codespell(\"--write-changes\", *paths_to_format, *doc_paths_to_format)\n    pip_tool(\"ruff\", \"check\", \"--fix-only\", \".\")\n    pip_tool(\"shed\", \"--py310-plus\", *paths_to_format, *doc_paths_to_format)\n\n    for p in doc_paths_to_format:\n        remove_consecutive_newlines_in_rst(p)\n\n\nVALID_STARTS = (HEADER.split()[0], \"#!/usr/bin/env python\")\n\n\n@task()\ndef check_format():\n    format()\n    n = max(map(len, VALID_STARTS))\n    bad = False\n    for p in tools.all_files():\n        if p.suffix != \".py\":\n            continue\n        with open(p, encoding=\"utf-8\") as fp:\n            start = fp.read(n)\n            if not any(start.startswith(s) for s in VALID_STARTS):\n                print(f\"{p} has incorrect start {start!r}\", file=sys.stderr)\n                bad = True\n    assert not bad\n    try:\n        check_not_changed()\n    except Exception:\n        box_width = 50\n        inner_width = box_width - 2\n        content_width = inner_width - 2\n        msg1 = \"Note: code differed after formatting.\"\n        msg2 = \"To fix this, run:\"\n        msg3 = \"    ./build.sh format\"\n\n        lines = [\n            \"\",\n            \"    \" + \"*\" * box_width,\n            \"    *\" + \" \" * inner_width + \"*\",\n            \"    *  \" + msg1 + \" \" * (content_width - len(msg1)) + \"*\",\n            \"    *\" + \" \" * inner_width + \"*\",\n            \"    *  \" + msg2 + \" \" * (content_width - len(msg2)) + \"*\",\n            \"    *\" + \" \" * inner_width + \"*\",\n            \"    *  \" + msg3 + \" \" * (content_width - len(msg3)) + \"*\",\n            \"    *\" + \" \" * inner_width + \"*\",\n            \"    \" + \"*\" * box_width,\n            \"\",\n        ]\n        print(\"\\n\".join(lines), file=sys.stderr)\n        raise\n\n\ndef check_not_changed():\n    subprocess.check_call([\"git\", \"diff\", \"--exit-code\"])\n\n\n@task()\ndef compile_requirements(*, upgrade=False):\n    if upgrade:\n        extra = [\"--upgrade\", \"--rebuild\"]\n    else:\n        extra = []\n\n    for f in Path(\"requirements\").glob(\"*.in\"):\n        out_file = f.with_suffix(\".txt\")\n        pip_tool(\n            \"pip-compile\",\n            \"--allow-unsafe\",  # future default, not actually unsafe\n            \"--resolver=backtracking\",  # new pip resolver, default in pip-compile 7+\n            *extra,\n            str(f),\n            \"hypothesis-python/pyproject.toml\",\n            \"--output-file\",\n            str(out_file),\n            cwd=tools.ROOT,\n            env={\n                \"CUSTOM_COMPILE_COMMAND\": \"./build.sh upgrade-requirements\",\n                **os.environ,\n            },\n        )\n        # Check that we haven't added anything to output files without adding to inputs\n        out_pkgs = out_file.read_text(encoding=\"utf-8\")\n        for p in f.read_text(encoding=\"utf-8\").splitlines():\n            p = p.lower().replace(\"_\", \"-\")\n            if re.fullmatch(r\"[a-z-]+\", p):\n                assert p + \"==\" in out_pkgs, f\"Package `{p}` deleted from {out_file}\"\n        out_file.write_text(out_pkgs.replace(f\"{tools.ROOT}/\", \"\"))\n\n\ndef update_python_versions():\n    install.ensure_python(PYTHONS[ci_version])\n    where = os.path.expanduser(\"~/.cache/hypothesis-build-runtimes/pyenv/\")\n    subprocess.run(\n        \"git fetch && git reset --hard origin/master\",\n        cwd=where,\n        shell=True,\n        capture_output=True,\n    )\n    cmd = \"bin/pyenv install --list\"\n    result = subprocess.run(\n        cmd, shell=True, stdout=subprocess.PIPE, cwd=where\n    ).stdout.decode()\n    # pyenv reports available versions in chronological order, so we keep the newest\n    # *unless* our current ends with a digit (is stable) and the candidate does not.\n    # (plus some special cases for the `t` suffix for free-threading builds)\n    stable = re.compile(r\".*3\\.\\d+.\\d+t?$\")\n    min_minor_version = re.search(\n        r'requires-python = \">= ?3.(\\d+)\"',\n        Path(\"hypothesis-python/pyproject.toml\").read_text(encoding=\"utf-8\"),\n    ).group(1)\n    best = {}\n    for line in map(str.strip, result.splitlines()):\n        if m := re.match(r\"(?:pypy)?3\\.(?:9|\\d\\dt?)\", line):\n            key = m.group()\n            curr = best.get(key, line)\n            if (\n                (stable.match(line) or not stable.match(curr))\n                and not (line.endswith(\"-dev\") and not curr.endswith(\"-dev\"))\n                and int(key.split(\".\")[-1].rstrip(\"t\")) >= int(min_minor_version)\n                and key.endswith(\"t\") == line.endswith((\"t\", \"t-dev\"))\n            ):\n                best[key] = line\n\n    if best == PYTHONS:\n        return\n\n    # Write the new mapping back to this file\n    thisfile = pathlib.Path(__file__)\n    before = thisfile.read_text(encoding=\"utf-8\")\n    after = re.sub(r\"\\nPYTHONS = \\{[^{}]+\\}\", f\"\\nPYTHONS = {best}\", before)\n    thisfile.write_text(after, encoding=\"utf-8\")\n    pip_tool(\"shed\", str(thisfile))\n\n    # Automatically sync ci_version with the version in build.sh\n    build_sh = tools.ROOT / \"build.sh\"\n    sh_before = build_sh.read_text(encoding=\"utf-8\")\n    sh_after = re.sub(r\"3\\.\\d\\d?\\.\\d\\d?\", best[ci_version], sh_before)\n    if sh_before != sh_after:\n        build_sh.unlink()  # so bash doesn't reload a modified file\n        build_sh.write_text(sh_after, encoding=\"utf-8\")\n        build_sh.chmod(0o755)\n\n\nDJANGO_VERSIONS = {\n    \"4.2\": \"4.2.29\",\n    \"5.2\": \"5.2.12\",\n    \"6.0\": \"6.0.3\",\n}\n\n\ndef update_django_versions():\n    # https://endoflife.date/django makes it easier to track these\n    releases = requests.get(\"https://endoflife.date/api/django.json\").json()\n    versions = {r[\"cycle\"]: r[\"latest\"] for r in releases[::-1] if TODAY <= r[\"eol\"]}\n\n    if versions == DJANGO_VERSIONS:\n        return\n\n    # Write the new mapping back to this file\n    thisfile = pathlib.Path(__file__)\n    before = thisfile.read_text(encoding=\"utf-8\")\n    after = re.sub(\n        r\"DJANGO_VERSIONS = \\{[^{}]+\\}\",\n        \"DJANGO_VERSIONS = \" + repr(versions).replace(\"}\", \",}\"),\n        before,\n    )\n    thisfile.write_text(after, encoding=\"utf-8\")\n    pip_tool(\"shed\", str(thisfile))\n\n    # Update the minimum version in pyproject.toml\n    pyproject_toml = hp.BASE_DIR / \"pyproject.toml\"\n    content = re.sub(\n        r\"django>=\\d+\\.\\d+\",\n        f\"django>={min(versions, key=float)}\",\n        pyproject_toml.read_text(encoding=\"utf-8\"),\n    )\n    pyproject_toml.write_text(content, encoding=\"utf-8\")\n\n    # Automatically sync ci_version with the version in build.sh\n    tox_ini = hp.BASE_DIR / \"tox.ini\"\n    content = tox_ini.read_text(encoding=\"utf-8\")\n    print(versions)\n    for short, full in versions.items():\n        content = re.sub(\n            rf\"django=={short}(\\.\\d+)?\",\n            rf\"django=={full}\",\n            content,\n        )\n    tox_ini.write_text(content, encoding=\"utf-8\")\n\n\ndef update_pyodide_versions():\n\n    def version_tuple(v: str) -> tuple[int, int, int]:\n        return tuple(int(x) for x in v.split(\".\"))  # type: ignore\n\n    vers_re = r\"(\\d+\\.\\d+\\.\\d+)\"\n    all_pyodide_build_versions = re.findall(\n        f\"pyodide_build-{vers_re}-py3-none-any.whl\",  # excludes pre-releases\n        requests.get(\"https://pypi.org/simple/pyodide-build/\").text,\n    )\n    pyodide_build_version = max(\n        # Don't just pick the most recent version; find the highest stable version.\n        set(all_pyodide_build_versions),\n        key=version_tuple,\n    )\n\n    cross_build_environments_url = \"https://raw.githubusercontent.com/pyodide/pyodide/refs/heads/main/pyodide-cross-build-environments.json\"\n    cross_build_environments_data = requests.get(cross_build_environments_url).json()\n\n    # Find the latest stable release for the Pyodide runtime/xbuildenv that is compatible\n    # with the pyodide-build version we found\n    stable_releases = [\n        release\n        for release in cross_build_environments_data[\"releases\"].values()\n        if re.fullmatch(vers_re, release[\"version\"])\n    ]\n\n    compatible_releases = []\n    for release in stable_releases:  # sufficiently large values\n        min_build_version = release.get(\"min_pyodide_build_version\", \"0.0.0\")\n        max_build_version = release.get(\"max_pyodide_build_version\", \"999.999.999\")\n\n        # Perform version comparisons to avoid getting an incompatible pyodide-build version\n        # with the Pyodide runtime\n        if (\n            version_tuple(min_build_version)\n            <= version_tuple(pyodide_build_version)\n            <= version_tuple(max_build_version)\n        ):\n            compatible_releases.append(release)\n\n    if not compatible_releases:\n        raise RuntimeError(\n            f\"No compatible Pyodide release found for pyodide-build {pyodide_build_version}\"\n        )\n\n    pyodide_release = max(\n        compatible_releases,\n        key=lambda release: version_tuple(release[\"version\"]),\n    )\n\n    pyodide_version = pyodide_release[\"version\"]\n    python_version = pyodide_release[\"python_version\"]\n\n    ci_file = tools.ROOT / \".github/workflows/main.yml\"\n    config = ci_file.read_text(encoding=\"utf-8\")\n    for name, var in [\n        (\"PYODIDE\", pyodide_version),\n        (\"PYODIDE_BUILD\", pyodide_build_version),\n        (\"PYTHON\", python_version),\n    ]:\n        config = re.sub(f\"{name}_VERSION: {vers_re}\", f\"{name}_VERSION: {var}\", config)\n    ci_file.write_text(config, encoding=\"utf-8\")\n\n\ndef update_vendored_files():\n    vendor = pathlib.Path(hp.PYTHON_SRC) / \"hypothesis\" / \"vendor\"\n\n    # Turns out that as well as adding new gTLDs, IANA can *terminate* old ones\n    url = \"http://data.iana.org/TLD/tlds-alpha-by-domain.txt\"\n    fname = vendor / url.split(\"/\")[-1]\n    new = requests.get(url).content\n    # If only the timestamp in the header comment has changed, skip the update.\n    if fname.read_bytes().splitlines()[1:] != new.splitlines()[1:]:\n        fname.write_bytes(new)\n\n    # Always require the most recent version of tzdata - we don't need to worry about\n    # pre-releases because tzdata is a 'latest data' package  (unlike pyodide-build).\n    # Our crosshair extra is research-grade, so we require latest versions there too.\n    pyproject_toml = pathlib.Path(hp.BASE_DIR, \"pyproject.toml\")\n    new = pyproject_toml.read_text(encoding=\"utf-8\")\n    for pkgname in (\"tzdata\", \"crosshair-tool\", \"hypothesis-crosshair\"):\n        pkg_url = f\"https://pypi.org/pypi/{pkgname}/json\"\n        pkg_version = requests.get(pkg_url).json()[\"info\"][\"version\"]\n        new = re.sub(rf\"{pkgname}>=([a-z0-9.]+)\", f\"{pkgname}>={pkg_version}\", new)\n    pyproject_toml.write_text(new, encoding=\"utf-8\")\n\n\ndef has_diff(file_or_directory):\n    diff = [\"git\", \"diff\", \"--no-patch\", \"--exit-code\", \"--\", file_or_directory]\n    return subprocess.call(diff) != 0\n\n\n@task()\ndef upgrade_requirements():\n    update_vendored_files()\n    compile_requirements(upgrade=True)\n    subprocess.call([\"./build.sh\", \"format\"], cwd=tools.ROOT)  # exits 1 if changed\n    if has_diff(hp.PYTHON_SRC) and not os.path.isfile(hp.RELEASE_FILE):\n        msg = hp.get_autoupdate_message(domainlist_changed=has_diff(hp.DOMAINS_LIST))\n        with open(hp.RELEASE_FILE, mode=\"w\", encoding=\"utf-8\") as f:\n            f.write(f\"RELEASE_TYPE: patch\\n\\n{msg}\")\n    update_python_versions()\n    update_pyodide_versions()\n    update_django_versions()\n    subprocess.call([\"git\", \"add\", \".\"], cwd=tools.ROOT)\n\n\n@task()\ndef check_requirements():\n    compile_requirements(upgrade=False)\n\n\n@task(if_changed=hp.HYPOTHESIS_PYTHON)\ndef documentation():\n    try:\n        if hp.has_release():\n            hp.update_changelog_and_version()\n        hp.build_docs()\n    finally:\n        subprocess.check_call(\n            [\"git\", \"checkout\", \"docs/changelog.rst\", \"src/hypothesis/version.py\"],\n            cwd=hp.HYPOTHESIS_PYTHON,\n        )\n\n\n@task()\ndef website():\n    subprocess.call([sys.executable, \"-m\", \"pelican\"], cwd=tools.ROOT / \"website\")\n\n\n@task()\ndef live_website():\n    subprocess.call(\n        [sys.executable, \"-m\", \"pelican\", \"--autoreload\", \"--listen\"],\n        cwd=tools.ROOT / \"website\",\n    )\n\n\n@task()\ndef live_docs():\n    pip_tool(\n        \"sphinx-autobuild\",\n        \"docs\",\n        \"docs/_build/html\",\n        \"--watch\",\n        \"src\",\n        \"--open-browser\",\n        cwd=hp.HYPOTHESIS_PYTHON,\n    )\n\n\ndef run_tox(task, version, *args):\n    python = install.python_executable(version)\n\n    # Create a version of the name that tox will pick up for the correct\n    # interpreter alias.\n    linked_version = os.path.basename(python) + ALIASES[version]\n    try:\n        os.symlink(python, linked_version)\n    except FileExistsError:\n        pass\n\n    env = dict(os.environ)\n    python = install.python_executable(version)\n\n    env[\"PATH\"] = os.path.dirname(python) + \":\" + env[\"PATH\"]\n    # Set environment variable for tox to use in basepython substitution\n    if version.startswith(\"pypy\"):\n        # For PyPy, use the version name from e.g. \"pypy3.11-7.3.20\"\n        # to match tox's environment name inference.\n        env[\"TOX_PYTHON_VERSION\"] = version.split(\"-\")[0]  # \"pypy3.11\"\n    else:\n        env[\"TOX_PYTHON_VERSION\"] = ALIASES[version]  # \"python3.12\"\n    print(env[\"PATH\"])\n\n    pip_tool(\"tox\", \"-e\", task, *args, env=env, cwd=hp.HYPOTHESIS_PYTHON)\n\n\n# update_python_versions(), above, keeps the contents of this dict up to date.\n# When a version is added or removed, manually update the env lists in tox.ini and\n# workflows/main.yml, and the `Programming Language ::` specifiers in pyproject.toml\nPYTHONS = {\n    \"3.10\": \"3.10.20\",\n    \"3.11\": \"3.11.15\",\n    \"3.12\": \"3.12.13\",\n    \"3.13\": \"3.13.12\",\n    \"3.13t\": \"3.13t-dev\",\n    \"3.14\": \"3.14.3\",\n    \"3.14t\": \"3.14t-dev\",\n    \"3.15\": \"3.15.0a7\",\n    \"3.15t\": \"3.15t-dev\",\n    \"pypy3.10\": \"pypy3.10-7.3.19\",\n    \"pypy3.11\": \"pypy3.11-7.3.20\",\n}\nci_version = \"3.14\"  # Keep this in sync with GH Actions main.yml and .readthedocs.yml\n\npython_tests = task(\n    if_changed=(\n        hp.PYTHON_SRC,\n        hp.PYTHON_TESTS,\n        hp.HYPOTHESIS_PYTHON / \"pyproject.toml\",\n        tools.ROOT / \"tooling\",\n        hp.HYPOTHESIS_PYTHON / \"scripts\",\n    )\n)\n\n\n# ALIASES are the executable names for each Python version\nALIASES = {}\nfor key, version in PYTHONS.items():\n    if key.startswith(\"pypy\"):\n        ALIASES[version] = \"pypy3\"\n        name = key.replace(\".\", \"\")\n    else:\n        ALIASES[version] = f\"python{key}\"\n        name = f\"py3{key[2:]}\"\n    TASKS[f\"check-{name}\"] = python_tests(\n        lambda n=f\"{name}-full\", v=version, *args: run_tox(n, v, *args)\n    )\n    for subtask in (\n        \"brief\",\n        \"full\",\n        \"cover\",\n        \"rest\",\n        \"nocover\",\n        \"niche\",\n        \"custom\",\n    ):\n        TASKS[f\"check-{name}-{subtask}\"] = python_tests(\n            lambda n=f\"{name}-{subtask}\", v=version, *args: run_tox(n, v, *args)\n        )\n\n\n@python_tests\ndef check_py310_pyjion(*args):\n    run_tox(\"py310-pyjion\", PYTHONS[\"3.10\"], *args)\n\n\n@task()\ndef tox(*args):\n    if len(args) < 2:\n        print(\"Usage: ./build.sh tox TOX_ENV PY_VERSION [tox args]\")\n        sys.exit(1)\n    run_tox(*args)\n\n\ndef standard_tox_task(name, py=ci_version):\n    TASKS[\"check-\" + name] = python_tests(\n        lambda *args: run_tox(name, PYTHONS.get(py, py), *args)\n    )\n\n\nstandard_tox_task(\"py311-pytest62\", py=\"3.11\")  # hits \"ast.Str is deprecated\" in 3.12+\nstandard_tox_task(\"pytest74\")\nstandard_tox_task(\"pytest84\")\nstandard_tox_task(\"pytest9\")\n\ndj_version = max(ci_version, \"3.12\")\nfor n in DJANGO_VERSIONS:\n    standard_tox_task(f\"django{n.replace('.', '')}\", py=dj_version)\n# we also test no-contrib on the latest django version\nstandard_tox_task(\"django-nocontrib\", py=dj_version)\n\n# test each pandas version with the latest python version they support\nstandard_tox_task(\"py310-pandas11\", py=\"3.10\")\nstandard_tox_task(\"py310-pandas12\", py=\"3.10\")\nstandard_tox_task(\"py310-pandas13\", py=\"3.10\")\nstandard_tox_task(\"py310-pandas14\", py=\"3.10\")\nstandard_tox_task(\"py311-pandas15\", py=\"3.11\")\nstandard_tox_task(\"py311-pandas20\", py=\"3.11\")\nstandard_tox_task(\"py312-pandas21\", py=\"3.12\")\nstandard_tox_task(\"py313-pandas22\", py=\"3.13\")\n\nfor kind in (\"cover\", \"nocover\", \"niche\", \"custom\"):\n    standard_tox_task(f\"crosshair-{kind}\")\n\nfor kind in (\"rest\", \"nocover\"):\n    # Note, in CI these are executed on alternative platforms (e.g., windows)\n    # directly in tox (and not via build.sh)\n    standard_tox_task(f\"alt-{kind}\")\n\nstandard_tox_task(\"threading\")\nstandard_tox_task(\"py310-oldestnumpy\", py=\"3.10\")\nstandard_tox_task(\"numpy-nightly\", py=\"3.12\")\n\nstandard_tox_task(\"coverage\")\nstandard_tox_task(\"conjecture-coverage\")\n\n\n@task()\ndef check_quality(*args):\n    run_tox(\"quality\", PYTHONS[ci_version], *args)\n\n\n@task(if_changed=(hp.PYTHON_SRC, os.path.join(hp.HYPOTHESIS_PYTHON, \"examples\")))\ndef check_examples3(*args):\n    run_tox(\"examples3\", PYTHONS[ci_version], *args)\n\n\n@task()\ndef check_whole_repo_tests(*args):\n    install.ensure_shellcheck()\n    subprocess.check_call(\n        [sys.executable, \"-m\", \"pip\", \"install\", \"--upgrade\", hp.HYPOTHESIS_PYTHON]\n    )\n\n    if not args:\n        args = [\"-n\", \"auto\", tools.REPO_TESTS / \"whole_repo\"]\n    subprocess.check_call([sys.executable, \"-m\", \"pytest\", *args])\n\n\n@task()\ndef check_documentation(*args):\n    install.ensure_shellcheck()\n    subprocess.check_call(\n        [sys.executable, \"-m\", \"pip\", \"install\", \"--upgrade\", hp.HYPOTHESIS_PYTHON]\n    )\n\n    if not args:\n        args = [\"-n\", \"auto\", tools.REPO_TESTS / \"documentation\"]\n    subprocess.check_call([sys.executable, \"-m\", \"pytest\", *args])\n\n\n@task()\ndef check_types(*args):\n    install.ensure_shellcheck()\n    subprocess.check_call(\n        [sys.executable, \"-m\", \"pip\", \"install\", \"--upgrade\", hp.HYPOTHESIS_PYTHON]\n    )\n\n    if not args:\n        args = [\"-n\", \"auto\", tools.REPO_TESTS / \"types\"]\n    subprocess.check_call([sys.executable, \"-m\", \"pytest\", *args])\n\n\n@task()\ndef check_types_api(*args):\n    install.ensure_shellcheck()\n    subprocess.check_call(\n        [sys.executable, \"-m\", \"pip\", \"install\", \"--upgrade\", hp.HYPOTHESIS_PYTHON]\n    )\n\n    if not args:\n        ignore = [\"--ignore\", tools.REPO_TESTS / \"types/test_hypothesis.py\"]\n        args = [\"-n\", \"auto\", tools.REPO_TESTS / \"types\"] + ignore\n    subprocess.check_call([sys.executable, \"-m\", \"pytest\", *args])\n\n\n@task()\ndef check_types_hypothesis(*args):\n    install.ensure_shellcheck()\n    subprocess.check_call(\n        [sys.executable, \"-m\", \"pip\", \"install\", \"--upgrade\", hp.HYPOTHESIS_PYTHON]\n    )\n\n    if not args:\n        testcase = \"types/test_hypothesis.py\"\n        args = [\"-n\", \"auto\", tools.REPO_TESTS / testcase]\n    subprocess.check_call([sys.executable, \"-m\", \"pytest\", *args])\n\n\n@task()\ndef shell():\n    import IPython\n\n    IPython.start_ipython([])\n\n\n@task()\ndef python(*args):\n    os.execv(sys.executable, (sys.executable, *args))\n\n\n@task()\ndef tasks():\n    \"\"\"Print a list of all task names supported by the build system.\"\"\"\n    for task_name in sorted(TASKS.keys()):\n        print(\"    \" + task_name)\n\n\nif __name__ == \"__main__\":\n    if \"SNAKEPIT\" not in os.environ:\n        print(\n            \"This module should not be executed directly, but instead via \"\n            \"build.sh (which sets up its environment)\"\n        )\n        sys.exit(1)\n\n    if len(sys.argv) > 1:\n        task_to_run = sys.argv[1]\n        args = sys.argv[2:]\n    else:\n        task_to_run = os.environ.get(\"TASK\")\n        args = ()\n\n    if task_to_run is None:\n        print(\n            \"No task specified. Either pass the task to run as an \"\n            \"argument or as an environment variable TASK. \"\n            '(Use \"./build.sh tasks\" to list all supported task names.)'\n        )\n        sys.exit(1)\n\n    if task_to_run not in TASKS:\n        print(f\"\\nUnknown task {task_to_run!r}.  Available tasks are:\")\n        tasks()\n        sys.exit(1)\n\n    try:\n        TASKS[task_to_run](*args)\n    except subprocess.CalledProcessError as e:\n        sys.exit(e.returncode)\n"
  },
  {
    "path": "tooling/src/hypothesistooling/installers.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"Module for obtaining various versions of Python.\n\nCurrently this is a thin shim around pyenv, but it would be nice to have\nthis work on Windows as well by using Anaconda (as our build already\ndoes).\n\"\"\"\n\nimport os\nimport shutil\nimport subprocess\n\nfrom hypothesistooling import scripts\nfrom hypothesistooling.junkdrawer import once\n\nHOME = os.environ[\"HOME\"]\n\n\ndef __python_executable(version):\n    return os.path.join(scripts.SNAKEPIT, version, \"bin\", \"python\")\n\n\ndef python_executable(version):\n    ensure_python(version)\n    return __python_executable(version)\n\n\nPYTHONS = set()\n\n\ndef ensure_python(version):\n    if version in PYTHONS:\n        return\n    scripts.run_script(\"ensure-python.sh\", version)\n    target = __python_executable(version)\n    assert os.path.exists(target), target\n    PYTHONS.add(version)\n\n\nSTACK = os.path.join(HOME, \".local\", \"bin\", \"stack\")\nSHELLCHECK = shutil.which(\"shellcheck\") or os.path.join(\n    HOME, \".local\", \"bin\", \"shellcheck\"\n)\n\n\ndef ensure_stack():\n    if os.path.exists(STACK):\n        return\n    subprocess.check_call(\"mkdir -p ~/.local/bin\", shell=True)\n    # if you're on macos, this will error with \"--wildcards is not supported\"\n    # or similar. You should put shellcheck on your PATH with your package\n    # manager of choice; eg `brew install shellcheck`.\n    subprocess.check_call(\n        \"curl -L https://www.stackage.org/stack/linux-x86_64 \"\n        \"| tar xz --wildcards --strip-components=1 -C $HOME\"\n        \"/.local/bin '*/stack'\",\n        shell=True,\n    )\n\n\n@once\ndef update_stack():\n    ensure_stack()\n    subprocess.check_call([STACK, \"update\"])\n\n\n@once\ndef ensure_shellcheck():\n    if os.path.exists(SHELLCHECK):\n        return\n    update_stack()\n    subprocess.check_call([STACK, \"install\", \"ShellCheck\"])\n"
  },
  {
    "path": "tooling/src/hypothesistooling/junkdrawer.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"Dumping ground module for things that don't have anywhere better to go.\n\nSee https://twitter.com/betsythemuffin/status/1003313844108824584\n\"\"\"\n\nimport ast\nimport os\nfrom contextlib import contextmanager\n\n\n@contextmanager\ndef in_dir(d):\n    prev = os.getcwd()\n    try:\n        os.chdir(d)\n        yield\n    finally:\n        os.chdir(prev)\n\n\ndef once(fn):\n    def accept():\n        if accept.has_been_called:\n            return\n        fn()\n        accept.has_been_called = True\n\n    accept.has_been_called = False\n    accept.__name__ = fn.__name__\n    return accept\n\n\ndef unlink_if_present(path):\n    try:\n        os.unlink(path)\n    except FileNotFoundError:\n        pass\n\n\ndef unquote_string(s):\n    return ast.literal_eval(s)\n"
  },
  {
    "path": "tooling/src/hypothesistooling/projects/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "tooling/src/hypothesistooling/projects/hypothesispython.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport json\nimport os\nimport re\nimport shutil\nimport subprocess\nimport sys\n\nimport requests\nimport tomli\n\nimport hypothesistooling as tools\nfrom hypothesistooling import releasemanagement as rm\n\nPACKAGE_NAME = \"hypothesis-python\"\n\nHYPOTHESIS_PYTHON = tools.ROOT / PACKAGE_NAME\nPYTHON_TAG_PREFIX = \"hypothesis-python-\"\n\n\nBASE_DIR = HYPOTHESIS_PYTHON\n\nPYTHON_SRC = HYPOTHESIS_PYTHON / \"src\"\nPYTHON_TESTS = HYPOTHESIS_PYTHON / \"tests\"\nDOMAINS_LIST = PYTHON_SRC / \"hypothesis\" / \"vendor\" / \"tlds-alpha-by-domain.txt\"\n\nRELEASE_FILE = HYPOTHESIS_PYTHON / \"RELEASE.rst\"\nRELEASE_SAMPLE_FILE = HYPOTHESIS_PYTHON / \"RELEASE-sample.rst\"\n\nassert PYTHON_SRC.exists()\n\n\n__version__ = None\n__version_info__ = None\n\nVERSION_FILE = os.path.join(PYTHON_SRC, \"hypothesis/version.py\")\n\nwith open(VERSION_FILE, encoding=\"utf-8\") as fp:\n    exec(fp.read())\n\nassert __version__ is not None\nassert __version_info__ is not None\n\n\ndef has_release():\n    return RELEASE_FILE.exists()\n\n\ndef has_release_sample():\n    return RELEASE_SAMPLE_FILE.exists()\n\n\ndef parse_release_file():\n    return rm.parse_release_file(RELEASE_FILE)\n\n\ndef has_source_changes():\n    return tools.has_changes([PYTHON_SRC])\n\n\ndef build_docs(*, builder=\"html\", only=(), to=None):\n    # See https://www.sphinx-doc.org/en/stable/man/sphinx-build.html\n    tools.scripts.pip_tool(\n        \"sphinx-build\",\n        \"--fail-on-warning\",\n        \"--show-traceback\",\n        \"--fresh-env\",\n        \"--builder\",\n        builder,\n        \"docs\",\n        \"docs/_build/\" + (builder if to is None else to),\n        *only,\n        cwd=HYPOTHESIS_PYTHON,\n    )\n\n\nCHANGELOG_ANCHOR = re.compile(r\"^\\.\\. _v\\d+\\.\\d+\\.\\d+:$\", flags=re.MULTILINE)\nCHANGELOG_BORDER = re.compile(r\"^-+$\", flags=re.MULTILINE)\nCHANGELOG_HEADER = re.compile(\n    r\"^\\d+\\.\\d+\\.\\d+ - \\d\\d\\d\\d-\\d\\d-\\d\\d$\", flags=re.MULTILINE\n)\n\n\ndef update_changelog_and_version():\n    global __version_info__\n    global __version__\n\n    contents = changelog()\n    assert \"\\r\" not in contents\n    lines = contents.split(\"\\n\")\n    for i, l in enumerate(lines):\n        if CHANGELOG_ANCHOR.match(l):\n            assert CHANGELOG_BORDER.match(lines[i + 2]), repr(lines[i + 2])\n            assert CHANGELOG_HEADER.match(lines[i + 3]), repr(lines[i + 3])\n            assert CHANGELOG_BORDER.match(lines[i + 4]), repr(lines[i + 4])\n            assert lines[i + 3].startswith(\n                __version__\n            ), f\"{__version__=}   {lines[i + 3]=}\"\n            beginning = \"\\n\".join(lines[:i])\n            rest = \"\\n\".join(lines[i:])\n            assert f\"{beginning}\\n{rest}\" == contents\n            break\n\n    release_type, release_contents = parse_release_file()\n\n    new_version_string, new_version_info = rm.bump_version_info(\n        __version_info__, release_type\n    )\n\n    __version_info__ = new_version_info\n    __version__ = new_version_string\n\n    if release_type == \"major\":\n        major, _, _ = __version_info__\n        old = f\"Hypothesis {major - 1}.x\"\n        beginning = beginning.replace(old, f\"Hypothesis {major}.x\")\n        rest = \"\\n\".join([old, len(old) * \"=\", \"\", rest])\n\n    rm.replace_assignment(VERSION_FILE, \"__version_info__\", repr(new_version_info))\n\n    heading_for_new_version = f\"{new_version_string} - {rm.release_date_string()}\"\n    border_for_new_version = \"-\" * len(heading_for_new_version)\n\n    new_changelog_parts = [\n        beginning.strip(),\n        \"\",\n        f\".. _v{new_version_string}:\",\n        \"\",\n        border_for_new_version,\n        heading_for_new_version,\n        border_for_new_version,\n        \"\",\n        release_contents,\n        \"\",\n        rest,\n    ]\n\n    CHANGELOG_FILE.write_text(\"\\n\".join(new_changelog_parts), encoding=\"utf-8\")\n\n    # Replace the `since=\"RELEASEDAY\"` argument to `note_deprecation`\n    # with today's date, to record it for future reference.\n    before = 'since=\"RELEASEDAY\"'\n    after = before.replace(\"RELEASEDAY\", rm.release_date_string())\n    for root, _, files in os.walk(PYTHON_SRC):\n        for fname in (os.path.join(root, f) for f in files if f.endswith(\".py\")):\n            with open(fname, encoding=\"utf-8\") as f:\n                contents = f.read()\n            if before in contents:\n                with open(fname, \"w\", encoding=\"utf-8\") as f:\n                    f.write(contents.replace(before, after))\n\n    update_pyproject_toml()\n\n\ndef update_pyproject_toml():\n    # manually write back these changes using regex instead of pulling in a\n    # toml dependency for writing. tomli doesn't support writing, and\n    # tomli-w doesn't support writing with comments.\n    toml_p = HYPOTHESIS_PYTHON / \"pyproject.toml\"\n    toml_data = tomli.loads(toml_p.read_text())\n    extras = toml_data[\"project\"][\"optional-dependencies\"]\n    extras.pop(\"all\")\n    readme = (tools.ROOT / \"README.md\").read_text()\n    content = toml_p.read_text()\n    content = re.sub(\n        r'\\[project\\.readme\\].*content-type = \"text/markdown\"',\n        f'[project.readme]\\ntext = \"\"\"{readme}\"\"\"\\ncontent-type = \"text/markdown\"',\n        content,\n        flags=re.DOTALL,\n    )\n\n    all_extras = sorted(set(sum(extras.values(), [])))\n    all_extras = json.dumps(all_extras).replace(\"\\n\", \"\\\\n\")\n    content = re.sub(\n        r\"^all = \\[.*\\]$\",\n        f\"all = {all_extras}\",\n        content,\n        flags=re.MULTILINE,\n    )\n    toml_p.write_text(content)\n\n\nCHANGELOG_FILE = HYPOTHESIS_PYTHON / \"docs\" / \"changelog.rst\"\nDIST = HYPOTHESIS_PYTHON / \"dist\"\n\n\ndef changelog():\n    return CHANGELOG_FILE.read_text(encoding=\"utf-8\")\n\n\ndef build_distribution():\n    if os.path.exists(DIST):\n        shutil.rmtree(DIST)\n    subprocess.check_output([sys.executable, \"-m\", \"build\", \"--outdir\", DIST])\n\n\ndef upload_distribution():\n    tools.assert_can_release()\n\n    subprocess.check_call(\n        [\n            sys.executable,\n            \"-m\",\n            \"twine\",\n            \"upload\",\n            \"--skip-existing\",\n            \"--username=__token__\",\n            os.path.join(DIST, \"*\"),\n        ]\n    )\n\n    # Construct plain-text + markdown version of this changelog entry,\n    # with link to canonical source.\n    build_docs(builder=\"text\", only=[\"docs/changelog.rst\"])\n    textfile = os.path.join(\n        HYPOTHESIS_PYTHON, \"docs\", \"_build\", \"text\", \"changelog.txt\"\n    )\n    with open(textfile, encoding=\"utf-8\") as f:\n        lines = f.readlines()\n    entries = [i for i, l in enumerate(lines) if CHANGELOG_HEADER.match(l)]\n    anchor = current_version().replace(\".\", \"-\")\n    changelog_body = (\n        \"\".join(lines[entries[0] + 2 : entries[1]]).strip()\n        + \"\\n\\n*[The canonical version of these notes (with links) is on readthedocs.]\"\n        f\"(https://hypothesis.readthedocs.io/en/latest/changelog.html#v{anchor})*\"\n    )\n\n    # Create a GitHub release, to trigger Zenodo DOI minting.  See\n    # https://developer.github.com/v3/repos/releases/#create-a-release\n    resp = requests.post(\n        \"https://api.github.com/repos/HypothesisWorks/hypothesis/releases\",\n        headers={\n            \"Accept\": \"application/vnd.github+json\",\n            \"Authorization\": f\"Bearer {os.environ['GH_TOKEN']}\",\n            \"X-GitHub-Api-Version\": \"2022-11-28\",\n        },\n        json={\n            \"tag_name\": tag_name(),\n            \"name\": \"Hypothesis for Python - version \" + current_version(),\n            \"body\": changelog_body,\n        },\n        timeout=120,  # seconds\n    )\n\n    # TODO: work out why this is 404'ing despite success (?!?) and fix it\n    try:\n        resp.raise_for_status()\n    except Exception:\n        import traceback\n\n        traceback.print_exc()\n\n\ndef current_version():\n    return __version__\n\n\ndef latest_version():\n    versions = []\n\n    for t in tools.tags():\n        if t.startswith(PYTHON_TAG_PREFIX):\n            t = t.removeprefix(PYTHON_TAG_PREFIX)\n        else:\n            continue\n        assert t == t.strip()\n        parts = t.split(\".\")\n        assert len(parts) == 3\n        v = tuple(map(int, parts))\n        versions.append((v, t))\n\n    _, latest = max(versions)\n\n    return latest\n\n\ndef tag_name():\n    return PYTHON_TAG_PREFIX + __version__\n\n\ndef get_autoupdate_message(domainlist_changed):\n    if domainlist_changed:\n        return (\n            \"This patch updates our vendored `list of top-level domains \"\n            \"<https://www.iana.org/domains/root/db>`__,\\nwhich is used by the \"\n            \"provisional :func:`~hypothesis.provisional.domains` strategy.\\n\"\n        )\n    return (\n        \"This patch updates our autoformatting tools, \"\n        \"improving our code style without any API changes.\"\n    )\n"
  },
  {
    "path": "tooling/src/hypothesistooling/releasemanagement.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\n\"\"\"Helpful common code for release management tasks that is shared across\nmultiple projects.\n\nNote that most code in here is brittle and specific to our build and\nprobably makes all sorts of undocumented assumptions, even as it looks\nlike a nice tidy reusable set of functionality.\n\"\"\"\n\nimport re\nfrom datetime import datetime, timezone\n\nimport hypothesistooling as tools\n\n__RELEASE_DATE_STRING = None\n\n\ndef release_date_string():\n    \"\"\"Returns a date string that represents what should be considered \"today\"\n    for the purposes of releasing, and ensure that we don't change part way\n    through a release.\"\"\"\n    global __RELEASE_DATE_STRING\n    if __RELEASE_DATE_STRING is None:\n        __RELEASE_DATE_STRING = datetime.now(timezone.utc).strftime(\"%Y-%m-%d\")\n    return __RELEASE_DATE_STRING\n\n\ndef assignment_matcher(name):\n    \"\"\"\n    Matches a single line of the form (some space)name = (some value). e.g.\n    \"  foo = 1\".\n    The whole line up to the assigned value is the first matching group,\n    the rest of the line is the second matching group.\n    i.e. group 1 is the assignment, group 2 is the value. In the above\n    example group 1 would be \"  foo = \" and group 2 would be \"1\"\n    \"\"\"\n    return re.compile(rf\"\\A(\\s*{re.escape(name)}\\s*=\\s*)(.+)\\Z\")\n\n\ndef extract_assignment_from_string(contents, name):\n    lines = contents.split(\"\\n\")\n\n    matcher = assignment_matcher(name)\n\n    for l in lines:\n        match = matcher.match(l)\n        if match is not None:\n            return match[2].strip()\n\n    raise ValueError(f\"Key {name} not found in {contents}\")\n\n\ndef extract_assignment(filename, name):\n    with open(filename, encoding=\"utf-8\") as i:\n        return extract_assignment_from_string(i.read(), name)\n\n\ndef replace_assignment_in_string(contents, name, value):\n    lines = contents.split(\"\\n\")\n\n    matcher = assignment_matcher(name)\n\n    count = 0\n\n    for i, l in enumerate(lines):\n        match = matcher.match(l)\n        if match is not None:\n            count += 1\n            lines[i] = match[1] + value\n\n    if count == 0:\n        raise ValueError(f\"Key {name} not found in {contents}\")\n    if count > 1:\n        raise ValueError(f\"Key {name} found {count} times in {contents}\")\n\n    return \"\\n\".join(lines)\n\n\ndef replace_assignment(filename, name, value):\n    \"\"\"Replaces a single assignment of the form key = value in a file with a\n    new value, attempting to preserve the existing format.\n\n    This is fairly fragile - in particular it knows nothing about\n    the file format. The existing value is simply the rest of the line after\n    the last space after the equals.\n    \"\"\"\n    with open(filename, encoding=\"utf-8\") as f:\n        contents = f.read()\n    result = replace_assignment_in_string(contents, name, value)\n    with open(filename, \"w\", encoding=\"utf-8\") as f:\n        f.write(result)\n\n\nRELEASE_TYPE = re.compile(r\"^RELEASE_TYPE: +(major|minor|patch)\")\n\n\nMAJOR = \"major\"\nMINOR = \"minor\"\nPATCH = \"patch\"\n\n\nVALID_RELEASE_TYPES = (MAJOR, MINOR, PATCH)\n\n\ndef parse_release_file(filename):\n    with open(filename, encoding=\"utf-8\") as i:\n        return parse_release_file_contents(i.read(), filename)\n\n\ndef parse_release_file_contents(release_contents, filename):\n    release_lines = [l.rstrip() for l in release_contents.split(\"\\n\")]\n\n    m = RELEASE_TYPE.match(release_lines[0])\n    if m is not None:\n        release_type = m.group(1)\n        if release_type not in VALID_RELEASE_TYPES:\n            raise ValueError(f\"Unrecognised release type {release_type!r}\")\n        del release_lines[0]\n        release_contents = \"\\n\".join(release_lines).strip()\n    else:\n        raise ValueError(\n            f\"{filename} does not start by specifying release type. The first \"\n            \"line of the file should be RELEASE_TYPE: followed by one of \"\n            \"major, minor, or patch, to specify the type of release that \"\n            \"this is (i.e. which version number to increment). Instead the \"\n            f\"first line was {release_lines[0]!r}\"\n        )\n\n    return release_type, release_contents\n\n\ndef bump_version_info(version_info, release_type):\n    new_version = list(version_info)\n    bump = VALID_RELEASE_TYPES.index(release_type)\n    new_version[bump] += 1\n    for i in range(bump + 1, len(new_version)):\n        new_version[i] = 0\n    new_version = tuple(new_version)\n    new_version_string = \".\".join(map(str, new_version))\n    return new_version_string, new_version\n\n\ndef update_markdown_changelog(changelog, name, version, entry):\n    with open(changelog, encoding=\"utf-8\") as f:\n        prev_contents = f.read()\n\n    title = f\"# {name} {version} ({release_date_string()})\\n\\n\"\n\n    with open(changelog, \"w\", encoding=\"utf-8\") as f:\n        f.write(title)\n        f.write(entry.strip())\n        f.write(\"\\n\\n\")\n        f.write(prev_contents)\n\n\ndef parse_version(version):\n    return tuple(map(int, version.split(\".\")))\n\n\ndef commit_pending_release(project):\n    \"\"\"Create a commit with the new release.\"\"\"\n    tools.git(\"rm\", project.RELEASE_FILE)\n    tools.git(\"add\", \"-u\", project.BASE_DIR)\n\n    tools.git(\n        \"commit\",\n        \"-m\",\n        f\"Bump {project.PACKAGE_NAME} version to {project.current_version()} \"\n        \"and update changelog\\n\\n[skip ci]\",\n    )\n"
  },
  {
    "path": "tooling/src/hypothesistooling/scripts.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport re\nimport shlex\nimport subprocess\nimport sys\n\nfrom hypothesistooling import ROOT\n\n\ndef print_command(command, args):\n    args = list(args)\n    ranges = []\n    for i, v in enumerate(args):\n        if os.path.exists(v):\n            if not ranges or ranges[-1][-1] < i - 1:\n                ranges.append([i, i])\n            elif ranges[-1][-1] + 1 == i:\n                ranges[-1][-1] += 1\n    for i, j in ranges:\n        if j > i:\n            args[i] = \"...\"\n            for k in range(i + 1, j + 1):\n                args[k] = None\n    args = [v for v in args if v is not None]\n    print(command, *map(shlex.quote, args))\n\n\ndef run_script(script, *args, **kwargs):\n    print_command(script, args)\n    return subprocess.check_call([os.path.join(SCRIPTS, script), *args], **kwargs)\n\n\nSCRIPTS = ROOT / \"tooling\" / \"scripts\"\nCOMMON = SCRIPTS / \"common.sh\"\n\n\ndef __calc_script_variables():\n    exports = re.compile(r\"^export ([A-Z_]+)(=|$)\", flags=re.MULTILINE)\n\n    common = COMMON.read_text(encoding=\"utf-8\")\n\n    for name, _ in exports.findall(common):\n        globals()[name] = os.environ[name]\n\n\ntry:\n    __calc_script_variables()\nexcept Exception:\n    pass\n\n\ndef tool_path(name):\n    return os.path.join(os.path.dirname(sys.executable), name)\n\n\ndef pip_tool(name, *args, **kwargs):\n    args = [str(arg) for arg in args]\n    print_command(name, args)\n    r = subprocess.call([tool_path(name), *args], **kwargs)\n\n    if r != 0:\n        sys.exit(r)\n"
  },
  {
    "path": "website/archive-redirect.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"refresh\" content=\"0; url=/articles/\">\n    <link rel=\"canonical\" href=\"/articles/\">\n    <title>Redirecting to Articles</title>\n</head>\n<body>\n    <p>Redirecting to <a href=\"/articles/\">articles</a>...</p>\n    <script>window.location.href = \"/articles/\";</script>\n</body>\n</html>\n"
  },
  {
    "path": "website/content/2016-04-15-economics-of-software-correctness.md",
    "content": "---\ntags: writing-good-software, non-technical\ndate: 2016-04-15 15:00\ntitle: The Economics of Software Correctness\nauthor: drmaciver\n---\n\nYou have probably never written a significant piece of correct software.\n\nThat's not a value judgement. It's certainly not a criticism of your competence. I can say with almost complete confidence that every non-trivial piece of software I have written contains at least one bug. You *might* have written small libraries that are essentially bug free, but the chance that you have written a non-trivial bug free program is tantamount to zero.\n\nI don't even mean this in some pedantic academic sense. I'm talking about behaviour where if someone spotted it and pointed it out to you you would probably admit that it's a bug. It might even be a bug that you cared about.\n\nWhy is this?\n\n<!--more-->\n\nWell, lets start with why it's not: It's not because we don't know how to write correct software. We've known how to write software that is more or less correct (or at least vastly closer to correct than the norm) for a while now. If you <a href=\"http://www.fastcompany.com/28121/they-write-right-stuff\">look at the NASA development process</a> they're pretty much doing it.\n\nAlso, if you look at the NASA development process you will probably conclude that we can't do that. It's orders of magnitude more work than we ever put into software development. It's process heavy, laborious, and does not adapt well to changing requirements or tight deadlines.\n\nThe problem is not that we don't know how to write correct software. The problem is that correct software is too expensive.\n\nAnd \"too expensive\" doesn't mean \"It will knock 10% off our profit margins, we couldn't possibly do that\". It means \"if our software cost this much to make, nobody would be willing to pay a price we could afford to sell it at\". It may also mean \"If our software took this long to make then someone else will release a competing product two years earlier than us, everyone will use that, and when ours comes along nobody will be interested in using it\".\n\n(\"sell\" and \"release\" here can mean a variety of things. It can mean that terribly unfashionable behaviour where people give you money and you give them a license to your software. It can mean subscriptions. It can mean ad space. It can even mean paid work. I'm just going to keep saying sell and release).\n\nNASA can do it because when they introduce a software bug they potentially lose some combination of billions of dollars, years of work and many lives. When that's the cost of a bug, spending that much time and money on correctness seems like a great deal. Safety critical industries like medical technology and aviation can do it for similar reasons\n([buggy medical technology kills people](https://en.wikipedia.org/wiki/Therac-25) and [you don't want your engines power cycling themselves midflight](http://www.engadget.com/2015/05/01/boeing-787-dreamliner-software-bug/)).\n\nThe rest of us aren't writing safety critical software, and as a result people aren't willing to pay for that level of correctness.\n\nSo the result is that we write software with bugs in it, and we adopt a much cheaper software testing methodology: We ship it and see what happens. Inevitably some user will find a bug in our software. Probably many users will find many bugs in our software.\n\nAnd this means that we're turning our users into our QA department.\n\nWhich, to be clear, is fine. Users have stated the price that they're willing to pay, and that price does not include correctness, so they're getting software that is not correct. I think we all feel bad about shipping buggy software, so let me emphasise this here: Buggy software is not a moral failing. The option to ship correct software is simply not on the table, so why on earth should we feel bad about not taking it?\n\nBut in another sense, turning our users into a QA department is a terrible idea.\n\nWhy? Because users are not actually good at QA. QA is a complicated professional skill which very few people can do well. Even skilled developers often don't know <a href=\"http://www.drmaciver.com/2013/09/how-to-submit-a-decent-bug-report/\">how to write a good bug report</a>. How can we possibly expect our users to?\n\nThe result is long and frustrating conversations with users in which you try to determine whether what they're seeing is actually a bug or a misunderstanding (although treating misunderstandings as bugs is a good idea too), trying to figure out what the actual bug is, etc. It's a time consuming process which ends up annoying the user and taking up a lot of expensive time from developers and customer support.\n\nAnd that's of course if the users tell you at all. Some users will just try your software, decide it doesn't work, and go away without ever saying anything to you. This is particularly bad for software where you can't easily tell who is using it.\n\nAlso, some of our users are actually adversaries. They're not only not going to tell you about bugs they find, they're going to actively try to keep you from finding out because they're using it to steal money and/or data from you.\n\nSo <em>this</em> is the problem with shipping buggy software: Bugs found by users are more expensive than bugs found before a user sees them. Bugs found by users may result in lost users, lost time and theft. These all hurt the bottom line.\n\nAt the same time, your users are a lot more effective at finding bugs than you are due to sheer numbers if nothing else, and as we've established it's basically impossible to ship fully correct software, so we end up choosing some level of acceptable defect rate in the middle. This is generally determined by the point at which it is more expensive to find the next bug yourself than it is to let your users find it. Any higher or lower defect rate and you could just adjust your development process and make more money, and companies like making money so if they're competently run will generally do the things that cause them to do so.\n\nYou can, and should, [cheaper to find bugs is to reduce the cost of when your users do find them](http://itamarst.org/softwaretesting/book/realworld.html), but it's always going to be expensive.\n\nThis means that there are only two viable ways to improve software quality:\n\n* Make users angrier about bugs\n* Make it cheaper to find bugs\n\nI think making users angrier about bugs is a good idea and I wish people cared more about software quality, but as a business plan it's a bit of a rubbish one. It creates higher quality software by making it more expensive to write software.\n\nMaking it cheaper to find bugs though... that's a good one, because it increases the quality of the software by increasing your profit margins. Literally everyone wins: The developers win, the users win, the business's owners win.\n\nAnd so this is the lever we get to pull to change the world: If you want better software, make or find tools that reduce the effort of finding bugs.\n\nObviously I think Hypothesis is an example of this, but it's neither the only one nor the only one you need. Better monitoring is another. Code review processes. Static analysis. Improved communication. There are many more.\n\nBut one thing that *won't* improve your ability to find bugs is feeling bad about yourself and trying really hard to write correct software then feeling guilty when you fail. This seems to be the current standard, and it's deeply counter-productive. You can't fix systemic issues with individual action, and the only way to ship better software is to change the economics to make it viable to do so.\n"
  },
  {
    "path": "website/content/2016-04-15-getting-started-with-hypothesis.md",
    "content": "---\ntags: intro, python, technical, properties\ndate: 2016-04-15 13:00\ntitle: Getting started with Hypothesis\nauthor: drmaciver\n---\n\nHypothesis will speed up your testing process and improve your software quality,\nbut when first starting out people often struggle to figure out exactly how to use it.\n\nUntil you're used to thinking in this style of testing, it's not always obvious what the invariants of your\ncode actually *are*, and people get stuck trying to come up with interesting ones to test.\n\nFortunately, there's a simple invariant which every piece of software should satisfy, and which can be\nremarkably powerful as a way to uncover surprisingly deep bugs in your software.\n\n<!--more-->\n\nThat invariant is simple: The software shouldn't crash. Or sometimes, it should only crash in defined\nways.\n\nThere is then a standard test you can write for most of your code that asserts this\ninvariant.\n\nIt consists of two steps:\n\n1. Pick a function in your code base that you want to be better tested.\n2. Call it with random data.\n\nThis style of testing is usually called *fuzzing*.\n\nThis will possibly require you to figure out how to generate your domain objects. Hypothesis\n[has a pretty extensive library](../generating-the-right-data/)\nof tools (called 'strategies' in Hypothesis terminology) for generating\ncustom types but if you can, try to start somewhere where the types you\nneed aren’t *too* complicated to generate.\n\nChances are actually pretty good that you’ll find something wrong this way if you pick a\nsufficiently interesting entry point. For example, there’s a long track record of people trying to\ntest interesting properties with their text handling and getting unicode errors when text()\ngives them something that their code didn’t know how to handle.\n\nYou’ll probably get exceptions here you don’t care about. e.g. some arguments to functions may not be valid.\nSet up your test to ignore those.\n\nSo at this point you’ll have something like this:\n\n```python\nfrom hypothesis import given, reject\nfrom hypothesis.strategies import integers, text\n\n\n@given(integers(), text())\ndef test_some_stuff(x, y):\n    try:\n        my_function(x, y)\n    except SomeExpectedException:\n        reject()\n```\n\nIn this example we generate two values - one integer, one text - and\npass them to your test function. Hypothesis will repeatedly call the\ntest function with values drawn from these strategies, trying to find\none that produces an unexpected exception.\n\nWhen an exception we know is possible happens (e.g. a ValueError because\nsome argument was out of range) we call reject. This discards the\nexample, and Hypothesis won't count it towards the 'budget' of examples\nit is allowed to run.\n\nThis is already a pretty good starting point and does have a decent\ntendency to flush out bugs. You’ll often find cases where you forgot some\nboundary condition and your code misbehaves as a result. But there’s\nstill plenty of room to improve.\n\nThere are now two directions you can go in from here:\n\n1. Try to assert some things about the function’s result. Anything at all. What type is it?\n   Can it be None? Does it have any relation at all to the input values that you can check?\n   It doesn’t have to be clever - even very trivial properties are useful here.\n2. Start making your code more defensive.\n\nThe second part is probably the most productive one.\n\nThe goal is to turn faulty assumptions in your code into crashes instead of silent corruption of your application state. You can do this in a couple ways:\n\n1. Add argument checking to your functions (Hypothesis uses a dedicated InvalidArgumentException for this case, but you can raise whatever errors you find appropriate).\n2. Add a whole bunch of assertions into your code itself.\nEven when it’s hard to reason about formal properties of your code, it’s usually relatively easy to add local properties, and assertions are a great way to encode them. John Regehr has [a good post on this subject](http://blog.regehr.org/archives/1091) if you want to know more about it.\n\nThis approach will make your code more robust even if you don’t find any bugs in it during testing (and you’ll probably find bugs in it during testing), and it gives you a nice easy route into property based testing by letting you focus on only one half of the problem at a time.\n\nOnce you think you've got the hang of this, a good next step is to start looking for\n[places with complex optimizations](../testing-performance-optimizations/) or\n[Encode/Decode pairs](../encode-decode-invariant/) in\nyour code, as they're a fairly easy properties to test and are both rich sources of bugs.\n"
  },
  {
    "path": "website/content/2016-04-16-anatomy-of-a-test.md",
    "content": "---\ntags: python, details, technical\ndate: 2016-04-16 06:00\ntitle: Anatomy of a Hypothesis Based Test\nauthor: drmaciver\n---\n\nWhat happens when you run a test using Hypothesis? This article will help you understand.\n\n<!--more-->\n\nThe Python version of Hypothesis uses *decorators* to transform a test function that\ndoesn't use Hypothesis into one that does.\n\nConsider the following example using [py.test](http://pytest.org/latest/) style testing:\n\n```python\nfrom hypothesis import given\nfrom hypothesis.strategies import floats\n\n\n@given(floats(), floats())\ndef test_floats_are_commutative(x, y):\n    assert x + y == y + x\n```\n\nThe inner function takes two arguments, but the wrapping function defined by the @given\ndecorator takes none and may be invoked as a normal test:\n\n```bash\npython -m pytest test_floats.py\n```\n\nAnd we see the following output from py.test:\n\n```\n    @given(floats(), floats())\n    def test_floats_are_commutative(x, y):\n>       assert x + y == y + x\nE       assert (0.0 + nan) == (nan + 0.0)\n\ntest_floats.py:7: AssertionError\n\nFalsifying example: test_floats_are_commutative(x=0.0, y=nan)\n```\n\nThe test fails, because [nan](https://en.wikipedia.org/wiki/NaN) is a valid floating\npoint number which is not equal to itself, and adding anything to nan yields nan.\n\nWhen we ran this, Hypothesis invoked our test function with a number of randomly chosen\nvalues for the arguments until it found one that failed. It then attempted to *shrink*\nthose values to produce a simpler one that would also fail.\n\nIf we wanted to see what it actually called our function with we can set the *verbosity\nlevel*. This can either be done in code with settings, or by specifying an environment\nvariable:\n\n\n```python\nfrom hypothesis import Verbosity, given, settings\nfrom hypothesis.strategies import floats\n\n\n@settings(verbosity=Verbosity.verbose)\n@given(floats(), floats())\ndef test_floats_are_commutative(x, y):\n    assert x + y == y + x\n```\n\n```bash\nHYPOTHESIS_VERBOSITY_LEVEL=verbose python -m pytest test_floats.py\n```\n\nAny verbosity values explicitly passed in settings will override whatever is set at\nthe environment level - the latter just provides a default.\n\nWhichever one we choose, running it we'll see output something like the following:\n\n```\n\nTrying example: test_floats_are_commutative(x=-0.05851890381391768, y=-6.060045836901702e+300)\nTrying example: test_floats_are_commutative(x=-0.06323690311413645, y=2.0324087421708266e-308)\nTrying example: test_floats_are_commutative(x=-0.05738038380011458, y=-1.5993500302384265e-308)\nTrying example: test_floats_are_commutative(x=-0.06598754758697359, y=-1.1412902232349034e-308)\nTrying example: test_floats_are_commutative(x=-0.06472919559855002, y=1.7429441378277974e+35)\nTrying example: test_floats_are_commutative(x=-0.06537123121982172, y=-8.136220566134233e-156)\nTrying example: test_floats_are_commutative(x=-0.06016703321602157, y=1.9718842567475311e-215)\nTrying example: test_floats_are_commutative(x=-0.055257588875432875, y=1.578407827448836e-308)\nTrying example: test_floats_are_commutative(x=-0.06313031758042666, y=1.6749023021600297e-175)\nTrying example: test_floats_are_commutative(x=-0.05886897920547916, y=1.213699633272585e+292)\nTrying example: test_floats_are_commutative(x=-12.0, y=-0.0)\nTrying example: test_floats_are_commutative(x=4.0, y=1.7976931348623157e+308)\nTrying example: test_floats_are_commutative(x=-9.0, y=0.0)\nTrying example: test_floats_are_commutative(x=-38.0, y=1.7976931348623157e+308)\nTrying example: test_floats_are_commutative(x=-24.0, y=1.5686642754811104e+289)\nTrying example: test_floats_are_commutative(x=-10.0, y=nan)\nTraceback (most recent call last):\n  ...\nAssertionError: assert (-10.0 + nan) == (nan + -10.0)\n\nTrying example: test_floats_are_commutative(x=10.0, y=nan)\nTraceback (most recent call last):\n  ...\nAssertionError: assert (10.0 + nan) == (nan + 10.0)\n\nTrying example: test_floats_are_commutative(x=0.0, y=nan)\nTraceback (most recent call last):\n  ...\nAssertionError: assert (0.0 + nan) == (nan + 0.0)\n\nTrying example: test_floats_are_commutative(x=0.0, y=0.0)\nTrying example: test_floats_are_commutative(x=0.0, y=inf)\nTrying example: test_floats_are_commutative(x=0.0, y=-inf)\nFalsifying example: test_floats_are_commutative(x=0.0, y=nan)\n```\n\nNotice how the first failing example we got was -10.0, nan but Hypothesis was able\nto turn that into 0.0, nan. That's the shrinking at work. For a simple case like this it\ndoesn't matter so much, but as your examples get complicated it's essential for making\nHypothesis's output easy to understand.\n\n\n```\nTrying example: test_floats_are_commutative(x=nan, y=0.0)\nTraceback (most recent call last):\n  ...\nAssertionError: assert (nan + 0.0) == (0.0 + nan)\n\nTrying example: test_floats_are_commutative(x=0.0, y=0.0)\nTrying example: test_floats_are_commutative(x=inf, y=0.0)\nTrying example: test_floats_are_commutative(x=-inf, y=0.0)\nFalsifying example: test_floats_are_commutative(x=nan, y=0.0)\n```\n\nNow lets see what happens when we rerun the test:\n\n\n```\nTrying example: test_floats_are_commutative(x=0.0, y=nan)\nTraceback (most recent call last):\n  ...\nAssertionError: assert (0.0 + nan) == (nan + 0.0)\n\nTrying example: test_floats_are_commutative(x=0.0, y=0.0)\nTrying example: test_floats_are_commutative(x=0.0, y=inf)\nTrying example: test_floats_are_commutative(x=0.0, y=-inf)\nFalsifying example: test_floats_are_commutative(x=0.0, y=nan)\n```\n\nNotice how the first example it tried was the failing example we had last time? That's\nnot an accident. Hypothesis has an example database where it saves failing examples.\nWhen it starts up it looks for any examples it has seen failing previously and tries\nthem first before any random generation occurs. If any of them fail, we take that\nfailure as our starting point and move straight to the shrinking phase without any\ngeneration.\n\nThe database format is safe to check in to version control if you like and will merge\nchanges correctly out of the box, but it's often clearer to specify the examples you\nwant to run every time in the source code as follows:\n\n\n```python\nfrom hypothesis import example, given\nfrom hypothesis.strategies import floats\n\n\n@example(0.0, float(\"nan\"))\n@given(floats(), floats())\ndef test_floats_are_commutative(x, y):\n    assert x + y == y + x\n```\n\n```\nFalsifying example: test_floats_are_commutative(x=0.0, y=nan)\n```\n\nIf you run this in verbose mode it will print out\nFalsifying example: test\\_floats\\_are\\_commutative(x=0.0, y=nan) immediately and\nnot try to do any shrinks. Values you pass in via example will not be shrunk.\nThis is partly a technical limitation but it can often be useful as well.\n\nExplicitly provided examples are run before any generated examples.\n\nSo, to recap and elaborate, when you use a test written using Hypothesis:\n\n1. Your test runner sees the decorated test as if it were a perfectly normal test function\n   and invokes it.\n2. Hypothesis calls your test function with each explicitly provided @example. If one\n   of these fails it stops immediately and bubbles up the exception for the test runner to handle.\n3. Hypothesis reads examples out of its database of previously failing examples. If any of them\n   fail, it stops there and proceeds to the shrinking step with that example. Otherwise it continues\n   to the generation step.\n4. Hypothesis tries generating a number of examples. If any of these raises an exception, it stops\n   there and proceeds to the shrinking step. If none of them raise an exception, it silently returns\n   and the test passes.\n5. Hypothesis takes the previously failing example it's seen and tries to produce a \"Simpler\" version\n   of it. Once it has found the simplest it possibly can, it saves that in the example database (in\n   actual fact it saves every failing example in the example database as it shrinks, but the reasons\n   why aren't important right now).\n6. Hypothesis takes the simplest failing example and replays it, finally letting the test bubble up to\n   the test runner.\n"
  },
  {
    "path": "website/content/2016-04-16-encode-decode-invariant.md",
    "content": "---\ntags: python, intro, technical, properties\ndate: 2016-04-16 06:00\ntitle: The Encode/Decode invariant\nauthor: drmaciver\n---\n\nOne of the simplest types of invariant to find once you move past\n[just fuzzing your code](../getting-started-with-hypothesis/) is asserting that two\ndifferent operations should produce the same result, and one of the simplest instances of\n*that* is looking for encode/decode pairs. That is, you have some function that takes a\nvalue and encodes it as another value, and another that is supposed to reverse the process.\n\nThis is ripe for testing with Hypothesis because it has a natural completely defined\nspecification: Encoding and then decoding should be exactly the same as doing nothing.\n\nLet's look at a concrete example.\n\n<!--more-->\n\nThe following code is a lightly reformatted version of\nan implementation of [Run Length Encoding](https://en.wikipedia.org/wiki/Run-length_encoding)\ntaken [from Rosetta Code](http://rosettacode.org/wiki/Run-length_encoding).\n\n```python\ndef encode(input_string):\n    count = 1\n    prev = \"\"\n    lst = []\n    for character in input_string:\n        if character != prev:\n            if prev:\n                entry = (prev, count)\n                lst.append(entry)\n            count = 1\n            prev = character\n        else:\n            count += 1\n    else:\n        entry = (character, count)\n        lst.append(entry)\n    return lst\n\n\ndef decode(lst):\n    q = \"\"\n    for character, count in lst:\n        q += character * count\n    return q\n```\n\nWe can test this using Hypothesis and py.test as follows:\n\n\n```python\nfrom hypothesis import given\nfrom hypothesis.strategies import text\n\n\n@given(text())\ndef test_decode_inverts_encode(s):\n    assert decode(encode(s)) == s\n```\n\nThis asserts what we described above: If we encode a string as run length encoded and then\ndecode it, we get back to where we started.\n\nThis test finds a bug, not through the actual invariant. Instead it finds one through pure\nfuzzing: The code does not correctly handle the empty string.\n\n\n```\nFalsifying example: test_decode_inverts_encode(s='')\n\nUnboundLocalError: local variable 'character' referenced before assignment\n```\n\nOne of the nice features of testing invariants is that they incorporate the fuzzing you\ncould be doing anyway, more or less for free, so even trivial invariants can often\nfind interesting problems.\n\nWe can fix this bug by adding a guard to the encode function:\n\n```python\nif not input_string:\n    return []\n```\n\nThe test now passes, which isn't very interesting, so let's break the code. We'll delete\na line from our implementation of encode which resets the count when the character changes:\n\n\n```python\ndef encode(input_string):\n    if not input_string:\n        return []\n    count = 1\n    prev = \"\"\n    lst = []\n    for character in input_string:\n        if character != prev:\n            if prev:\n                entry = (prev, count)\n                lst.append(entry)\n            # count = 1  # Missing reset operation\n            prev = character\n        else:\n            count += 1\n    else:\n        entry = (character, count)\n        lst.append(entry)\n    return lst\n```\n\nNow the test fails:\n\n```\n    @given(text())\n    def test_decode_inverts_encode(s):\n>       assert decode(encode(s)) == s\nE       assert '1100' == '110'\nE         - 1100\nE         ?    -\nE         + 110\n\ntest_encoding.py:35: AssertionError\n------------------------------------ Hypothesis ------------------------------------\nFalsifying example: test_decode_inverts_encode(s='110')\n\n```\n\nNot resetting the count did indeed produce unintended data that doesn't translate back\nto the original thing. Hypothesis has given us the shortest example that could trigger\nit - two identical characters followed by one different one. It's not *quite* the\nsimplest example according to Hypothesis's preferred ordering - that would be '001' -\nbut it's still simple enough to be quite legible, which helps to rapidly diagnose\nthe problem when you see it in real code.\n\nEncode/decode loops like this are *very* common, because you will frequently want to\nserialize your domain objects to other representations - into forms, into APIs, into\nthe database, and these are things that are so integral to your applications that it's\nworth getting all the edge cases right.\n\nOther examples of this:\n\n* [This talk by Matt Bacchman](https://speakerdeck.com/bachmann1234/property-based-testing-hypothesis)\n  in which he discovers an eccentricity of formats for dates.\n* Mercurial bugs [4927](https://bz.mercurial-scm.org/show_bug.cgi?id=4927) and [5031](https://bz.mercurial-scm.org/show_bug.cgi?id=5031)\n  were found by applying this sort of testing to their internal UTF8b encoding functions.\n* [This test](https://github.com/The-Compiler/qutebrowser/blob/24a71e5c2ebbffd9021694f32fa9ec51d0046d5a/tests/unit/browser/test_webelem.py#L652).\n  Has caught three bugs in Qutebrowser's JavaScript escaping ([1](https://github.com/The-Compiler/qutebrowser/commit/73e9fd11188ce4dddd7626e39d691e0df649e87c),\n  [2](https://github.com/The-Compiler/qutebrowser/commit/93d27cbb5f49085dd5a7f5e05f2cc45cc84f94a4),\n  [3](https://github.com/The-Compiler/qutebrowser/commit/24a71e5c2ebbffd9021694f32fa9ec51d0046d5a)), which could have caused data loss if a user had run\n  into them.\n"
  },
  {
    "path": "website/content/2016-04-16-quickcheck-in-every-language.md",
    "content": "---\ntags: alternatives, technical\ndate: 2016-04-16 15:00\ntitle: QuickCheck in Every Language\nauthor: drmaciver\n---\n\n<p>\nThere are a lot of ports of <a href=\"https://en.wikipedia.org/wiki/QuickCheck\">QuickCheck</a>,\nthe original property based testing library, to a variety of different languages.\n</p>\n\n<p>\nSome of them are good. Some of them are <em>very</em> good. Some of them are OK. Many are not.\n</p>\n\n<p>\nI thought it would be worth keeping track of which are which, so I've put together a list.\n</p>\n\n<!--more-->\n\n<p>In order to make it onto this list, an implementation has to meet the following criteria:</p>\n\n<ol>\n\t<li>Must support random generation of data to a test function. e.g. testing systems based on\n      <a href=\"https://hackage.haskell.org/package/smallcheck\">smallcheck</a> while interesting and related\n      don't fit on this list.\n  </li>\n\t<li>It must be fairly straightforward to generate your own custom types.</li>\n\t<li>It must support shrinking of falsifying examples.</li>\n\t<li>It must be under active development, in the sense that bugs in it will get fixed.</li>\n\t<li>Must be under an OSI approved license.</li>\n</ol>\n<p>\nIn this I've tried to collect a list of what I think the best ones are for any given language.\nI haven't used all of these, but I've used some and read and talked to people about the others.\n</p>\n\n<h2>Uncontested Winners by Language</h2>\n\n<p>For many languages there is a clear winner that you should just use. Here are the ones I've\nfound and what I think of them.</p>\n\n\n<table class=\"table\">\n\n<thead>\n<tr>\n<th>Language</th>\n<th>Library</th>\n<th>Our rating</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>C</td>\n<td><a href=\"https://github.com/silentbicycle/theft\">theft</a></td>\n<td>Good but does not come with a library of data generators.</td>\n</tr>\n<tr>\n<td>C++</td>\n<td><a href=\"https://github.com/grogers0/CppQuickCheck\">CppQuickCheck</a></td>\n<td>Unsure</td>\n</tr>\n<tr>\n<td>Clojure</td>\n<td><a href=\"https://github.com/clojure/test.check\">test.check</a></td>\n<td>Very good</td>\n</tr>\n<tr>\n<td>Coq</td>\n<td><a href=https://github.com/QuickChick/QuickChick>QuickChick</a></td>\n<td>Unsure</td>\n</tr>\n<tr>\n<td>F#</td>\n<td><a href=\"https://github.com/fscheck/FsCheck\">FsCheck</a></td>\n<td>Very Good</td>\n</tr>\n<tr>\n<td>Go</td>\n<td><a href=\"https://github.com/leanovate/gopter\">gopter</a></td>\n<td>Unsure but looks promising.</td>\n</tr>\n<tr>\n<td>Haskell</td>\n<td><a href=\"https://hackage.haskell.org/package/hedgehog\">Hedgehog</a></td>\n<td>Comparatively new, but looks solid. See below.</td>\n</tr>\n<tr>\n<td>Java</td>\n<td><a href=\"https://github.com/NCR-CoDE/QuickTheories\">QuickTheories</a></td>\n<td>Unsure. Extremely new but looks promising.</td>\n</tr>\n<tr>\n<td>JavaScript</td>\n<td><a href=\"https://github.com/jsverify/jsverify\">jsverify</a></td>\n<td>Good</td>\n</tr>\n<tr>\n<td>PHP</td>\n<td><a href=\"https://github.com/giorgiosironi/eris\">Eris</a></td>\n<td>Unsure. Looks promising.</td>\n</tr>\n<tr>\n<td>Python</td>\n<td><a href=\"http://hypothesis.works\">Hypothesis</a></td>\n<td>I may be a bit biased on this one, but it's also unambiguously true.</td>\n</tr>\n<tr>\n<td>Ruby</td>\n<td><a href=\"https://github.com/abargnesi/rantly\">Rantly</a></td>\n<td>Unsure. We're not convinced, but the alternatives are definitely worse.</td>\n</tr>\n<tr>\n<td>Rust</td>\n<td><a href=\"https://github.com/BurntSushi/quickcheck\">Quickcheck</a></td>\n<td>Unsure, but probably very good based on initial appearance and usage level.</td>\n</tr>\n<tr>\n<td>Scala</td>\n<td><a href=\"https://www.scalacheck.org/\">ScalaCheck</a></td>\n<td>Very Good</td>\n</tr>\n<tr>\n<td>Swift</td>\n<td><a href=\"https://github.com/typelift/SwiftCheck\">Swiftcheck</a></td>\n<td>Unsure</td>\n</tr>\n</tbody>\n</table>\n\n<p>Where when I've said \"Unsure\" I really just mean that I think it looks good but\nI haven't put in the depth of in time to be sure, not that I have doubts.</p>\n\n<h2>Special case: Haskell</h2>\n\n<p>\n  <a href=\"https://hackage.haskell.org/package/QuickCheck\">The original QuickCheck</a>\n  was of course written in Haskell, so it may seem odd that it's not the property based testing\n  library I recommend for Haskell!\n</p>\n\n<p>\n  The reason is that I feel that the design of classic QuickCheck is fundamentally limiting,\n  and that Hedgehog takes it in the direction that the rest of the property-based testing\n  world is moving (and where most of the implementations for dynamic languages, Hypothesis\n  included, already are). In particular its approach starts from generators rather than\n  type classes, and it has <a href=\"../integrated-shrinking %}\">integrated shrinking</a>,\n  and a fairly comprehensive library of generators.\n</p>\n\n<h2>Special case: Erlang</h2>\n\n<p>\n  Erlang is a special case because they have <a href=\"http://www.quviq.com/\">QuviQ's QuickCheck</a>.\n  Their QuickCheck implementation is by all accounts <em>extremely</em> good, but it is also proprietary\n  and fairly expensive. Nevertheless, if you find yourselves in the right language, circumstance and\n  financial situation to use it, I would strongly recommend doing so.\n</p>\n\n<p>\n  In particular, QuviQ's QuickCheck is really the only implementation in this article I think is\n  simply better than Hypothesis. Hypothesis is significantly more user friendly, especially if the\n  users in question are less than familiar with Erlang, but there are things QuviQ can do that\n  Hypothesis can't, and the data generation has had a great deal more engineering effort put into it.\n</p>\n\n<p>\n  If you're using Erlang but <em>not</em> able to pay for QuickCheck, apparently the one to use is\n  <a href=\"https://github.com/manopapad/proper\">PropEr</a>. If you're also unable to use GPLed software\n  there's <a href=https://github.com/krestenkrab/triq>triq</a>. I know very little about either.\n</p>\n\n<h2>Special case: OCaml</h2>\n\n<p>\n  OCaml seems to be suffering from a problem of being close enough to Haskell that people try to do a\n  straight port of Quickcheck but far enough from Haskell that this doesn't work. The result is that\n  there is <a href=\"https://github.com/alanfalloon/ocaml-quickcheck\">a \"mechanical port\" of Quickcheck\n  which is completely abandoned</a> and <a href=\"https://github.com/camlunity/ocaml-quickcheck\">a fork\n  of it that uses more idiomatic OCaml</a>. I'm insufficiently familiar with OCaml or its community\n  to know if either is used or whether there is another one that is.\n</p>\n\n<h2>What does this have to do with Hypothesis?</h2>\n\n<p>\n  In some sense these are all \"competitors\" to Hypothesis, but we're perfectly happy not to compete.\n</p>\n\n<p>\n  In the case of Erlang, I wouldn't even try. In the case of Scala, F#, or Clojure, I might at some\n  point work with them to try to bring the best parts of Hypothesis to their existing implementation,\n  but I don't consider them a priority - they're well served by what they have right now, and there\n  are many languages that are not.\n</p>\n\n<p>\n  For the rest though? I'm glad they exist! I care about testing and about high quality software,\n  and they're doing their part to make it possible.\n</p>\n\n<p>\n  But I feel they're being badly served by their underlying model, and that they feel quite unnatural\n  to use in the context of a more conventional test setting. I think Hypothesis is the way forward,\n  and I'll be doing my best <a href=\"/services/#ports-of-hypothesis-to-new-languages\">to make it\n  possible for everyone to use it in their language of choice</a>.\n</p>\n"
  },
  {
    "path": "website/content/2016-04-16-the-purpose-of-hypothesis.md",
    "content": "---\ntags: writing-good-software, principles, non-technical\ndate: 2016-04-16 12:00\ntitle: The Purpose of Hypothesis\nauthor: drmaciver\n---\n\nWhat is Hypothesis for?\n\nFrom the perspective of a user, the purpose of Hypothesis is to make it easier for you\nto write better tests.\n\nFrom my perspective as the primary author, that is of course also *a* purpose of Hypothesis.\nI write a lot of code, it needs testing, and the idea of trying to do that without Hypothesis\nhas become nearly unthinkable.\n\nBut, on a large scale, the true purpose of Hypothesis is to drag the world kicking and screaming\ninto a new and terrifying age of high quality software.\n\n<!--more-->\n\nSoftware is everywhere. We have built a civilization on it, and it's only getting more prevalent\nas more services move online and embedded and \"internet of things\" devices become cheaper and\nmore common.\n\nSoftware is also terrible. It’s buggy, it's insecure, and it's rarely well thought out.\n\nThis combination is clearly a recipe for disaster.\n\nThe state of software testing is even worse. It’s uncontroversial at this point that you *should*\nbe testing your code, but it's a rare codebase whose authors could honestly claim that they feel\nits testing is sufficient.\n\nMuch of the problem here is that it’s too hard to write good tests. Tests take up a vast quantity\nof development time, but they mostly just laboriously encode exactly the same assumptions and\nfallacies that the authors had when they wrote the code, so they miss exactly the same bugs that\nyou missed when they wrote the code.\n\nMeanwhile, there are all sorts of tools for making testing better that are basically unused, or\nused in only specialised contexts. The original Quickcheck is from 1999 and the majority of\ndevelopers have not even heard of it, let alone used it. There are a bunch of half-baked\nimplementations for most languages, but very few of them are worth using. More recently, there\nare many good tools applied to specialized problems, but very little that even attempts, let\nalone succeeds, to help general purpose testing.\n\nThe goal of Hypothesis is to fix this, by taking research level ideas and applying solid\nengineering to them to produce testing tools that are both powerful *and* practical, and\nare accessible to everyone..\n\nMany of the ideas that Hypothesis is built on are new. Many of them are not. It doesn't matter.\nThe purpose of Hypothesis is not to produce research level ideas. The purpose of Hypothesis is\nto produce high quality software by any means necessary. Where the ideas we need exist, we\nwill use them. Where they do not, we will invent them.\n\nIf people aren't using advanced testing tools, that's a bug. We should find it and fix it.\n\nFortunately, we have this tool called Hypothesis. It's very good at finding bugs. But this\none it can also fix.\n"
  },
  {
    "path": "website/content/2016-04-19-rule-based-stateful-testing.md",
    "content": "---\ntags: python, technical, intro\ndate: 2016-04-19 07:00\ntitle: Rule Based Stateful Testing\nauthor: drmaciver\n---\n\nHypothesis's standard testing mechanisms are very good for testing things that can be\nconsidered direct functions of data. But supposed you have some complex stateful\nsystem or object that you want to test. How can you do that?\n\nIn this article we'll see how to use Hypothesis's *rule based state machines* to define\ntests that generate not just simple data, but entire programs using some stateful\nobject. These will give the same level of boost to testing the behaviour of the\nobject as you get to testing the data it accepts.\n\n<!--more-->\n\nThe model of a stateful system we'll be using is a [priority queue](https://en.wikipedia.org/wiki/Priority_queue)\nimplemented as a binary heap.\n\nWe have the following operations:\n\n* newheap() - returns a new heap\n* heappush(heap, value) - place a new value into the heap\n* heappop(heap) - remove and return the smallest value currently on the heap. Error if heap is empty.\n* heapempty(heap) - return True if the heap has no elements, else False.\n\nWe'll use the following implementation of these:\n\n```python\ndef heapnew():\n    return []\n\n\ndef heapempty(heap):\n    return not heap\n\n\ndef heappush(heap, value):\n    heap.append(value)\n    index = len(heap) - 1\n    while index > 0:\n        parent = (index - 1) // 2\n        if heap[parent] > heap[index]:\n            heap[parent], heap[index] = heap[index], heap[parent]\n            index = parent\n        else:\n            break\n\n\ndef heappop(heap):\n    return heap.pop(0)\n```\n\n(Note that this implementation is *wrong*. heappop as implemented will return the smallest element\nif the heap currently satisfies the heap property, but it will not rebalance the heap afterwards\nso it may leave the heap in an invalid state)\n\nWe could test this readily enough using @given with something like the following:\n\n\n```python\nfrom hypothesis import given\nfrom hypothesis.strategies import integers, lists\n\n\n@given(lists(integers()))\ndef test_pop_in_sorted_order(ls):\n    h = heapnew()\n    for l in ls:\n        heappush(h, l)\n    r = []\n    while not heapempty(h):\n        r.append(heappop(h))\n    assert r == sorted(ls)\n```\n\nAnd this indeed finds the bug:\n\n```\n>       assert r == sorted(ls)\nE       assert [0, 1, 0] == [0, 0, 1]\nE         At index 1 diff: 1 != 0\nE         Use -v to get the full diff\n\nbinheap.py:74: AssertionError\n----- Hypothesis -----\nFalsifying example: test_pop_in_sorted_order(ls=[0, 1, 0])\n```\n\nSo we replace heappop with a correct implementation which rebalances the heap:\n\n```python\ndef heappop(heap):\n    if len(heap) == 0:\n        raise ValueError(\"Empty heap\")\n    if len(heap) == 1:\n        return heap.pop()\n    result = heap[0]\n    heap[0] = heap.pop()\n    index = 0\n    while index * 2 + 1 < len(heap):\n        children = [index * 2 + 1, index * 2 + 2]\n        children = [i for i in children if i < len(heap)]\n        assert children\n        children.sort(key=lambda x: heap[x])\n        for c in children:\n            if heap[index] > heap[c]:\n                heap[index], heap[c] = heap[c], heap[index]\n                index = c\n                break\n        else:\n            break\n    return result\n```\n\nBut how do we know this is enough? Might some combination of mixing pushes and pops break the\ninvariants of the heap in a way that this simple pattern of pushing everything then popping\neverything cannot witness?\n\nThis is where the rule based state machines come in. Instead of just letting Hypothesis give\nus data which we feed into a fixed structure of test, we let Hypothesis choose which operations\nto perform on our data structure:\n\n```python\nfrom hypothesis.stateful import RuleBasedStateMachine, precondition, rule\n\n\nclass HeapMachine(RuleBasedStateMachine):\n    def __init__(self):\n        super().__init__()\n        self.heap = []\n\n    @rule(value=integers())\n    def push(self, value):\n        heappush(self.heap, value)\n\n    @rule()\n    @precondition(lambda self: self.heap)\n    def pop(self):\n        correct = min(self.heap)\n        result = heappop(self.heap)\n        assert correct == result\n```\n\n@rule is a slightly restricted version of @given that only works for methods on a RuleBasedStateMachine.\n\nHowever it has one *major* difference from @given, which is that multiple rules can be chained together:\nA test using this state machine doesn't just run each rule in isolation, it instantiates an instance of\nthe machine and then runs multiple rules in succession.\n\nThe @precondition decorator constrains when a rule is allowed to fire: We are not allowed to pop from\nan empty heap, so the pop rule may only fire when there is data to be popped.\n\nWe can run this by getting a standard unit test TestCase object out of it to be picked up by unittest\nor py.test as normal:\n\n```python\nTestHeaps = HeapMachine.TestCase\n```\n\nWith our original broken heappop we find the same bug as before:\n\n```\nE       AssertionError: assert 0 == 1\n\nbinheap.py:90: AssertionError\n----- Captured stdout call -----\nStep #1: push(value=1)\nStep #2: push(value=0)\nStep #3: push(value=0)\nStep #4: pop()\nStep #5: pop()\n```\n\nWith the fixed implementation the test passes.\n\nAs it currently stands, this is already very useful. It's particularly good for testing single standalone\nobjects or services like storage systems.\n\nBut one limitation of it as we have written it is that it only concerns ourselves with a single heap. What\nif we wanted to combine two heaps? For example, suppose we wanted a heap merging operation that takes two\nheaps and returns a new heap containing the values in either of the original two.\n\nAs before, we'll start with a broken implementation:\n\n```python\ndef heapmerge(x, y):\n    x, y = sorted((x, y))\n    return x + y\n```\n\nWe can't just write a strategy for heaps, because each heap would be a fresh object and thus it would not\npreserve the stateful aspect.\n\nWhat we instead do is use the other big feature of Hypothesis's rule bases state machines: Bundles.\n\nBundles allow rules to return as well as accept values. A bundle is a strategy which generates anything\na rule has previously provided to it. Using them is as follows:\n\n\n```python\nclass HeapMachine(RuleBasedStateMachine):\n    Heaps = Bundle(\"heaps\")\n\n    @rule(target=Heaps)\n    def newheap(self):\n        return []\n\n    @rule(heap=Heaps, value=integers())\n    def push(self, heap, value):\n        heappush(heap, value)\n\n    @rule(heap=Heaps.filter(bool))\n    def pop(self, heap):\n        correct = min(heap)\n        result = heappop(heap)\n        assert correct == result\n\n    @rule(target=Heaps, heap1=Heaps, heap2=Heaps)\n    def merge(self, heap1, heap2):\n        return heapmerge(heap1, heap2)\n```\n\nSo now instead of a single heap we manage a collection of heaps. All of our previous operations become\nconstrained by an instance of a heap.\n\nNote the use of filter: A bundle is a strategy you can use like any other. In this case the filter replaces\nour use of a precondition because we now only care about whether this *specific* heap is empty.\n\nThis is sufficient to find the fact that our implementation is wrong:\n\n```\n    @rule(heap=Heaps.filter(bool))\n    def pop(self, heap):\n        correct = min(heap)\n        result = heappop(heap)\n>       assert correct == result\nE       AssertionError: assert 0 == 1\n\nbinheap.py:105: AssertionError\n\n----- Captured stdout call -----\n\nStep #1: v1 = newheap()\nStep #2: push(heap=v1, value=0)\nStep #3: push(heap=v1, value=1)\nStep #4: push(heap=v1, value=1)\nStep #5: v2 = merge(heap2=v1, heap1=v1)\nStep #6: pop(heap=v2)\nStep #7: pop(heap=v2)\n```\n\nWe create a small heap, merge it with itself, and rapidly discover that it has become unbalanced.\n\nWe can fix this by fixing our heapmerge to be correct:\n\n```python\ndef heapmerge(x, y):\n    result = list(x)\n    for v in y:\n        heappush(result, v)\n    return result\n```\n\nBut that's boring. Lets introduce a more *interestingly* broken implementation instead:\n\n```python\ndef heapmerge(x, y):\n    result = []\n    i = 0\n    j = 0\n    while i < len(x) and j < len(y):\n        if x[i] <= y[j]:\n            result.append(x[i])\n            i += 1\n        else:\n            result.append(y[j])\n            j += 1\n    result.extend(x[i:])\n    result.extend(y[j:])\n    return result\n```\n\nThis merge operation selectively splices two heaps together as if we were merging two\nsorted lists (heaps aren't actually sorted, but the code still works regardless it\njust doesn't do anything very meaningful).\n\nThis is wrong, but it turns out to work surprisingly well for small heaps and it's\nnot completely straightforward to find an example showing that it's wrong.\n\nHere's what Hypothesis comes up with:\n\n```\nStep #1: v1 = newheap()\nStep #2: push(heap=v1, value=0)\nStep #3: v2 = merge(heap1=v1, heap2=v1)\nStep #4: v3 = merge(heap1=v2, heap2=v2)\nStep #5: push(heap=v3, value=-1)\nStep #6: v4 = merge(heap1=v1, heap2=v2)\nStep #7: pop(heap=v4)\nStep #8: push(heap=v3, value=-1)\nStep #9: v5 = merge(heap1=v1, heap2=v2)\nStep #10: v6 = merge(heap1=v5, heap2=v4)\nStep #11: v7 = merge(heap1=v6, heap2=v3)\nStep #12: pop(heap=v7)\nStep #13: pop(heap=v7)\n```\n\nThrough a careful set of heap creation and merging, Hypothesis manages to find a series\nof merges that produce an unbalanced heap. Every heap prior to v7 is balanced, but v7 looks\nlike this:\n\n```\n>>> v7\n[-1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0]\n```\n\nWhich doesn't satisfy the heap property because of that -1 far down in the list.\n\nI don't know about you, but I would never have come up with that example. There's probably\na simpler one given a different set of operations - e.g. one thing that would probably improve\nthe quality of this test is to let Hypothesis instantiate a new heap with a list of elements\nwhich it pops onto it.\n\nBut the nice thing about rule based stateful testing is that I don't *have* to come up with\nthe example. Instead Hypothesis is able to guarantee that every combination of operations\non my objects works, and can flush out some remarkably subtle bugs in the process.\n\nBecause after all, if it takes this complicated an example to demonstrate that a completely\nwrong implementation is wrong, how hard can it sometimes be to demonstrate subtle bugs?\n\n### Real world usage\n\nThis feature is currently somewhat under-documented so hasn't seen as widespread adoption as\nit could. However, there are at least two interesting real world examples:\n\n1. Hypothesis uses it to test itself. Hypothesis has [tests of its example database](\n   https://github.com/HypothesisWorks/hypothesis-python/blob/master/tests/cover/test_database_agreement.py)\n   which work very much like the above, and [a small model of its test API](\n   https://github.com/HypothesisWorks/hypothesis-python/blob/master/tests/nocover/test_strategy_state.py)\n   which generates random strategies and runs tests using them.\n2. It's being used to [test Mercurial](https://www.mercurial-scm.org/pipermail/mercurial-devel/2016-February/080037.html)\n   generating random. So far it's found [bug 5112](https://bz.mercurial-scm.org/show_bug.cgi?id=5112) and\n   [bug 5113](https://bz.mercurial-scm.org/show_bug.cgi?id=5113). The usage pattern on Mercurial is one\n   such that the stateful testing probably needs more resources, more rules and more work on deployment\n   before it's going to find much more than that though.\n"
  },
  {
    "path": "website/content/2016-04-29-testing-performance-optimizations.md",
    "content": "---\ntags: technical, intro, python, properties\ndate: 2016-04-29 11:00\ntitle: Testing performance optimizations\nauthor: drmaciver\n---\n\nOnce you've\n[flushed out the basic crashing bugs](../getting-started-with-hypothesis/)\nin your code, you're going to want to look for more interesting things to test.\n\nThe next easiest thing to test is code where you know what the right answer is for every input.\n\nObviously in theory you think you know what the right answer is - you can just run the code. That's not very\nhelpful though, as that's the answer you're trying to verify.\n\nBut sometimes there is more than one way to get the right answer, and you choose the one you run in production\nnot because it gives a different answer but because it gives the same answer *faster*.\n\n<!--more-->\n\nFor example:\n\n* There might be a fancy but fast version of an algorithm and a simple but slow version of an algorithm.\n* You might have a caching layer and be able to run the code with and without caching turned on, or with a\n  different cache timeout.\n* You might be moving to a new database backend to improve your scalability, but you still have the code for\n  the old backend until you've completed your migration.\n\nThere are plenty of other ways this can crop up, but those are the ones that seem the most common.\n\nAnyway, this creates an *excellent* use case for property based testing, because if two functions are supposed\nto always return the same answer, you can test that: Just call both functions with the same data and assert\nthat their answer is the same.\n\nLet's look at this in the fancy algorithm case. Suppose we implemented [merge sort](\nhttps://en.wikipedia.org/wiki/Merge_sort):\n\n```python\ndef merge_sort(ls):\n    if len(ls) <= 1:\n        return ls\n    else:\n        k = len(ls) // 2\n        return merge_sorted_lists(merge_sort(ls[:k]), merge_sort(ls[k:]))\n\n\ndef merge_sorted_lists(x, y):\n    result = []\n    i = 0\n    j = 0\n    while i < len(x) and j < len(y):\n        if x[i] <= y[j]:\n            result.append(x[i])\n            i += 1\n        else:\n            result.append(y[j])\n            j += 1\n    return result\n```\n\nWe want a reference implementation to test it against, so lets also implement [bubble sort](\nhttps://en.wikipedia.org/wiki/Bubble_sort):\n\n```python\ndef bubble_sort(ls):\n    ls = list(ls)\n    needs_sorting = True\n    while needs_sorting:\n        needs_sorting = False\n        for i in range(1, len(ls)):\n            if ls[i - 1] > ls[i]:\n                needs_sorting = True\n                ls[i - 1], ls[i] = ls[i], ls[i - 1]\n    return ls\n```\n\nThese *should* always give the same answer,  so let's test that:\n\n```python\n@given(lists(integers()))\ndef test_bubble_sorting_is_same_as_merge_sorting(ls):\n    assert bubble_sort(ls) == merge_sort(ls)\n```\n\nThis gives us an error:\n\n```\n    @given(lists(integers()))\n    def test_bubble_sorting_is_same_as_merge_sorting(ls):\n>       assert bubble_sort(ls) == merge_sort(ls)\nE       assert [0, 0] == [0]\nE         Left contains more items, first extra item: 0\nE         Use -v to get the full diff\n\nfoo.py:43: AssertionError\n----- Hypothesis -----\nFalsifying example: test_bubble_sorting_is_same_as_merge_sorting(ls=[0, 0])\n```\n\nWhat's happened is that we messed up our implementation of merge\\_sorted\\_lists, because we forgot\nto include the elements left over in the other list once we've reached the end of one of them. As a\nresult we ended up losing elements from the list, a problem that our simpler implementation lacks.\nWe can fix this as follows and then the test passes:\n\n```python\ndef merge_sorted_lists(x, y):\n    result = []\n    i = 0\n    j = 0\n    while i < len(x) and j < len(y):\n        if x[i] <= y[j]:\n            result.append(x[i])\n            i += 1\n        else:\n            result.append(y[j])\n            j += 1\n    result.extend(x[i:])\n    result.extend(y[j:])\n    return result\n```\n\nThis technique combines especially well with\n[Hypothesis's stateful testing](../rule-based-stateful-testing/), because\nyou can use it to then test different implementations of complex APIs. For example, Hypothesis uses this\nproperty together with stateful testing to [verify that the different implementations of its example database\nbehave identically](https://github.com/HypothesisWorks/hypothesis/blob/master/hypothesis-python/tests/nocover/test_database_agreement.py).\n"
  },
  {
    "path": "website/content/2016-05-02-referential-transparency.md",
    "content": "---\ntags: non-technical\ndate: 2016-05-02 08:00\ntitle: You Don't Need Referential Transparency\nauthor: drmaciver\n---\n\nIt's a common belief that in order for property based testing to be useful, your code must be [referentially transparent](https://en.wikipedia.org/wiki/Referential_transparency). That is, it must be a pure function with no side effects that just takes input data and produces output data and is solely defined by what input data produces what output data.\n\nThis is, bluntly, complete and utter nonsense with no basis in reality.\n\n<!--more-->\n\n\nThe idea comes from the fact that it was true of very early versions of [the original Haskell QuickCheck](https://hackage.haskell.org/package/QuickCheck) - it was designed to look more like formal methods than unit testing, and it was designed for a language where referential transparency was the norm.\n\nBut that was the *original* version of Haskell QuickCheck. It's not even true for the latest version of it, let alone for ports to other languages! The Haskell version has full support for testing properties in IO (if you don't know Haskell, this means \"tests which may have side effects\"). It works really well. Hypothesis doesn't even consider this a question - testing code with side effects works the same way as testing code without side effects.\n\nThe *only* requirement that property based testing has on the side effects your tests may perform is that if your test has *global* side effects then it must be able to roll them back at the end.\n\nIf that sounds familiar, it's because it's *exactly the same requirement every other test has*. Tests that have global side effects are not repeatable and may interfere with other tests, so they must keep their side effects to themselves by rolling them back at the end of the test.\n\nProperty based testing is just normal testing, run multiple times, with a source of data to fill in some of the blanks. There is no special requirement on it beyond that, and the myth that there is causes great harm and keeps many people from adopting more powerful testing tools.\n"
  },
  {
    "path": "website/content/2016-05-11-generating-the-right-data.md",
    "content": "---\ntags: technical, python, intro\ndate: 2016-05-11 10:00\ntitle: Generating the right data\nauthor: drmaciver\n---\n\nOne thing that often causes people problems is figuring out how to generate\nthe right data to fit their data\nmodel. You can start with just generating strings and integers, but eventually you want\nto be able to generate\nobjects from your domain model. Hypothesis provides a lot of tools to help you build the\ndata you want, but sometimes the choice can be a bit overwhelming.\n\nHere's a worked example to walk you through some of the details and help you get to grips with how to use\nthem.\n\n<!--more-->\n\nSuppose we have the following class:\n\n```python\nclass Project:\n    def __init__(self, name, start, end):\n        self.name = name\n        self.start = start\n        self.end = end\n\n    def __repr__(self):\n        return f\"Project {self.name} from {self.start.isoformat()} to {self.end.isoformat()}\"\n```\n\nA project has a name, a start date, and an end date.\n\nHow do we generate such a thing?\n\nThe idea is to break the problem down into parts, and then use the tools\nHypothesis provides to assemble those parts into a strategy for generating\nour projects.\n\nWe'll start by generating the data we need for each field, and then at the end\nwe'll see how to put it all together to generate a Project.\n\n### Names\n\nFirst we need to generate a name. We'll use Hypothesis's standard text\nstrategy for that:\n\n```pycon\n>>> from hypothesis.strategies import text\n>>> text().example()\n''\n>>> text().example()\n'\\nŁ昘迥'\n```\n\nLets customize this a bit: First off, lets say project names have to be\nnon-empty.\n\n```pycon\n>>> text(min_size=1).example()\n'w\\nC'\n>>> text(min_size=1).example()\n'ሚಃJ»'\n```\n\nNow, lets avoid the high end unicode for now (of course, your system *should*\nhandle the full range of unicode, but this is just an example, right?).\n\nTo do this we need to pass an alphabet to the text strategy. This can either be\na range of characters or another strategy. We're going to use the *characters*\nstrategy, which gives you a flexible way of describing a strategy for single-character\ntext strings, to do that.\n\n```pycon\ni>>> characters(min_codepoint=1, max_codepoint=1000, exclude_categories=('Cc', 'Cs')).example()\n'²'\n>>> characters(min_codepoint=1, max_codepoint=1000, exclude_categories=('Cc', 'Cs')).example()\n'E'\n>>> characters(min_codepoint=1, max_codepoint=1000, exclude_categories=('Cc', 'Cs')).example()\n'̺'\n\n```\n\nThe max and min codepoint parameters do what you'd expect: They limit the range of\npermissible codepoints. We've blocked off the 0 codepoint (it's not really useful and\ntends to just cause trouble with C libraries) and anything with a codepoint above\n1000 - so we're considering non-ASCII characters but nothing really high end.\n\nThe blacklist\\_categories parameter uses the notion of [unicode category](https://en.wikipedia.org/wiki/Unicode_character_property#General_Category)\nto limit the range of acceptable characters. If you want to see what category a\ncharacter has you can use Python's unicodedata module to find out:\n\n```pycon\n>>> from unicodedata import category\n>>> category('\\n')\n'Cc'\n>>> category('\\t')\n'Cc'\n>>> category(' ')\n'Zs'\n>>> category('a')\n'Ll'\n```\n\nThe categories we've excluded are *control characters* and *surrogates*. Surrogates\nare excluded by default but when you explicitly pass in blacklist categories you\nneed to exclude them yourself.\n\nSo we can put that together with text() to get a name matching our requirements:\n\n```pycon\n>>> names = text(characters(max_codepoint=1000, exclude_categories=('Cc', 'Cs')), min_size=1)\n```\n\nBut this is still not quite right: We've allowed spaces in names, but we don't really want\na name to start with or end with a space. You can see that this is currently allowed by\nasking Hypothesis for a more specific example:\n\n```pycon\n>>> find(names, lambda x: x[0] == ' ')\n' '\n```\n\nSo let's fix it so that they can't by stripping the spaces off it.\n\nTo do this we're going to use the strategy's *map* method which lets you compose it with\nan arbitrary function to post-process the results into the for you want:\n\n```pycon\n>>> names = text(characters(max_codepoint=1000, exclude_categories=('Cc', 'Cs')), min_size=1).map(\n...     lambda x: x.strip())\n```\n\nNow let's check that we can no longer have the above problem:\n\n```pycon\n>>> find(names, lambda x: x[0] == ' ')\nTraceback (most recent call last):\n  File \"<stdin>\", line 1, in <module>\n  File \"/usr/lib/python3.5/site-packages/hypothesis/core.py\", line 648, in find\n    runner.run()\n  File \"/usr/lib/python3.5/site-packages/hypothesis/internal/conjecture/engine.py\", line 168, in run\n    self._run()\n  File \"/usr/lib/python3.5/site-packages/hypothesis/internal/conjecture/engine.py\", line 262, in _run\n    self.test_function(data)\n  File \"/usr/lib/python3.5/site-packages/hypothesis/internal/conjecture/engine.py\", line 68, in test_function\n    self._test_function(data)\n  File \"/usr/lib/python3.5/site-packages/hypothesis/core.py\", line 616, in template_condition\n    success = condition(result)\n  File \"<stdin>\", line 1, in <lambda>\nIndexError: string index out of range\n```\n\nWhoops!\n\nThe problem is that our initial test worked because the strings we were generating were always\nnon-empty because of the min\\_size parameter. We're still only generating non-empty strings,\nbut if we generate a string which is all spaces then strip it, the result will be empty\n*after* our map.\n\nWe can fix this using the strategy's *filter* function, which restricts to only generating\nthings which satisfy some condition:\n\n```pycon\n>>> names = text(characters(max_codepoint=1000, exclude_categories=('Cc', 'Cs')), min_size=1).map(\n...     lambda s: s.strip()).filter(lambda s: len(s) > 0)\n```\n\nAnd repeating the check:\n\n```pycon\n>>> find(names, lambda x: x[0] == ' ')\nTraceback (most recent call last):\n  File \"<stdin>\", line 1, in <module>\n  File \"/usr/lib/python3.5/site-packages/hypothesis/core.py\", line 670, in find\n    raise NoSuchExample(get_pretty_function_description(condition))\nhypothesis.errors.NoSuchExample: No examples found of condition lambda x: <unknown>\n```\n\nHypothesis raises NoSuchExample to indicate that... well, that there's no such example.\n\nIn general you should be a little bit careful with filter and only use it to filter\nto conditions that are relatively hard to happen by accident. In this case it's fine\nbecause the filter condition only fails if our initial draw was a string consisting\nentirely of spaces, but if we'd e.g. tried the opposite and tried to filter to strings\nthat *only* had spaces, we'd have had a bad time of it and got a very slow and not\nvery useful test.\n\nAnyway, we now really do have a strategy that produces decent names for our projects.\nLets put this all together into a test that demonstrates that our names now have the\ndesired properties:\n\n```python\nfrom unicodedata import category\n\nfrom hypothesis import given\nfrom hypothesis.strategies import characters, text\n\nnames = (\n    text(characters(max_codepoint=1000, exclude_categories=(\"Cc\", \"Cs\")), min_size=1)\n    .map(lambda s: s.strip())\n    .filter(lambda s: len(s) > 0)\n)\n\n\n@given(names)\ndef test_names_match_our_requirements(name):\n    assert len(name) > 0\n    assert name == name.strip()\n    for c in name:\n        assert 1 <= ord(c) <= 1000\n        assert category(c) not in (\"Cc\", \"Cs\")\n```\n\nIt's not common practice to write tests for your strategies, but it can be helpful\nwhen trying to figure things out.\n\n### Dates and times\n\nHypothesis has date and time generation in a hypothesis.extra subpackage because it\nrelies on pytz to generate them, but other than that it works in exactly the same\nway as before:\n\n```pycon\n>>> from hypothesis.extra.datetime import datetimes\n>>> datetimes().example()\ndatetime.datetime(1642, 1, 23, 2, 34, 28, 148985, tzinfo=<DstTzInfo 'Antarctica/Mawson' zzz0:00:00 STD>)\n```\n\nLets constrain our dates to be UTC, because the sensible thing to do is to use UTC\ninternally and convert on display to the user:\n\n```pycon\n>>> datetimes(timezones=('UTC',)).example()\ndatetime.datetime(6820, 2, 4, 19, 16, 27, 322062, tzinfo=<UTC>)\n```\n\nWe can also constrain our projects to start in a reasonable range of years,\nas by default Hypothesis will cover the whole of representable history:\n\n```pycon\n>>> datetimes(timezones=('UTC',), min_year=2000, max_year=2100).example()\ndatetime.datetime(2084, 6, 9, 11, 48, 14, 213208, tzinfo=<UTC>)\n```\n\nAgain we can put together a test that checks this behaviour (though we have\nless code here so it's less useful):\n\n```python\nfrom hypothesis import given\nfrom hypothesis.extra.datetime import datetimes\n\nproject_date = datetimes(timezones=(\"UTC\",), min_year=2000, max_year=2100)\n\n\n@given(project_date)\ndef test_dates_are_in_the_right_range(date):\n    assert 2000 <= date.year <= 2100\n    assert date.tzinfo._tzname == \"UTC\"\n```\n\n### Putting it all together\n\nWe can now generate all the parts for our project definitions, but how do we\ngenerate a project?\n\nThe first thing to reach for is the *builds* function.\n\n```pycon\n\n>>> from hypothesis.strategies import builds\n>>> projects = builds(Project, name=names, start=project_date, end=project_date)\n>>> projects.example()\nProject 'd!#ñcJν' from 2091-06-22T06:57:39.050162+00:00 to 2057-06-11T02:41:43.889510+00:00\n```\n\nbuilds lets you take a set of strategies and feed their results as arguments to a\nfunction (or, in this case, class. Anything callable really) to create a new\nstrategy that works by drawing those arguments then passing them to the function\nto give you that example.\n\nUnfortunately, this isn't quite right:\n\n```pycon\n>>> find(projects, lambda x: x.start > x.end)\nProject '0' from 2000-01-01T00:00:00.000001+00:00 to 2000-01-01T00:00:00+00:00\n```\n\nProjects can start after they end when we use builds this way. One way to fix this would be\nto use filter():\n\n```pycon\n>>> projects = builds(Project, name=names, start=project_date, end=project_date).filter(\n...     lambda p: p.start < p.end)\n>>> find(projects, lambda x: x.start > x.end)\nTraceback (most recent call last):\n  File \"<stdin>\", line 1, in <module>\n  File \"/usr/lib/python3.5/site-packages/hypothesis/core.py\", line 670, in find\n    raise NoSuchExample(get_pretty_function_description(condition))\nhypothesis.errors.NoSuchExample: No examples found of condition lambda x: <unknown>\n```\n\nThis will work, but it starts to edge into the territory of where filter should be\navoided - about half of the initially generated examples will fail the filter.\n\nWhat we'll do instead is draw two dates and use whichever one is smallest as the\nstart, and whatever is largest at the end. This is hard to do with builds because\nof the dependence between the arguments, so instead we'll use builds' more advanced\ncousin, *composite*:\n\n```python\nfrom hypothesis import assume\nfrom hypothesis.strategies import composite\n\n\n@composite\ndef projects(draw):\n    name = draw(names)\n    date1 = draw(project_date)\n    date2 = draw(project_date)\n    assume(date1 != date2)\n    start = min(date1, date2)\n    end = max(date1, date2)\n    return Project(name, start, end)\n```\n\nThe idea of composite is you get passed a magic first argument 'draw' that you can\nuse to get examples out of a strategy. You then make as many draws as you want and\nuse these to return the desired data.\n\nYou can also use the *assume* function to discard the current call if you get yourself\ninto a state where you can't proceed or where it's easier to start again. In this case\nwe do that when we draw the same data twice.\n\n```pycon\n>>> projects().example()\nProject 'rĂ5ĠǓ#' from 2000-05-14T07:21:12.282521+00:00 to 2026-05-12T13:20:43.225796+00:00\n>>> find(projects(), lambda x: x.start > x.end)\nTraceback (most recent call last):\n  File \"<stdin>\", line 1, in <module>\n  File \"/usr/lib/python3.5/site-packages/hypothesis/core.py\", line 670, in find\n    raise NoSuchExample(get_pretty_function_description(condition))\nhypothesis.errors.NoSuchExample: No examples found of condition lambda x: <unknown>\n```\n\nNote that in all of our examples we're now writing projects() instead of projects. That's\nbecause composite returns a function rather than a strategy. Any arguments to your\ndefining function other than the first are also arguments to the one produced by composite.\n\nWe can now put together one final test that we got this bit right too:\n\n```python\n@given(projects())\ndef test_projects_end_after_they_started(project):\n    assert project.start < project.end\n```\n\n### Wrapping up\n\nThere's a lot more to Hypothesis's data generation than this, but hopefully it gives you\na flavour of the sort of things to try and the sort of things that are possible.\n\nIt's worth having a read of [the documentation](https://hypothesis.readthedocs.io/en/latest/data.html)\nfor this, and if you're still stuck then try asking [the community](https://hypothesis.readthedocs.io/en/latest/community.html)\nfor some help. We're pretty friendly.\n"
  },
  {
    "path": "website/content/2016-05-13-what-is-property-based-testing.md",
    "content": "---\ntags: non-technical, philosophy\ndate: 2016-05-14 09:00\ntitle: What is Property Based Testing?\nauthor: drmaciver\n---\n\nI get asked this a lot, and I write property based testing tools for a living, so you'd think\nI have a good answer to this, but historically I haven't. This is my attempt to fix that.\n\nHistorically the definition of property based testing has been \"The thing that\n[QuickCheck](../quickcheck-in-every-language/) does\". As\na working definition this has served pretty well, but the problem is that it makes us unable\nto distinguish what the essential features of property-based testing are and what are just\n[accidental features that appeared in the implementations that we're used to](../referential-transparency/).\n\nAs the author of a property based testing system which diverges quite a lot from QuickCheck,\nthis troubles me more than it would most people, so I thought I'd set out some of my thoughts on\nwhat property based testing is and isn't.\n\nThis isn't intended to be definitive, and it will evolve over time as my thoughts do, but\nit should provide a useful grounding for further discussion.\n\n<!--more-->\n\nThere are essentially two ways we can draw a boundary for something like this: We can go\nnarrow or we can go wide. i.e. we can restrict our definitions to things that look exactly\nlike QuickCheck, or things that are in the same general family of behaviour. My inclination\nis always to go wide, but I'm going to try to rein that in for the purpose of this piece.\n\nBut I'm still going to start by planting a flag. The following are *not* essential features\nof property based testing:\n\n1. [Referential Transparency](../referential-transparency/).\n2. Types\n3. Randomization\n4. The use of any particular tool or library\n\nAs evidence I present the following:\n\n1. Almost every property based testing library, including but not limited to Hypothesis and\n   QuickCheck (both Erlang and Haskell).\n2. The many successful property based testing systems for dynamic languages. e.g. Erlang\n   QuickCheck, test.check, Hypothesis.\n3. [SmallCheck](https://hackage.haskell.org/package/smallcheck). I have mixed feelings about\n   its effectiveness, but it's unambiguously property-based testing.\n4. It's very easy to hand-roll your own testing protocols for property-based testing of a\n   particular result. For example, I've [previously done this for testing a code formatter](\n   http://www.drmaciver.com/2015/03/27-bugs-in-24-hours/): Run it over a corpus (more on\n   whether running over a corpus \"really\" counts in a second) of Python files, check whether\n   the resulting formatted code satisfies PEP8. It's classic property-based testing with an\n   oracle.\n\nSo that provides us with a useful starting point of things that are definitely property based\ntesting. But you're never going to find a good definition by looking at only positive examples,\nso let's look at some cases where it's more arguable.\n\nFirst off, lets revisit that parenthetical question: Does just testing against a large corpus count?\n\nI'm going to go with \"probably\". I think if we're counting SmallCheck we need to count testing\nagainst a large corpus: If you take the first 20k outputs that would be generated by SmallCheck\nand just replay the test using those the first N of those each time, you're doing exactly the\nsame sort of testing. Similarly if you draw 20k outputs using Hypothesis and then just randomly\nsample from them each time.\n\nI think drawing from a small, fixed, corpus probably *doesn't* count. If you could feasibly\nwrite a property based test as 10 example based tests in line in your source code, it's\nprobably really just example based testing. This boundary is a bit, um, fuzzy though.\n\nOn which note, what about fuzzing?\n\nI have previously argued that fuzzing is just a form of property-based testing - you're testing\nthe property \"it doesn't crash\". I think I've reversed my opinion on this. In particular, I think\n[the style of testing I advocate for getting started with Hypothesis](../getting-started-with-hypothesis/), *probably* doesn't\ncount as property based testing.\n\nI'm unsure about this boundary. The main reason I'm drawing it here is that they do feel like\nthey have a different character - property based testing requires you to reason about how your\nprogram should behave, while fuzzing can just be applied to arbitrary programs with minimal\nunderstanding of their behaviour - and also that fuzzing feels somehow more fundamental.\n\nBut you can certainly do property based testing using fuzzing tools, in the same way that you\ncan do it with hand-rolled property based testing systems - I could have taken my Python formatting\ntest above, added [python-afl](http://jwilk.net/software/python-afl) to the mix, and\nthat would still be property based testing.\n\nConversely, you can do fuzzing with property-based testing tools: If fuzzing is not property\nbased testing then not all tests using Hypothesis, QuickCheck, etc. are property based tests.\nI'm actually OK with that. There's a long tradition of testing tools being used outside their\ndomain - e.g. most test frameworks originally designed as unit testing tools end up getting\nbeing used for the whole gamut of testing.\n\nSo with that in mind, lets provide a definition of fuzzing that I'd like to use:\n\n> Fuzzing is feeding a piece of code (function, program, etc.) data from a large corpus, possibly\n> dynamically generated, possibly dependent on the results of execution on previous data, in\n> order to see whether it fails.\n\nThe definitions of \"data\" and \"whether it fails\" will vary from fuzzer to fuzzer - some fuzzers\nwill generate only binary data, some fuzzers will generate more structured data. Some fuzzers\nwill look for a process crash, some might just look for a function returning false.\n\n(Often definitions of fuzzing focus on \"malformed\" data. I think this is misguided and fails\nto consider a lot of things that people would obviously consider fuzzers. e.g. [CSmith](https://embed.cs.utah.edu/csmith/)\nis certainly a type of fuzzer but deliberately only generates well formed C programs).\n\nAnd given that definition, I think I can now provide a definition of property-based testing:\n\n> Property based testing is the construction of tests such that, when these tests are fuzzed,\n> failures in the test reveal problems with the system under test that could not have been\n> revealed by direct fuzzing of that system.\n\n(If you feel strongly that fuzzing *should* count as property-based testing you can just drop\nthe 'that could not have been etc.' part. I'm on the fence about it myself.)\n\nThese extra modes of failure then constitute the properties that we're testing.\n\nI think this works pretty well at capturing what we're doing with property based testing. It's\nnot perfect, but I'm pretty happy with it. One of the things I particularly like is that it makes\nit clear that property-based testing is what *you* do, not what the computer does. The part\nthat the computer does is \"just fuzzing\".\n\nUnder this point of view, a property-based testing library is really two parts:\n\n1. A fuzzer.\n2. A library of tools for making it easy to construct property-based tests using that fuzzer.\n\nHypothesis is very explicitly designed along these lines - the core of it is a structured\nfuzzing library called Conjecture - which suggests that I may have a bit of bias here, but\nI still feel that it captures the behaviour of most other property based testing systems\nquite well, and provides quite a nice middle ground between the wider definition that I\nwanted and the more tightly focused definition that QuickCheck orients people around.\n"
  },
  {
    "path": "website/content/2016-05-26-exploring-voting-with-hypothesis.md",
    "content": "---\ntags: python, technical, example\ndate: 2016-05-26 11:00\ntitle: Exploring Voting Systems with Hypothesis\nauthor: drmaciver\n---\n\nHypothesis is, of course, a library for writing tests.\n\nBut from an *implementation* point of view this is hardly noticeable.\nReally it's a library for constructing and exploring data and using it\nto prove or disprove hypotheses about it. It then has a small testing\nlibrary built on top of it.\n\nIt's far more widely used as a testing library, and that's really where\nthe focus of its development lies, but with the *find* function you can\nuse it just as well to explore your data interactively.\n\nIn this article we'll go through an example of doing this, by using it\nto take a brief look at one of my other favourite subjects: Voting\nsystems.\n\n<!--more-->\n\nWe're going to focus entirely on single winner preferential voting\nsystems: You have a set of candidates, and every voter gives a complete\nordering of the candidates from their favourite to their least\nfavourite. The voting system then tries to select a single candidate and\ndeclare them the winner.\n\nThe general Python interface for a voting system we'll use is things\nthat look like the following:\n\n```python\ndef plurality_winner(election):\n    counts = Counter(vote[0] for vote in election)\n    alternatives = candidates_for_election(election)\n    winning_score = max(counts.values())\n    winners = [c for c, v in counts.items() if v == winning_score]\n    if len(winners) > 1:\n        return None\n    else:\n        return winners[0]\n```\n\nThat is, they take a list of individual votes, each expressed\nas a list putting the candidates in order, and return a candidate that\nis an unambiguous winner or None in the event of a tie.\n\nThe above implements plurality voting, what most people might think of\nas \"normal voting\": The candidate with the most first preference votes\nwins.\n\nThe other main voting system we'll consider is Instant Runoff Voting (\nwhich you might know under the name \"Alternative Vote\" if you follow\nBritish politics):\n\n```python\ndef irv_winner(election):\n    candidates = candidates_for_election(election)\n    while len(candidates) > 1:\n        scores = Counter()\n        for vote in election:\n            for c in vote:\n                if c in candidates:\n                    scores[c] += 1\n                    break\n        losing_score = min(scores[c] for c in candidates)\n        candidates = [c for c in candidates if scores[c] > losing_score]\n    if not candidates:\n        return None\n    else:\n        return candidates[0]\n```\n\nIn IRV, we run the vote in multiple rounds until we've eliminated all\nbut one candidate. In each round, we give each candidate a score which\nis the number of voters who have ranked that candidate highest amongst\nall the ones remaining. The candidates with the joint lowest score\ndrop out.\n\nAt the end, we'll either have either zero or one candidates remaining (\nwe can have zero if all candidates are tied for joint lowest score at\nsome point). If we have zero, that's a draw. If we have one, that's a\nvictory.\n\nIt seems pretty plausible that these would not produce the same answer\nall the time (it would be surprising if they did!), but it's maybe not\nobvious how you would go about constructing an example that shows it.\n\nFortunately, we don't have to because Hypothesis can do it for us!\n\nWe first create a strategy which generates elections, using Hypothesis's\ncomposite decorator:\n\n```python\nimport hypothesis.strategies as st\n\n\n@st.composite\ndef election(draw):\n    candidates = list(range(draw(st.integers(2, 10))))\n    return draw(st.lists(st.permutations(candidates), min_size=1))\n```\n\nThis first draws the set of candidates as a list of integers of size\nbetween 2 and 10 (it doesn't really matter what our candidates are as\nlong as they're distinct, so we use integers for simplicity). It then\ndraws an election as lists of permutations of those candidates, as we\ndefined it above.\n\nWe now write a condition to look for:\n\n```python\ndef differing_without_ties(election):\n    irv = irv_winner(election)\n    if irv is None:\n        return False\n    plurality = plurality_winner(election)\n    if plurality is None:\n        return False\n    return irv != plurality\n```\n\nThat is, we're interested in elections where neither plurality nor IRV\nresulted in a tie, but they resulted in distinct candidates winning.\n\nWe can now run this in the console:\n\n```\n>>> from hypothesis import find\n>>> import voting as v\n>>> distinct = find(v.election(), v.differing_without_ties)\n>>> distinct\n[[0, 1, 2],\n [0, 1, 2],\n [1, 0, 2],\n [2, 1, 0],\n [0, 1, 2],\n [0, 1, 2],\n [1, 0, 2],\n [1, 0, 2],\n [2, 1, 0]]\n```\n\nThe example is a bit large, mostly because we insisted on there being\nno ties: If we'd broken ties arbitrarily (e.g. preferring the lower\nnumbered candidates) we could have found a smaller one. Also, in some\nruns Hypothesis ends up finding a slightly smaller election but with\nfour candidates instead of three.\n\nWe can check to make sure that these really do give different results:\n\n```\n>>> v.irv_winner(distinct)\n1\n\n>>> v.plurality_winner(distinct)\n0\n```\n\nThere are a lot of other interesting properties of voting systems to\nexplore, but this is an article about Hypothesis rather than one about\nvoting, so I'll stop here. However the interested reader might want to\ntry to build on this to:\n\n1. Find an election which has a [Condorcet Cycle](https://en.wikipedia.org/wiki/Voting_paradox)\n2. Find elections in which the majority prefers the plurality winner to\n   the IRV winner and vice versa.\n3. Use @given rather than find and write some tests verifying some of\n   [the classic properties of election systems](https://en.wikipedia.org/wiki/Voting_system#Evaluating_voting_systems_using_criteria).\n\nAnd the reader who isn't that interested in voting systems might still\nwant to think about how this could be useful in other areas: Development\nis often a constant series of small experiments and, while testing is\noften a good way to perform them, sometimes you just have a more\nexploratory \"I wonder if...?\" question to answer, and it can be\nextremely helpful to be able to bring Hypothesis to bear there too.\n"
  },
  {
    "path": "website/content/2016-05-29-testing-optimizers-with-hypothesis.md",
    "content": "---\ntags: technical, python, example, properties\ndate: 2016-05-29 21:00\ntitle: Testing Optimizers\nauthor: drmaciver\nredirect_from: /articles/testing-optimizers\n---\n\nWe've [previously looked into testing performance optimizations](../testing-performance-optimizations/)\nusing Hypothesis, but this\narticle is about something quite different: It's about testing code\nthat is designed to optimize a value. That is, you have some function\nand you want to find arguments to it that maximize (or minimize) its\nvalue.\n\nAs well as being an interesting subject in its own right, this will also\nnicely illustrate the use of Hypothesis's data() functionality, which\nallows you to draw more data after the test has started, and will\nintroduce a useful general property that can improve your testing in\na much wider variety of settings.\n\n<!--more-->\n\nWe'll use [the Knapsack Packing Problem](https://en.wikipedia.org/wiki/Knapsack_problem)\nas our example optimizer. We'll use the greedy approximation algorithm\ndescribed in the link, and see if Hypothesis can show us that it's\nmerely an approximation and not in fact optimal.\n\n```python\ndef pack_knapsack(items, capacity):\n    \"\"\"Given items as a list [(value, weight)], with value and weight\n    strictly positive integers, try to find a maximum value subset of\n    items with total weight <= capacity\"\"\"\n    remaining_capacity = capacity\n    result = []\n\n    # Sort in order of decreasing value per unit weight, breaking\n    # ties by taking the lowest weighted items first.\n    items = sorted(items, key=lambda x: (x[1] / x[0], x[1]))\n    for value, weight in items:\n        if weight <= remaining_capacity:\n            result.append((value, weight))\n            remaining_capacity -= weight\n    return result\n```\n\nSo how are we going to test this?\n\nIf we had another optimizer we could test by comparing the two results,\nbut we don't, so we need to figure out properties it should satisfy in\nthe absence of that.\n\nThe trick we will used to test this is to look for responses to change.\n\nThat is, we will run the function, we will make a change to the data\nthat should cause the function's output to change in a predictable way,\nand then we will run the function again and see if it did.\n\nBut how do we figure out what changes to make?\n\nThe key idea is that we will look at the output of running the optimizer\nand use that to guide what changes we make. In particular we will test\nthe following two properties:\n\n1. If we remove an item that was previously chosen as part of the\n   optimal solution, this should not improve the score.\n2. If we add an extra copy of an item that was previously chosen as part\n   of the optimal solution, this should not make the score worse.\n\nIn the first case, any solution that is found when running with one\nfewer item would also be a possible solution when running with the full\nset, so if the optimizer is working correctly then it should have found\nthat one if it were an improvement.\n\nIn the second case, the opposite is true: Any solution that was\npreviously available is still available, so if the optimizer is working\ncorrectly it can't find a worse one than it previously found.\n\nThe two tests look very similar:\n\n```python\nfrom hypothesis import Verbosity, assume, given, settings, strategies as st\n\n\ndef score_items(items):\n    return sum(value for value, _ in items)\n\n\nPositiveIntegers = st.integers(min_value=1, max_value=10)\nItems = st.lists(st.tuples(PositiveIntegers, PositiveIntegers), min_size=1)\nCapacities = PositiveIntegers\n\n\n@given(Items, Capacities, st.data())\ndef test_cloning_an_item(items, capacity, data):\n    original_solution = pack_knapsack(items, capacity)\n    assume(original_solution)\n    items.append(data.draw(st.sampled_from(original_solution)))\n    new_solution = pack_knapsack(items, capacity)\n    assert score_items(new_solution) >= score_items(original_solution)\n\n\n@given(Items, Capacities, st.data())\ndef test_removing_an_item(items, capacity, data):\n    original_solution = pack_knapsack(items, capacity)\n    assume(original_solution)\n    item = data.draw(st.sampled_from(original_solution))\n    items.remove(item)\n    new_solution = pack_knapsack(items, capacity)\n    assert score_items(new_solution) <= score_items(original_solution)\n```\n\n(The max_value parameter for integers is inessential but results in\nnicer example quality).\n\nThe *data* strategy simply provides an object you can use for drawing\nmore data interactively during the test. This allows us to make our\nchoices dependent on the output of the function when we run it. The\ndraws made will be printed as additional information in the case of a\nfailing example.\n\nIn fact, both of these tests fail:\n\n```\n\nFalsifying example: test_cloning_an_item(items=[(1, 1), (1, 1), (2, 5)], capacity=7, data=data(...))\nDraw 1: (1, 1)\n\n```\n\nIn this case what happens is that when Hypothesis clones an item of\nweight and value 1, the algorithm stuffs its knapsack with all three\n(1, 1) items, at which point it has spare capacity but no remaining\nitems that are small enough to fit in it.\n\n```\n\nFalsifying example: test_removing_a_chosen_item(items=[(1, 1), (2, 4), (1, 2)], capacity=6, data=data(...))\nDraw 1: (1, 1)\n\n```\n\nIn this case what happens is the opposite: Previously the greedy\nalgorithm was reaching for the (1, 1) item as the most appealing because\nit had the highest value to weight ratio, but by including it it only\nhad space for one of the remaining two. When Hypothesis removed that\noption, it could fit the remaining two items into its knapsack and thus\nscored a higher point.\n\nIn this case these failures were more or less expected: As described in\nthe Wikipedia link, for the relatively small knapsacks we're exploring\nhere the greedy approximation algorithm turns out to in fact be quite\nbad, and Hypothesis can easily expose that.\n\nThis technique however can be more widely applied: e.g. You can try\nchanging permissions and settings on a user and asserting that they\nalways have more options, or increasing the capacity of a subsystem and\nseeing that it is always allocated more tasks.\n"
  },
  {
    "path": "website/content/2016-05-31-looking-for-guest-posts.md",
    "content": "---\ntags: non-technical, news\ndate: 2016-05-29 21:00\ntitle: Guest Posts Welcome\nauthor: drmaciver\n---\n\nI would like to see more posters on the hypothesis.works blog. I'm\nparticularly interested in experience reports from people who use\nHypothesis in the wild. Could that be you?\n\n<!--more-->\n\nDetails of how to guest post on here:\n\n1. This site is [a Jekyll site on GitHub](https://github.com/HypothesisWorks/HypothesisWorks.github.io).\n   To add a post, create a markdown file in the _posts directory with the\n   appropriate structure and send a pull request.\n2. You will want to add an entry for yourself to [the authors data file](https://github.com/HypothesisWorks/HypothesisWorks.github.io/blob/master/_data/authors.yml)\n3. You of course retain all copyright to your work. All you're granting is the right to publish it on this site.\n\nI'd particularly like to hear from:\n\n* People who work in QA\n* People using the Django support\n* People using Hypothesis for heavily numerical work\n* People whose first experience of property based testing was via Hypothesis\n* People who would like to write about another property based testing system (\n  and ideally to compare it to Hypothesis)\n\nBut I'd also like to hear from anyone else who would like to write\nsomething about Hypothesis, or property based testing in general: Whether\nit's an experience report, a cool trick you figured out, an introductory\narticle to Hypothesis, etc.\n"
  },
  {
    "path": "website/content/2016-06-05-incremental-property-based-testing.md",
    "content": "---\ntags: intro, python, technical, properties\ndate: 2016-06-05 16:00\ntitle: Evolving toward property-based testing with Hypothesis\nauthor: jml\n---\n\nMany people are quite comfortable writing ordinary unit tests, but feel a bit\nconfused when they start with property-based testing. This post shows how two\nordinary programmers started with normal Python unit tests and nudged them\nincrementally toward property-based tests, gaining many advantages on the way.\n\n<!--more-->\n\nBackground\n----------\n\nI used to work on a command-line tool with an interface much like git's. It\nhad a repository, and within that repository you could create branches and\nswitch between them. Let's call the tool `tlr`.\n\nIt was supposed to behave something like this:\n\nList branches:\n\n    $ tlr branch\n    foo\n    * master\n\nSwitch to an existing branch:\n\n    $ tlr checkout foo\n    * foo\n    master\n\nCreate a branch and switch to it:\n\n    $ tlr checkout -b new-branch\n    $ tlr branch\n    foo\n    master\n    * new-branch\n\nEarly on, my colleague and I found a bug: when you created a new branch with\n`checkout -b` it wouldn't switch to it. The behavior looked something like\nthis:\n\n    $ tlr checkout -b new-branch\n    $ tlr branch\n    foo\n    * master\n    new-branch\n\nThe previously active branch (in this case, `master`) stayed active, rather\nthan switching to the newly-created branch (`new-branch`).\n\nBefore we fixed the bug, we decided to write a test. I thought this would be a\ngood chance to start using Hypothesis.\n\nWriting a simple test\n---------------------\n\nMy colleague was less familiar with Hypothesis than I was, so we started with\na plain old Python unit test:\n\n```python\ndef test_checkout_new_branch(self):\n    \"\"\"Checking out a new branch makes it the current active branch.\"\"\"\n    tmpdir = FilePath(self.mktemp())\n    tmpdir.makedirs()\n    repo = Repository.initialize(tmpdir.path)\n    repo.checkout(\"new-branch\", create=True)\n    self.assertEqual(\"new-branch\", repo.get_active_branch())\n```\n\nThe first thing to notice here is that the string `\"new-branch\"` is not\nactually relevant to the test. It's just a value we picked to exercise the\nbuggy code. The test should be able to pass with *any valid branch name*.\n\nEven before we started to use Hypothesis, we made this more explicit by making\nthe branch name a parameter to the test:\n\n```python\ndef test_checkout_new_branch(self, branch_name=\"new-branch\"):\n    tmpdir = FilePath(self.mktemp())\n    tmpdir.makedirs()\n    repo = Repository.initialize(tmpdir.path)\n    repo.checkout(branch_name, create=True)\n    self.assertEqual(branch_name, repo.get_active_branch())\n```\n\n(For brevity, I'll elide the docstring from the rest of the code examples)\n\nWe never manually provided the `branch_name` parameter, but this change made\nit more clear that the test ought to pass regardless of the branch name.\n\nIntroducing Hypothesis\n----------------------\n\nOnce we had a parameter, the next thing was to use Hypothesis to provide the\nparameter for us. First, we imported Hypothesis:\n\n```python\nfrom hypothesis import given, strategies as st\n```\n\nAnd then made the simplest change to our test to actually use it:\n\n```python\n@given(branch_name=st.just(\"new-branch\"))\ndef test_checkout_new_branch(self, branch_name):\n    tmpdir = FilePath(self.mktemp())\n    tmpdir.makedirs()\n    repo = Repository.initialize(tmpdir.path)\n    repo.checkout(branch_name, create=True)\n    self.assertEqual(branch_name, repo.get_active_branch())\n```\n\nHere, rather than providing the branch name as a default argument value, we\nare telling Hypothesis to come up with a branch name for us using the\n`just(\"new-branch\")`\n[strategy](https://hypothesis.readthedocs.io/en/latest/data.html). This\nstrategy will always come up with `\"new-branch\"`, so it's actually no\ndifferent from what we had before.\n\nWhat we actually wanted to test is that any valid branch name worked. We\ndidn't yet know how to generate any valid branch name, but using a\ntime-honored tradition we pretended that we did:\n\n```python\ndef valid_branch_names():\n    \"\"\"Hypothesis strategy to generate arbitrary valid branch names.\"\"\"\n    # TODO: Improve this strategy.\n    return st.just(\"new-branch\")\n\n\n@given(branch_name=valid_branch_names())\ndef test_checkout_new_branch(self, branch_name):\n    tmpdir = FilePath(self.mktemp())\n    tmpdir.makedirs()\n    repo = Repository.initialize(tmpdir.path)\n    repo.checkout(branch_name, create=True)\n    self.assertEqual(branch_name, repo.get_active_branch())\n```\n\nEven if we had stopped here, this would have been an improvement. Although the\nHypothesis version of the test doesn't have any extra power over the vanilla\nversion, it is more explicit about what it's testing, and the\n`valid_branch_names()` strategy can be reused by future tests, giving us a\nsingle point for improving the coverage of many tests at once.\n\nExpanding the strategy\n----------------------\n\nIt's only when we get Hypothesis to start generating our data for us that we\nreally get to take advantage of its bug finding power.\n\nThe first thing my colleague and I tried was:\n\n```python\ndef valid_branch_names():\n    return st.text()\n```\n\nBut that failed pretty hard-core.\n\nTurns out branch names were implemented as symlinks on disk, so valid branch\nname has to be a valid file name on whatever filesystem the tests are running\non. This at least rules out empty names, `\".\"`, `\"..\"`, very long names, names\nwith slashes in them, and probably others (it's actually\n[really complicated](https://en.wikipedia.org/wiki/Filename#Comparison_of_filename_limitations)).\n\nHypothesis had made something very clear to us: neither my colleague nor I\nactually knew what a valid branch name should be. None of our interfaces\ndocumented it, we had no validators, no clear ideas for rendering & display,\nnothing. We had just been assuming that people would pick good, normal,\nsensible names.\n\nIt was as if we had suddenly gained the benefit of extensive real-world\nend-user testing, just by calling the right function. This was:\n\n 1. Awesome. We've found bugs that our users won't.\n 2. Annoying. We really didn't want to fix this bug right now.\n\nIn the end, we compromised and implemented a relatively conservative strategy\nto simulate the good, normal, sensible branch names that we expected:\n\n```python\nfrom string import ascii_lowercase\n\nVALID_BRANCH_CHARS = ascii_lowercase + \"_-.\"\n\n\ndef valid_branch_names():\n    # TODO: Handle unicode / weird branch names by rejecting them early, raising nice errors\n    # TODO: How do we handle case-insensitive file systems?\n    return st.text(alphabet=VALID_BRANCH_CHARS, min_size=1, max_size=112)\n```\n\nNot ideal, but *much* more extensive than just hard-coding `\"new-branch\"`, and\nmuch clearer communication of intent.\n\nAdding edge cases\n-----------------\n\nThere's one valid branch name that this strategy *could* generate, but\nprobably won't: `master`. If we left the test just as it is, then one time in\na hojillion the strategy would generate `\"master\"` and the test would fail.\n\nRather than waiting on chance, we encoded this in the `valid_branch_names`\nstrategy, to make it more likely:\n\n```python\ndef valid_branch_names():\n    return st.text(alphabet=letters, min_size=1, max_size=112).map(\n        lambda t: t.lower()\n    ) | st.just(\"master\")\n```\n\nWhen we ran the tests now, they failed with an exception due to the branch\n`master` already existing. To fix this, we used `assume`:\n\n```python\nfrom hypothesis import assume\n\n\n@given(branch_name=valid_branch_names())\ndef test_checkout_new_branch(self, branch_name):\n    assume(branch_name != \"master\")\n    tmpdir = FilePath(self.mktemp())\n    tmpdir.makedirs()\n    repo = Repository.initialize(tmpdir.path)\n    repo.checkout(branch_name, create=True)\n    self.assertEqual(branch_name, repo.get_active_branch())\n```\n\nWhy did we add `master` to the valid branch names if we were just going to\nexclude it anyway? Because when other tests say \"give me a valid branch name\",\nwe want *them* to make the decision about whether `master` is appropriate or\nnot. Any future test author will be compelled to actually think about whether\nhandling `master` is a thing that they want to do. That's one of the great\nbenefits of Hypothesis: it's like having a rigorous design critic in your\nteam.\n\nGoing forward\n-------------\n\nWe stopped there, but we need not have. Just as the test should have held for\nany branch, it should also hold for any repository. We were just creating an\nempty repository because it was convenient for us.\n\nIf we were to continue, the next step would be to [write a `repositories()`\nfunction to generate repositories]({% post_url 2016-05-11-generating-the-right-data/)\nwith more varied contents, commit histories, and existing branches.\nThe test might then look something like this:\n\n```python\n@given(repo=repositories(), branch_name=valid_branch_names())\ndef test_checkout_new_branch(self, repo, branch_name):\n    \"\"\"\n    Checking out a new branch results in it being the current active\n    branch.\n    \"\"\"\n    assume(branch_name not in repo.get_branches())\n    repo.checkout(branch_name, create=True)\n    self.assertEqual(branch_name, repo.get_active_branch())\n```\n\nThis is about as close to a bona fide \"property\" as you're likely to get in\ncode that isn't a straight-up computer science problem: if you create and\nswitch to a branch that doesn't already exist, the new active branch is the\nnewly created branch.\n\nWe got there not by sitting down and thinking about the properties of our\nsoftware in the abstract, nor by necessarily knowing much about property-based\ntesting, but rather by incrementally taking advantage of features of Python\nand Hypothesis. On the way, we discovered and, umm, contained a whole class of\nbugs, and we made sure that all future tests would be heaps more powerful.\nWin.\n"
  },
  {
    "path": "website/content/2016-06-13-testing-configuration-parameters.md",
    "content": "---\ntags: technical, python, properties\ndate: 2016-06-13 00:00\ntitle: Testing Configuration Parameters\nauthor: drmaciver\n---\n\nA lot of applications end up growing a complex configuration system,\nwith a large number of different knobs and dials you can turn to change\nbehaviour. Some of these are just for performance tuning, some change\noperational concerns, some have other functions.\n\nTesting these is tricky. As the number of parameters goes up, the number\nof possible configuration goes up exponentially. Manual testing of the\ndifferent combinations quickly becomes completely unmanageable, not\nto mention extremely tedious.\n\nFortunately, this is somewhere where property-based testing in general\nand Hypothesis in particular can help a lot.\n\n<!--more-->\n\nConfiguration parameters almost all have one thing in common: For the\nvast majority of things, they shouldn't change the behaviour. A\nconfiguration parameter is rarely going to be a complete reskin of your\napplication.\n\nThis means that they are relatively easy to test with property-based\ntesting. You take an existing test - either one that is already using\nHypothesis or a normal example based test - and you vary some\nconfiguration parameters and make sure the test still passes.\n\nThis turns out to be remarkably effective. Here's an example where I\nused this technique and found some bugs in the [Argon2](\nhttps://github.com/P-H-C/phc-winner-argon2) password hashing library,\nusing [Hynek](https://hynek.me/)'s\n[CFFI based bindings](https://github.com/hynek/argon2_cffi).\n\nThe idea of password hashing is straightforward: Given a password, you\ncan create a hash against which the password can be verified without\never storing the password (after all, you're not storing passwords in\nplain text on your servers, right?). Although straightforward to\ndescribe, there's a lot of difficulty in making a good implementation\nof this. Argon2 is a fairly recent one which won [the Password Hashing\nCompetition](https://password-hashing.net/) so should be fairly good.\n\nWe can verify that hashing works correctly fairly immediately using\nHypothesis:\n\n```python\nfrom argon2 import PasswordHasher\n\nfrom hypothesis import given, strategies as st\n\n\nclass TestPasswordHasherWithHypothesis:\n    @given(password=st.text())\n    def test_a_password_verifies(self, password):\n        ph = PasswordHasher()\n        hash = ph.hash(password)\n        assert ph.verify(hash, password)\n```\n\nThis takes an arbitrary text password, hashes it and verifies it against\nthe generated hash.\n\nThis passes. So far, so good.\n\nBut as you probably expected from its context here, argon2 has quite\na lot of different parameters to it. We can expand the test to vary\nthem and see what happens:\n\n```python\nfrom argon2 import PasswordHasher\n\nfrom hypothesis import assume, given, strategies as st\n\n\nclass TestPasswordHasherWithHypothesis:\n    @given(\n        password=st.text(),\n        time_cost=st.integers(1, 10),\n        parallelism=st.integers(1, 10),\n        memory_cost=st.integers(8, 2048),\n        hash_len=st.integers(12, 1000),\n        salt_len=st.integers(8, 1000),\n    )\n    def test_a_password_verifies(\n        self,\n        password,\n        time_cost,\n        parallelism,\n        memory_cost,\n        hash_len,\n        salt_len,\n    ):\n        assume(parallelism * 8 <= memory_cost)\n        ph = PasswordHasher(\n            time_cost=time_cost,\n            parallelism=parallelism,\n            memory_cost=memory_cost,\n            hash_len=hash_len,\n            salt_len=salt_len,\n        )\n        hash = ph.hash(password)\n        assert ph.verify(hash, password)\n```\n\n\nThese parameters are mostly intended to vary the difficulty of\ncalculating the hash. Honestly I'm not entirely sure what all of them\ndo. Fortunately for the purposes of writing this test, understanding is\noptional.\n\nIn terms of how I chose the specific strategies to get there, I just\npicked some plausible looking parameters ranges and adjusted them until\nI wasn't getting validation errors (I did look for documentation, I\npromise). The assume() call comes from reading the argon2 source to try\nto find out what the valid range of parallelism was.\n\nThis ended up finding\n[two bugs](https://github.com/hynek/argon2_cffi/issues/4), which I duly\nreported to Hynek, but they actually turned out to be upstream bugs!\n\nIn both cases, a password would no longer validate against itself:\n\n\n```\nFalsifying example: test_a_password_verifies(\n    password='', time_cost=1, parallelism=1, memory_cost=8, hash_len=4,\n    salt_len=8,\n)\n```\n\n```\nFalsifying example: test_a_password_verifies(\n    password='', time_cost=1, parallelism=1, memory_cost=8,\n    hash_len=513, salt_len=8\n)\n```\n\n(I found the second one by manually determining that the first bug\nhappened whenever salt_len < 12 and manually ruling that case out).\n\nOne interesting thing about both of these bugs is that they're actually\nnot bugs in the Python library but are both downstream bugs. I hadn't\nset out to do that when I wrote these tests, but it nicely validates\nthat Hypothesis is rather useful for testing C libraries as well as\nPython, given how easy they are to bind to with CFFI.\n"
  },
  {
    "path": "website/content/2016-06-30-tests-as-complete-specifications.md",
    "content": "---\ntags: technical, python, properties, intro\ndate: 2016-06-30 00:00\ntitle: Testing as a Complete Specification\nauthor: drmaciver\n---\n\nSometimes you're lucky enough to have problems where the result is\ncompletely specified by a few simple properties.\n\nThis doesn't necessarily correspond to them being easy! Many such\nproblems are actually extremely fiddly to implement.\n\nIt does mean that they're easy to *test* though. Lets see how.\n\n<!--more-->\n\nLet's look at the problem of doing a binary search. Specifically we'll\nlook at a left biased binary search: Given a sorted list and some value,\nwe want to find the smallest index that we can insert that value at and\nstill have the result be sorted.\n\nSo we've got the following properties:\n\n1. binary_search must always return a valid index to insert the value\n   at.\n2. If we insert the value at that index the result must be sorted.\n3. If we insert the value at any *smaller* index, the result must *not*\n   be sorted.\n\nUsing Hypothesis we can write down tests for all these properties:\n\n```python\nfrom hypothesis import given, strategies as st\n\n\n@given(lists(integers()).map(sorted), integers())\ndef test_binary_search_gives_valid_index(ls, v):\n    i = binary_search(ls, v)\n    assert 0 <= i <= len(ls)\n\n\n@given(lists(integers()).map(sorted), integers())\ndef test_inserting_at_binary_search_remains_sorted(ls, v):\n    i = binary_search(ls, v)\n    ls.insert(i, v)\n    assert sorted(ls) == ls\n\n\n@given(lists(integers()).map(sorted), integers())\ndef test_inserting_at_smaller_index_gives_unsorted(ls, v):\n    for i in range(binary_search(ls, v)):\n        ls2 = list(ls)\n        ls2.insert(i, v)\n        assert sorted(ls2) != ls\n```\n\nIf these tests pass, our implementation must be perfectly correct,\nright? They capture the specification of the binary_search function\nexactly, so they should be enough.\n\nAnd they mostly are, but they suffer from one problem that will\nsometimes crop up with property-based testing: They don't hit all bugs\nwith quite high enough probability.\n\nThis is the difference between testing and mathematical proof: A proof\nwill guarantee that these properties *always* hold, while a test can\nonly guarantee that they hold in the areas that it's checked. A test\nusing Hypothesis will check a much wider area than most hand-written\ntests, but it's still limited to a finite set of examples.\n\nLets see how this can cause us problems. Consider the following\nimplementation of binary search:\n\n```python\ndef binary_search(list, value):\n    if not list:\n        return 0\n    if value > list[-1]:\n        return len(list)\n    if value <= list[0]:\n        return 0\n    lo = 0\n    hi = len(list) - 1\n    while lo + 1 < hi:\n        mid = (lo + hi) // 2\n        pivot = list[mid]\n        if value < pivot:\n            hi = mid\n        elif value == pivot:\n            return mid\n        else:\n            lo = mid\n    return hi\n```\n\nThis implements the common check that if our pivot index ever has\nexactly the right value we return early there. Unfortunately in this\ncase that check is wrong: It violates the property that we should\nalways find the *smallest* property, so the third test should fail.\n\nAnd sure enough, if you run the test enough times it eventually *does*\nfail:\n\n```\nFalsifying example: test_inserting_at_smaller_index_gives_unsorted(\n    ls=[0, 1, 1, 1, 1], v=1\n )\n```\n\n(you may also get (ls=[-1, 0, 0, 0, 0], v=0))\n\nHowever when I run it it usually *doesn't* fail the first time. It\nusually takes somewhere between two and five runs before it fails. This\nis because in order to trigger this behaviour being wrong you need\nquite specific behaviour: value needs to appear in ls at least\ntwice, and it needs to do so in such a way that one of the indices where\nit appears that is *not* the first one gets chosen as mid at some\npoint in the process. Hypothesis does some things that boost the\nchances of this happening, but they don't boost it *that* much.\n\nOf course, once it starts failing Hypothesis's test database kicks in,\nand the test keeps failing until the bug is fixed, but low probability\nfailures are still annoying because they move the point at which you\ndiscover the problem further away from when you introduced it. This is\nespecially true when you're using [stateful testing\n](../rule-based-stateful-testing/),\nbecause the search space is so large that there are a lot of low\nprobability bugs.\n\nFortunately there's an easy fix for this case: You can write additional\ntests that are more likely to discover bugs because they are less\nsensitively dependent on the example chosen by Hypothesis to exhibit\ninteresting behaviours.\n\nConsider the following test:\n\n```python\n@given(lists(integers()).map(sorted), integers())\ndef test_inserting_at_result_point_and_searching_again(ls, v):\n    i = binary_search(ls, v)\n    ls.insert(i, v)\n    assert binary_search(ls, v) == i\n```\n\nThe idea here is that by doing a search, inserting the value at that\nindex, and searching again we cannot have moved the insert point:\nInserting there again would still result in a sorted list, and inserting\nany earlier would still have resulted in an unsorted list, so this must\nstill be the same insert point (this should remind you a bit of\n[the approach for testing optimizers we used before](\n../testing-optimizers-with-hypothesis/)\n).\n\nThis test fails pretty consistently because it doesn't rely nearly so\nmuch on finding duplicates: Instead it deliberately creates them in a\nplace where they are likely to be problematic.\n\nSo, in conclusion:\n\n1. When the problem is fully specified, this gives you a natural source\n   of tests that you can easily write using Hypothesis.\n2. However this is where your tests should *start* rather than finish,\n   and you still need to think about other interesting ways to test your\n   software.\n"
  },
  {
    "path": "website/content/2016-07-04-calculating-the-mean.md",
    "content": "---\ntags: technical, python, properties, intro\ndate: 2016-07-04 00:00\ntitle: Calculating the mean of a list of numbers\nauthor: drmaciver\n---\n\nConsider the following problem:\n\nYou have a list of floating point numbers. No nasty tricks - these\naren't NaN or Infinity, just normal \"simple\" floating point numbers.\n\nNow: Calculate the mean (average). Can you do it?\n\nIt turns out this is a hard problem. It's hard to get it even *close* to\nright. Lets see why.\n\n<!--more-->\n\nConsider the following test case using Hypothesis:\n\n```python\nfrom hypothesis import given\nfrom hypothesis.strategies import floats, lists\n\n\n@given(lists(floats(allow_nan=False, allow_infinity=False), min_size=1))\ndef test_mean_is_within_reasonable_bounds(ls):\n    assert min(ls) <= mean(ls) <= max(ls)\n```\n\nThis isn't testing much about correctness, only that the value of the\nmean is within reasonable bounds for the list: There are a lot of\nfunctions that would satisfy this without being the mean. min and max\nboth satisfy this, as does the median, etc.\n\nHowever, almost nobody's implementation of the mean satisfies this.\n\nTo see why, lets write our own mean:\n\n```python\ndef mean(ls):\n    return sum(ls) / len(ls)\n```\n\nThis seems reasonable enough - it's just the definition of the mean -\nbut it's wrong:\n\n```\nassert inf <= 8.98846567431158e+307\n +  where inf = mean([8.988465674311579e+307, 8.98846567431158e+307])\n +  and   8.98846567431158e+307 = max([8.988465674311579e+307, 8.98846567431158e+307])\n\nFalsifying example: test_mean_is_within_reasonable_bounds(\n    ls=[8.988465674311579e+307, 8.98846567431158e+307]\n)\n```\n\nThe problem is that finite floating point numbers may be large enough\nthat their sum overflows to infinity. When you then divide infinity by a\nfinite number you still get infinity, which is out of the range.\n\nSo to prevent that overflow, lets try to bound the size of our numbers\nby the length *first*:\n\n```python\ndef mean(ls):\n    return sum(l / len(ls) for l in ls)\n```\n\n```\nassert min(ls) <= mean(ls) <= max(ls)\nassert 1.390671161567e-309 <= 1.390671161566996e-309\nwhere 1.390671161567e-309 = min([1.390671161567e-309, 1.390671161567e-309, 1.390671161567e-309])\nand   1.390671161566996e-309 = mean([1.390671161567e-309, 1.390671161567e-309, 1.390671161567e-309])\n\nFalsifying example: test_mean_is_within_reasonable_bounds(\n    ls=[1.390671161567e-309, 1.390671161567e-309, 1.390671161567e-309]\n)\n```\n\nIn this case the problem you run into is not overflow, but the lack of\nprecision of floating point numbers: Floating point numbers are only\nexact up to powers of two times an integer, so dividing by three will\ncause rounding errors. In this case we have the problem that (x / 3) * 3\nmay not be equal to x in general.\n\nSo now we've got a sense of why this might be hard. Lets see how\nexisting implementations do at satisfying this test.\n\nFirst let's try numpy:\n\n```python\nimport numpy as np\n\n\ndef mean(ls):\n    return np.array(ls).mean()\n```\n\nThis runs into the problem we had in our first implementation:\n\n```\nassert min(ls) <= mean(ls) <= max(ls)\nassert inf <= 8.98846567431158e+307\n\nwhere inf = mean([8.988465674311579e+307, 8.98846567431158e+307])\nand   8.98846567431158e+307 = max([8.988465674311579e+307, 8.98846567431158e+307])\n\nFalsifying example: test_mean_is_within_reasonable_bounds(\n    ls=[8.988465674311579e+307, 8.98846567431158e+307]\n)\n```\n\nThere's also the new statistics module from Python 3.4. Unfortunately,\nthis is broken too\n([this is fixed in 3.5.2](https://bugs.python.org/issue25177)):\n\n```\nOverflowError: integer division result too large for a float\n\nFalsifying example: test_mean_is_within_reasonable_bounds(\n    ls=[8.988465674311579e+307, 8.98846567431158e+307]\n)\n```\n\nIn the case where we previously overflowed to infinity this instead\nraises an error. The reason for this is that internally the statistics\nmodule is converting everything to the Fraction type, which is an\narbitrary precision rational type. Because of the details of where and\nwhen they were converting back to floats, this produced a rational that\ncouldn't be readily converted back to a float.\n\nIt's relatively easy to write an implementation which passes this test\nby simply cheating and not actually calculating the mean:\n\n```python\ndef clamp(lo, v, hi):\n    return min(hi, max(lo, v))\n\n\ndef mean(ls):\n    return clamp(min(ls), sum(ls) / len(ls), max(ls))\n```\n\ni.e. just restricting the value to lie in the desired range.\n\nHowever getting an actually correct implementation of the mean (which\n*would* pass this test) is quite hard:\n\nTo see just how hard, here's a [30 page\npaper on calculating the mean of two numbers](https://hal.archives-ouvertes.fr/file/index/docid/576641/filename/computing-midpoint.pdf).\n\nI wouldn't feel obliged to read that paper if I were you. I *have* read\nit and I don't remember many of the details.\n\nThis test is a nice instance of a general one: Once you've got the\n[this code doesn't crash](../getting-started-with-hypothesis/),\ntests working, you can start to layer on additional constraints on the\nresult value. As this example shows, even when the constraints you\nimpose are *very* lax it can often catch interesting bugs.\n\nIt also demonstrates a problem: Floating point mathematics is *very*\nhard, and this makes it somewhat unsuitable for testing with Hypothesis.\n\nThis isn't because Hypothesis is *bad* at testing floating point code,\nit's because it's good at showing you how hard programming actually is,\nand floating point code is much harder than people like to admit.\n\nAs a result, you probably don't care about the bugs it will find:\nGenerally speaking most peoples' attitude to floating point errors is\n\"Eh, those are weird numbers, we don't really care about that. It's\nprobably good enough\". Very few people are actually prepared to do the\nrequired work of a numerical sensitivity analysis that is needed if you\nwant your floating point code to be correct.\n\nI used to use this example a lot for demonstrating Hypothesis to people,\nbut because of these problems I tend not to any more: Telling people\nabout bugs they're not going to want to fix will get you neither bug\nfixes nor friends.\n\nBut it's worth knowing that this is a problem: Programming *is* really\nhard, and ignoring the problems won't make it less hard. You can ignore\nthe correctness issues until they actually bite you, but it's best not\nto be surprised when they do.\n\nAnd it's also worth remembering the general technique here, because this\nisn't just useful for floating point numbers: Most code can benefit from\nthis, and most of the time the bugs it tells you won't be nearly this\nunpleasant.\n"
  },
  {
    "path": "website/content/2016-07-09-hypothesis-3.4.1-release.md",
    "content": "---\ntags: news, python, non-technical\ndate: 2016-07-09 00:00\ntitle: Hypothesis for Python 3.4.1 Release\nauthor: drmaciver\n---\n\nThis is a bug fix release for a single bug:\n\n*   On Windows when running two Hypothesis processes in parallel (e.g.\n    using pytest-xdist) they could race with each other and one would\n    raise an exception due to the non-atomic nature of file renaming on\n    Windows and the fact that you can’t rename over an existing file.\n    This is now fixed.\n\n## Notes\n\nMy tendency of doing immediate patch releases for bugs is unusual but\ngenerally seems to be appreciated. In this case this was a bug that was\nblocking\n[a py.test merge](https://github.com/pytest-dev/pytest/pull/1705).\n\nI suspect this is not the last bug around atomic file creation on\nWindows. Cross platform atomic file creation seems to be a harder\nproblem than I would have expected.\n"
  },
  {
    "path": "website/content/2016-07-13-hypothesis-3.4.2-release.md",
    "content": "---\ntags: news, python, non-technical\ndate: 2016-07-13 00:00\ntitle: 3.4.2 Release of Hypothesis for Python\nauthor: drmaciver\n---\n\nThis is a bug fix release, fixing a number of problems with the settings\nsystem:\n\n* Test functions defined using @given can now be called from other\n  threads (Issue #337)\n* Attempting to delete a settings property would previously have\n  silently done the wrong thing. Now it raises an AttributeError.\n* Creating a settings object with a custom database_file parameter\n  was silently getting ignored and the default was being used instead.\n  Now it’s not.\n\n## Notes\n\nFor historic reasons, _settings.py had been excluded from the\nrequirement to have 100% branch coverage. Issue #337 would have been\ncaught by a coverage requirement: the code in question simply couldn't\nhave worked, but it was not covered by any tests, so it slipped through.\n\nAs part of the general principle that bugs shouldn't just be fixed\nwithout addressing the reason why the bug slipped through in the first\nplace, I decided to impose the coverage requirements on _settings.py\nas well, which is how the other two bugs were found. Both of these had\ncode that was never run during tests - in the case of the deletion bug\nthere was a \\_\\_delete\\_\\_ descriptor method that was never being run,\nand in the case of the database\\_file one there was a check later that\ncould never fire because the internal \\_database field was always being\nset in \\_\\_init\\_\\_.\n\nI feel like this experiment thoroughly validated that 100% coverage is a\nuseful thing to aim for. Unfortunately it also pointed out that the\nsettings system is *much* more complicated than it needs to be. I'm\nunsure what to do about that - some of its functionality is a bit too\nbaked into the public API to lightly change, and I'm don't think it's\nworth breaking that just to simplify the code.\n"
  },
  {
    "path": "website/content/2016-07-23-what-is-hypothesis.md",
    "content": "---\ntags: python, intro\ndate: 2016-07-24 00:00\ntitle: What is Hypothesis?\nauthor: drmaciver\n---\n\nHypothesis is a library designed to help you write what are called\n*property-based tests*.\n\nThe key idea of property based testing is that rather than writing a test\nthat tests just a single scenario, you write tests that describe a range\nof scenarios and then let the computer explore the possibilities for you\nrather than having to hand-write every one yourself.\n\nIn order to contrast this with the sort of tests you might be used to, when\ntalking about property-based testing we tend to describe the normal sort of\ntesting as *example-based testing*.\n\nProperty-based testing can be significantly more powerful than example based\ntesting, because it automates the most time consuming part of writing tests\n- coming up with the specific examples - and will usually perform it better\nthan a human would. This allows you to focus on the parts that humans are\nbetter at - understanding the system, its range of acceptable behaviours,\nand how they might break.\n\nYou don't *need* a library to do property-based testing. If you've ever\nwritten a test which generates some random data and uses it for testing,\nthat's a property-based test. But having a library can help you a lot,\nmaking your tests easier to write, more robust, and better at finding\nbugs. In the rest of this article we'll see how.\n\n<!--more-->\n\n### How to use it\n\nThe key object of Hypothesis is a *strategy*. A strategy is a recipe for\ndescribing the sort of data you want to generate. The existence of a rich\nand comprehensive strategy library is the first big advantage of Hypothesis\nover a more manual process: Rather than having to hand-write generators\nfor the data you want, you can just compose the ones that Hypothesis\nprovides you with to get the data you want. e.g. if you want a lists of\nfloats, you just use the strategy lists(floats()). As well as being\neasier to write, the resulting data will usually have a distribution\nthat is much better at finding edge cases than all but the most heavily\ntuned manual implementations.\n\nAs well as the basic out of the box strategy implementations, Hypothesis\nhas a number of tools for composing strategies with user defined functions\nand constraints, making it fairly easy to generate the data you want.\n\nNote: For the remainder of this article I'll focus on the Hypothesis for\nPython implementation. The Java implementation is similar, but has a number\nof small differences that I'll discuss in a later article.\n\nOnce you know how to generate your data, the main entry point to Hypothesis\nis the @given decorator. This takes a function that accepts some arguments\nand turns it into a normal test function.\n\nAn important consequence of that is that Hypothesis is not itself a test\nrunner. It works inside your normal testing framework - it will work fine\nwith nose, py.test, unittest, etc. because all it does is expose a function\nof the right name that the test runner can then pick up.\n\nUsing it with a py.test or nose style test looks like this:\n\n```python\nfrom mercurial.encoding import fromutf8b, toutf8b\n\nfrom hypothesis import given\nfrom hypothesis.strategies import binary\n\n\n@given(binary())\ndef test_decode_inverts_encode(s):\n    assert fromutf8b(toutf8b(s)) == s\n```\n\n(This is an example from testing Mercurial which found two bugs:\n[4927](https://bz.mercurial-scm.org/show_bug.cgi?id=4927) and\n[5031](https://bz.mercurial-scm.org/show_bug.cgi?id=5031)).\n\nIn this test we are asserting that for any binary string, converting\nit to its utf8b representation and back again should result in the\nsame string we started with. The @given decorator then handles\nexecuting this test over a range of different binary strings without\nus having to explicitly specify any of the examples ourself.\n\nWhen this is first run, you will see an error that looks something\nlike this:\n\n```\nFalsifying example: test_decode_inverts_encode(s='\\xc2\\xc2\\x80')\n\nTraceback (most recent call last):\n  File \"/home/david/.pyenv/versions/2.7/lib/python2.7/site-packages/hypothesis/core.py\", line 443, in evaluate_test_data\n    search_strategy, test,\n  File \"/home/david/.pyenv/versions/2.7/lib/python2.7/site-packages/hypothesis/executors.py\", line 58, in default_new_style_executor\n    return function(data)\n  File \"/home/david/.pyenv/versions/2.7/lib/python2.7/site-packages/hypothesis/core.py\", line 110, in run\n    return test(*args, **kwargs)\n  File \"/home/david/hg/test_enc.py\", line 8, in test_decode_inverts_encode\n    assert fromutf8b(toutf8b(s)) == s\n  File \"/home/david/hg/mercurial/encoding.py\", line 485, in fromutf8b\n    u = s.decode(\"utf-8\")\n  File \"/home/david/.pyenv/versions/2.7/lib/python2.7/encodings/utf_8.py\", line 16, in decode\n    return codecs.utf_8_decode(input, errors, True)\nUnicodeDecodeError: 'utf8' codec can't decode byte 0xc2 in position 1: invalid continuation byte\n```\n\nNote that the falsifying example is quite small. Hypothesis has a\n\"simplification\" process which runs behind the scenes and generally\ntries to give the impression that the test simply failed with one\nexample that happened to be a really nice one.\n\nAnother important thing to note is that because of the random nature\nof Hypothesis and because this bug is relatively hard to find, this\ntest may run successfully a couple of times before finding it.\n\nHowever, once that happens, when we rerun the test it will keep failing\nwith the same example. This is because Hypothesis has a local test\ndatabase that it saves failing examples in. When you rerun the test,\nit will first try the previous failure.\n\nThis is pretty important: It means that although Hypothesis is at its\nheart random testing, it is *repeatable* random testing: A bug will\nnever go away by chance, because a test will only start passing if\nthe example that previously failed no longer failed.\n\n(This isn't entirely true because a bug could be caused by random\nfactors such as timing or hash randomization. However in these cases\nit's true for example-based testing as well. If anything Hypothesis\nis *more* robust here because it will tend to find these cases with\nhigher probability).\n\nUltimately that's \"all\" Hypothesis does: It provides repeatability,\nreporting and simplification for randomized tests, and it provides\na large library of generators to make it easier to write them.\n\nBecause of these features, the workflow is a huge improvement on\nwriting your own property-based tests by hand, and thanks to the\nlibrary of generators it's often even easier than writing your\nown example based tests by hand.\n\n### What now?\n\nIf you want to read more on the subject, there are a couple places\nyou could go:\n\n* If you want to know more of the details of the process I described\n  when a test executes, you can check out the\n  [Anatomy of a test](../anatomy-of-a-test/)\n  article which will walk you through the steps in more detail.\n* If you'd like more examples of how to use it, check out the rest of the\n  [articles](/articles).\n\nBut really the best way to learn more is to try to use it!\nAs you've hopefully seen in this article, it's quite approachable to\nget started with. Try writing some tests and see what happens.\n"
  },
  {
    "path": "website/content/2016-08-09-hypothesis-pytest-fixtures.md",
    "content": "---\ntags: technical, faq, python\ndate: 2016-08-09 10:00\ntitle: How do I use pytest fixtures with Hypothesis?\nauthor: drmaciver\n---\n\n[pytest](http://doc.pytest.org/en/latest/) is a great test runner, and is the one\nHypothesis itself uses for testing (though Hypothesis works fine with other test\nrunners too).\n\nIt has a fairly elaborate [fixture system](http://doc.pytest.org/en/latest/fixture.html),\nand people are often unsure how that interacts with Hypothesis. In this article we'll\ngo over the details of how to use the two together.\n\n<!--more-->\n\nMostly, Hypothesis and py.test fixtures don't interact: Each just ignores the other's\npresence.\n\nWhen using a @given decorator, any arguments that are not provided in the @given\nwill be left visible in the final function:\n\n```python\nfrom inspect import signature\n\nfrom hypothesis import given, strategies as st\n\n\n@given(a=st.none(), c=st.none())\ndef test_stuff(a, b, c, d):\n    pass\n\n\nprint(signature(test_stuff))\n```\n\nThis then outputs the following:\n\n```\n<Signature (b, d)>\n```\n\nWe've hidden the arguments 'a' and 'c', but the unspecified arguments 'b' and 'd'\nare still left to be passed in. In particular, they can be provided as py.test\nfixtures:\n\n```python\nfrom pytest import fixture\n\nfrom hypothesis import given, strategies as st\n\n\n@fixture\ndef stuff():\n    return \"kittens\"\n\n\n@given(a=st.none())\ndef test_stuff(a, stuff):\n    assert a is None\n    assert stuff == \"kittens\"\n```\n\nThis also works if we want to use @given with positional arguments:\n\n```python\nfrom pytest import fixture\n\nfrom hypothesis import given, strategies as st\n\n\n@fixture\ndef stuff():\n    return \"kittens\"\n\n\n@given(t.none())\ndef test_stuff(stuff, a):\n    assert a is None\n    assert stuff == \"kittens\"\n```\n\nThe positional argument fills in from the right, replacing the 'a'\nargument and leaving us with 'stuff' to be provided by the fixture.\n\nPersonally I don't usually do this because I find it gets a bit\nconfusing - if I'm going to use fixtures then I always use the named\nvariant of given. There's no reason you *can't* do it this way if\nyou prefer though.\n\n@given also works fine in combination with parametrized tests:\n\n```python\nimport pytest\n\nfrom hypothesis import given, strategies as st\n\n\n@pytest.mark.parametrize(\"stuff\", [1, 2, 3])\n@given(a=st.none())\ndef test_stuff(a, stuff):\n    assert a is None\n    assert 1 <= stuff <= 3\n```\n\nThis will run 3 tests, one for each value for 'stuff'.\n\nThere is one unfortunate feature of how this interaction works though: In pytest\nyou can declare fixtures which do set up and tear down per function. These will\n\"work\" with Hypothesis, but they will run once for the entire test function\nrather than once for each time given calls your test function. So the following\nwill fail:\n\n```python\nfrom pytest import fixture\n\nfrom hypothesis import given, strategies as st\n\ncounter = 0\n\n\n@fixture(scope=\"function\")\ndef stuff():\n    global counter\n    counter = 0\n\n\n@given(a=st.none())\ndef test_stuff(a, stuff):\n    global counter\n    counter += 1\n    assert counter == 1\n```\n\nThe counter will not get reset at the beginning of each call to the test function,\nso it will be incremented each time and the test will start failing after the\nfirst call.\n\nThere currently aren't any great ways around this unfortunately. The best you can\nreally do is do manual setup and teardown yourself in your tests using\nHypothesis (e.g. by implementing a version of your fixture as a context manager).\n\nLong-term, I'd like to resolve this by providing a mechanism for allowing fixtures\nto be run for each example (it's probably not correct to have *every* function scoped\nfixture run for each example), but for now it's stalled because it [requires changes\non the py.test side as well as the Hypothesis side](https://github.com/pytest-dev/pytest/issues/916)\nand we haven't quite managed to find the time and place to collaborate on figuring\nout how to fix this yet.\n"
  },
  {
    "path": "website/content/2016-08-19-recursive-data.md",
    "content": "---\ntags: technical, python, intro\ndate: 2016-08-19 10:00\ntitle: Generating recursive data\nauthor: drmaciver\n---\n\nSometimes you want to generate data which is *recursive*.\nThat is, in order to draw some data you may need to draw\nsome more data from the same strategy. For example we might\nwant to generate a tree structure, or arbitrary JSON.\n\nHypothesis has the *recursive* function in the hypothesis.strategies\nmodule to make this easier to do. This is an article about how to\nuse it.\n\n<!--more-->\n\nLets start with a simple example of drawing tree shaped data:\nIn our example a tree is either a single boolean value (a leaf\nnode), or a tuple of two child trees. So a tree might be e.g. True,\nor (False, True), or ((True, True), False), etc.\n\nFirst off, it might not be obvious that you *need* the recursive\nstrategy. In principle you could just do this with composite:\n\n\n```python\nimport hypothesis.strategies as st\n\n\n@st.composite\ndef composite_tree(draw):\n    return draw(\n        st.one_of(\n            st.booleans(),\n            st.tuples(composite_tree(), composite_tree()),\n        )\n    )\n```\n\nIf you try drawing examples from this you'll probably see one of\nthree scenarios:\n\n1. You'll get a single boolean value\n2. You'll get a very large tree\n3. You'll get a RecursionError from a stack overflow\n\nIt's unlikely that you'll see any non-trivial small examples.\n\nThe reason for this is that this sort of recursion tends to\nexplode in size: If this were implemneted as a naive random\ngeneration process then the expected size of the tree would\nbe infinite. Hypothesis has some built in limiters to stop\nit ever trying to actually generate infinitely large amounts\nof data, but it will still tend to draw trees that are very\nlarge if they're not trivial, and it can't do anything about\nthe recursion problem.\n\nSo instead of using this sort of unstructured recursion,\nHypothesis exposes a way of doing recursion in a slightly more\nstructured way that lets it control the size of the\ngenerated data much more effectively. This is the recursive\nstrategy.\n\nIn order to use the recursive strategy you need two parts:\n\n1. A base strategy for generating \"simple\" instances of the\n   data that you want.\n2. A function that takes a child strategy that generates data\n   of the type you want and returns a new strategy generating\n   \"larger\" instances.\n\nSo for example for our trees of booleans and tuples we could\nuse booleans() for the first and something for returning tuples\nof children for the second:\n\n```python\nrecursive_tree = st.recursive(\n    st.booleans(), lambda children: st.tuples(children, children)\n)\n```\n\nThe way to think about the recursive strategy is that you're\nrepeatedly building up a series of strategies as follows:\n\n```python\ns1 = base\ns2 = one_of(s1, extend(s1))\ns3 = one_of(s2, extend(s2))\n...\n```\n\nSo at each level you augment the things from the previous\nlevel with your extend function. Drawing from the resulting\nrecursive strategy then picks one of this infinite sequence\nof strategies and draws from it (this isn't quite what happens\nin practice, but it's pretty close).\n\nThe resulting strategy does a much better job of drawing small\nand medium sized trees than our original composite based one\ndoes, and should never raise a RecursionError:\n\n```\n>>> recursive_tree.example()\n((False, True), ((True, True), False))\n\n>>> recursive_tree.example()\n((((False, False), True), False), False)\n\n>>> recursive_tree.example()\n(False, True)\n\n>>> recursive_tree.example()\nTrue\n\n```\n\nYou can also control the size of the trees it draws with the\nthird parameter to recursive:\n\n```\n>>> st.recursive(st.booleans(), lambda children: st.tuples(children, children), max_leaves=2).example()\nTrue\n\n>>> st.recursive(st.booleans(), lambda children: st.tuples(children, children), max_leaves=2).example()\n(True, False)\n```\n\nThe max_leaves parameter controls the number of values drawn from\nthe 'base' strategy. It defaults to 50, which will tend to give you\nmoderately sized values. This helps keep example sizes under control,\nas otherwise it can be easy to create extend functions which cause the\nsize to grow very rapidly.\n\nIn this particular example, Hypothesis will typically not hit the default,\nbut consider something like the following:\n\n```\n>>> st.recursive(st.booleans(), lambda children: st.lists(children, min_size=3)).example()\n[[False,\n  True,\n  False,\n  False,\n  False,\n  True,\n  True,\n  True,\n  False,\n  False,\n  False,\n  True,\n  True,\n  False],\n False,\n [False, True, False, True, False],\n [True, False, True, False, False, False]]\n```\n\nIn this case the size of the example will tend to push up against the max_leaves value\nbecause extend() grows the strategy in size quite rapidly, so if you want larger\nexamples you will need to turn up max_leaves.\n"
  },
  {
    "path": "website/content/2016-08-31-how-many-tests.md",
    "content": "---\ntags: technical, details, faq, python\ndate: 2016-08-31 00:00\ntitle: How many times will Hypothesis run my test?\nauthor: drmaciver\n---\n\nThis is one of the most common first questions about Hypothesis.\n\nPeople generally assume that the number of tests run will depend on\nthe specific strategies used, but that's generally not the case.\nInstead Hypothesis has a fairly fixed set of heuristics to determine\nhow many times to run, which are mostly independent of the data\nbeing generated.\n\nBut how many runs is *that*?\n\nThe short answer is 200. Assuming you have a default configuration\nand everything is running smoothly, Hypothesis will run your test\n200 times.\n\nThe longer answer is \"It's complicated\". It will depend on the exact\nbehaviour of your tests and the value of some settings. In this article\nI'll try to clear up some of the specifics of which\n[settings](http://hypothesis.readthedocs.io/en/latest/settings.html)\naffect the answer and how.\n\n<!--more-->\n\nAdvance warning: This is a set of heuristics built up over time. It's\nprobably not the best choice of heuristics, but it mostly seems\nto work well in practice. It will hopefully be replaced with a\nsimpler set of rules at some point.\n\nThe first setting that affects how many times the test function will\nbe called is the timeout setting. This specifies a maximum amount of\ntime for Hypothesis to run your tests for. Once that has exceeded it\nwill stop and not run any more (note: This is a soft limit, so it\nwon't interrupt a test midway through).\n\nThe result of this is that slow tests may get run fewer times. By\ndefault the timeout is one minute, which is high enough that most\ntests shouldn't hit it, if your tests take somewhere in the region\nof 300-400ms on average they will start to hit the timeout.\n\nThe timeout is respected regardless of whether the test passes or\nfails, but other than that the behaviour for a passing test is\nvery different from a failing one.\n\n### Passing tests\n\nFor the passing case there are two other settings that affect the\nanswer: max\\_examples and max\\_iterations.\n\nIn the normal case, max\\_examples is what you can think of as the\nnumber of test runs. The difference comes when you start using\nassume or filter (and a few other cases).\n\nHypothesis distinguishes between a *valid* test run and an invalid one\n- if assume has been called with a falsey value or at some point in\nthe generation process it got stuck (e.g. because filter couldn't\nfind any satisfying examples) it aborts the example and starts\nagain from the beginning. max\\_examples counts only valid examples\nwhile max\\_iterations counts all examples, valid or otherwise. Some\nduplicate tests will also be considered invalid (though Hypothesis\ncan't distinguish all duplicates. e.g. if you did\nintegers().map(lambda x: 1) it would think you had many distinct values\nwhen you only had one). The default value for max_iterations\nis currently 1000.\n\nTo see why it's important to have the max\\_iterations limit,\nconsider something like:\n\n```python\nfrom hypothesis import assume, given, strategies as st\n\n\n@given(st.integers())\ndef test_stuff(i):\n    assume(False)\n```\n\nThen without a limit on invalid examples this would run forever.\n\nConversely however, treating valid examples specially is useful because\notherwise even casual use of assume would reduce the number of tests\nyou run, reducing the quality of your testing.\n\nAnother thing to note here is that the test with assume(False) will\nactually fail, raising:\n\n```\nhypothesis.errors.Unsatisfiable: Unable to satisfy assumptions of hypothesis test_stuff. Only 0 examples considered satisfied assumptions\n```\n\nThis is because of the min\\_satisfying\\_examples setting: If\nHypothesis couldn't find enough valid test cases then it will\nfail the test rather than silently doing the wrong thing.\n\nmin\\_satisfying\\_examples will never increase the number of tests\nrun, only fail the test if that number of valid examples haven't\nbeen run. If you're hitting this failure you can either turn it\ndown or turn the timeout or max\\_iterations up. Better, you can\nfigure out *why* you're hitting that and fix it, because it's\nprobably a sign you're not getting much benefit out of Hypothesis.\n\n\n### Failing tests\n\nIf in the course of normal execution Hypothesis finds an example\nwhich causes your test to fail, it switches into shrinking mode.\n\nShrinking mode tries to take your example and produce a smaller\none. It ignores max\\_examples and max\\_iterations but respects\ntimeout. It also respects one additional setting: max\\_shrinks.\n\nmax\\_shrinks is the maximum number of *failing* tests that Hypothesis\nwill see before it stops. It may try any number of valid or invalid\nexamples in the course of shrinking. This is because failing\nexamples tend to be a lot rarer than passing or invalid examples,\nso it makes more sense to limit based on that if we want to get\ngood examples out at the end.\n\nOnce Hypothesis has finished shrinking it will run your test once\nmore to replay it for display: In the final run only it will print\nout the example and any notes, and will let the exception bubble\nup to the test runner to be handled as normal.\n\n\n### In Conclusion\n\n\"It's complicated\".\n\nThese heuristics are probably not the best. They've evolved\nover time, and are definitely not the ones that you or I would\nobviously come up with if you sat down and designed the system\nfrom scratch.\n\nFortunately, you're not expected to know these heuristics by heart\nand mostly shouldn't have to. I'm working on a new feature that\nwill help show how many examples Hypothesis has tried and help\ndebug why it's stopped at that point. Hopefully it will be coming\nin a release in the near future.\n"
  },
  {
    "path": "website/content/2016-09-04-hypothesis-vs-eris.md",
    "content": "---\ntags: technical, python, intro\ndate: 2016-09-04 15:00\ntitle: Hypothesis vs. Eris\nauthor: giorgiosironi\n---\n\n[Eris](https://github.com/giorgiosironi/eris/) is a library for property-based testing of PHP code, inspired by the mature frameworks that other languages provide like [QuickCheck](https://hackage.haskell.org/package/QuickCheck), Clojure's [test.check](https://github.com/clojure/test.check) and of course Hypothesis.\n\nHere is a side-by-side comparison of some basic and advanced features that have been implemented in both Hypothesis and Eris, which may help developers coming from either Python or PHP and looking at the other side.\n\n<!--more-->\n\n## Hello, world\n\nThe first example can be considered an `Hello, world` of randomized testing: given two random numbers, their sum should be constant no matter the order in which they are summed. The test case has two input parameters, so that it can be run dozens or hundreds of times, each run with different and increasingly complex input values.\n\nHypothesis provides an idiomatic Python solution, the `@given` decorator, that can be used to compose the strategies objects instantiated from `hypothesis.strategies`. The test case is very similar to an example-based one, except for the addition of arguments:\n\n```python\nimport unittest\n\nfrom hypothesis import given, strategies as st\n\n\nclass TestEris(unittest.TestCase):\n    \"Comparing the syntax and implementation of features with Eris\"\n\n    @given(st.integers(), st.integers())\n    def test_sum_is_commutative(self, first, second):\n        x = first + second\n        y = second + first\n        self.assertEqual(\n            x, y, \"Sum between %d and %d should be commutative\" % (first, second)\n        )\n```\n\nIn this example, I am using the unittest syntax for maximum test portability, but this does not affect Hypothesis, which works across testing frameworks.\n\nEris provides functionality with a trait instead, that can be composed into the test cases that need access to randomized input. The test method is not augmented with additional parameters, but its code is moved inside an anonymous function for the `then()` primitive. Input distributions are defined in a mathematically-named `forAll()` primitive:\n\n```php\n<?php\nuse Eris\\Generator;\nuse Eris\\TestTrait;\n\nclass IntegerTest extends PHPUnit_Framework_TestCase\n{\n    use TestTrait;\n\n    public function testSumIsCommutative()\n    {\n        $this\n            ->forAll(\n                Generator\\int(),\n                Generator\\int()\n            )\n            ->then(function ($first, $second) {\n                $x = $first + $second;\n                $y = $second + $first;\n                $this->assertEquals(\n                    $x,\n                    $y,\n                    \"Sum between {$first} and {$second} should be commutative\"\n                );\n            });\n    }\n```\n\nBoth these tests will be run hundreds of times, each computing two sums and comparing them for equality with the assertion library of the underlying testing framework (unittest and PHPUnit).\n\n## Composing strategies\n\nA very simple composition problem consists of generating a collection data structured whose elements are drawn from a known distribution, for example a list of integers. Hypothesis provides *strategies* that can compose other strategies, in this case to build a list of random integers of arbitrary length:\n\n```python\n@given(st.lists(st.integers()))\ndef test_sorting_a_list_twice_is_the_same_as_sorting_it_once(self, xs):\n    xs.sort()\n    ys = list(xs)\n    xs.sort()\n    self.assertEqual(xs, ys)\n```\n\nEris calls *generators* the objects representing statistical distributions, but uses the same compositional pattern for higher-order values like lists and all collections:\n\n```php\n    public function testArraySortingIsIdempotent()\n    {\n        $this\n            ->forAll(\n                Generator\\seq(Generator\\nat())\n            )\n            ->then(function ($array) {\n                sort($array);\n                $expected = $array;\n                sort($array);\n                $this->assertEquals($expected, $array);\n            });\n    }\n```\n\nIn both these test cases, we generate a random list and check that the sorting operation is idempotent: operating it twice on the input data gives the same result as operating it once.\n\n## Filtering generated values\n\nNot all problems are abstract enough to accept all values in input, so it may be necessary to exclude part of the generated values when they do not fit our needs.\n\nHypothesis provides a `filter()` method to apply a lambda to values, expressing a condition for them to be included in the test:\n\n```python\n@given(st.integers().filter(lambda x: x > 42))\ndef test_filtering(self, x):\n    self.assertGreater(x, 42)\n```\n\nEris allows to filter values with a predicate in the same way, but prefers to allocate the filter to the generic `ForAll` object rather than decorate it on each Generator:\n\n```php\n    public function testWhenWithAnAnonymousFunctionWithGherkinSyntax()\n    {\n        $this\n            ->forAll(\n                Generator\\choose(0, 1000)\n            )\n            ->when(function ($n) {\n                return $n > 42;\n            })\n            ->then(function ($number) {\n                $this->assertTrue(\n                    $number > 42,\n                    \"\\$number was filtered to be more than 42, but it's $number\"\n                );\n            });\n    }\n```\n\nFiltering and the constructs that follow are integrated with shrinking in both Hypothesis and Eris: once a test fails and shrinking starts, constraints and transformations will continue to be applied to the generated values so that the simpler inputs are still going to belong to the same distribution; in this scenario, shrinking would only be able to propose numbers greater than 42.\n\n## Transforming generated values\n\nAnother common need consists of transforming the generated value to a different space, for example the set of all even numbers rather than the (larger) set of integers. Hypothesis allows to do this by passing a lambda to the `map()` method of a strategy:\n\n```python\n@given(st.integers().map(lambda x: x * 2))\ndef test_mapping(self, x):\n    self.assertEqual(x % 2, 0)\n```\n\nEris instead provides a `Map` higher-order generator, which applies the lambda during generation:\n\n```php\n    public function testApplyingAFunctionToGeneratedValues()\n    {\n        $this\n            ->forAll(\n                Generator\\map(\n                    function ($n) { return $n * 2; },\n                    Generator\\nat()\n                )\n            )\n            ->then(function ($number) {\n                $this->assertTrue(\n                    $number % 2 == 0,\n                    \"$number is not even\"\n                );\n            });\n    }\n```\n\nIn both cases, the advantage of using the `map` support from the library (rather than writing our own multiplying code in the tests) is that the resulting object can be further composed to build larger data structures like a list or set of even numbers.\n\n## Generators with random parameters\n\nIt's possible to build even stricter values, that have internal constraints that must be satisfied but can't easily be generated by applying a pure function to a previously generated value.\n\nHypothesis provides the `flatmap()` method to pass the output of an inner strategy to a lambda that creates an outer strategy to use in the test. Here a list of 4 integers is passed to the lambda, to generate a tuple consisting of the list and a random element chosen from it:\n\n```python\n@given(\n    st.lists(st.integers(), min_size=4, max_size=4).flatmap(\n        lambda xs: st.tuples(st.just(xs), st.sampled_from(xs))\n    )\n)\ndef test_list_and_element_from_it(self, pair):\n    (generated_list, element) = pair\n    self.assertIn(element, generated_list)\n```\n\nEris does the same with a slightly different naming, calling this primitive `bind`:\n\n```php\n    public function testCreatingABrandNewGeneratorFromAGeneratedValue()\n    {\n        $this\n            ->forAll(\n                Generator\\bind(\n                    Generator\\vector(4, Generator\\nat()),\n                    function ($vector) {\n                        return Generator\\tuple(\n                            Generator\\elements($vector),\n                            Generator\\constant($vector)\n                        );\n                    }\n                )\n            )\n            ->then(function ($tuple) {\n                list($element, $vector) = $tuple;\n                $this->assertContains($element, $vector);\n            });\n    }\n```\n\n## What the future brings\n\nHypothesis is a much more mature project than Eris, especially when it comes to keeping state between test runs or acting as a generic random data provider rather than as an extension to a testing framework. It will be interesting to continue porting Hypothesis features to the PHP world, given the original features and patterns that Hypothesis shows with respect to the rest of the `*Check` world.\n\n## References\n\nThe Hypothesis examples shown in this post can be found in [this example repository](https://github.com/giorgiosironi/hypothesis-exploration/blob/master/test_eris.py).\n\nThe Eris examples can instead be found in the example/ folder of [the](https://github.com/giorgiosironi/eris/blob/master/examples/IntegerTest.php#L9) [Eris](https://github.com/giorgiosironi/eris/blob/master/examples/SequenceTest.php#L31) [repository](https://github.com/giorgiosironi/eris/blob/master/examples/WhenTest.php#L8) [on](https://github.com/giorgiosironi/eris/blob/master/examples/MapTest.php#L8) [GitHub](https://github.com/giorgiosironi/eris/blob/master/examples/BindTest.php#L8).\n"
  },
  {
    "path": "website/content/2016-09-23-hypothesis-3.5.0-release.md",
    "content": "---\ntags: news, python, non-technical\ndate: 2016-09-23 00:00\ntitle: 3.5.0 and 3.5.1 Releases of Hypothesis for Python\nauthor: drmaciver\n---\n\nThis is a combined release announcement for two releases. 3.5.0\nwas released yesterday, and 3.5.1 has been released today after\nsome early bug reports in 3.5.0\n\n## Changes\n\n### 3.5.0 - 2016-09-22\n\nThis is a feature release.\n\n* fractions() and decimals() strategies now support min_value and max_value\n  parameters. Thanks go to Anne Mulhern for the development of this feature.\n* The Hypothesis pytest plugin now supports a --hypothesis-show-statistics parameter\n  that gives detailed statistics about the tests that were run. Huge thanks to\n  [Jean-Louis Fuchs](https://github.com/ganwell) and [Adfinis-SyGroup](https://www.adfinis-sygroup.ch/)\n  for funding the development of this feature.\n* There is a new event() function that can be used to add custom statistics.\n\nAdditionally there have been some minor bug fixes:\n\n* In some cases Hypothesis should produce fewer duplicate examples (this will mostly\n  only affect cases with a single parameter).\n* py.test command line parameters are now under an option group for Hypothesis (thanks\n  to David Keijser for fixing this)\n* Hypothesis would previously error if you used function annotations on your tests under\n  Python 3.4.\n* The repr of many strategies using lambdas has been improved to include the lambda body\n  (this was previously supported in many but not all cases).\n\n\n### 3.5.1 - 2016-09-23\n\nThis is a bug fix release.\n\n* Hypothesis now runs cleanly in -B and -BB modes, avoiding mixing bytes and unicode.\n* unittest.TestCase tests would not have shown up in the new statistics mode. Now they\n  do.\n* Similarly, stateful tests would not have shown up in statistics and now they do.\n* Statistics now print with pytest node IDs (the names you'd get in pytest verbose mode).\n\n\n## Notes\n\nAside from the above changes, there are a couple big things behind the scenes of this\nrelease that make it a big deal.\n\nThe first is that the flagship chunk of work, statistics, is a long-standing want to\nhave that has never quite been prioritised. By funding it, Jean-Louis and Adfinis-SyGroup\nsuccessfully bumped it up to the top of the priority list, making it the first funded\nfeature in Hypothesis for Python!\n\nAnother less significant but still important is that this release marks the first real\nbreak with an unofficial Hypothesis for Python policy of not having any dependencies\nother than the standard library and backports. This release adds a dependency on the\nuncompyle6 package. This may seem like an odd choice, but it was invaluable for fixing\nthe repr behaviour, which in turn was really needed for providing good statistics\nfor filter and recursive strategies.\n"
  },
  {
    "path": "website/content/2016-10-01-pytest-integration-sponsorship.md",
    "content": "---\ntags: news, python, non-technical\ndate: 2016-10-01 00:00\ntitle: Seeking funding for deeper integration between Hypothesis and pytest\nauthor: drmaciver\n---\n\nProbably the number one complaint I hear from Hypothesis users is that it\n\"doesn't work\" with py.test fixtures. [This isn't true](http://hypothesis.works/articles/hypothesis-pytest-fixtures/),\nbut it does have one very specific limitation in how it works that annoys people:\nIt only runs function scoped fixtures once for the entire test, not once per\nexample. Because of the way people use function scoped fixtures for handling\nstateful things like databases, this often causes people problems.\n\nI've been [maintaining for a while](https://github.com/pytest-dev/pytest/issues/916) that\nthis is impossible to fix without some changes on the pytest end.\n\nThe good news is that this turns out not to be the case. After some conversations with\npytest developers, some examining of other pytest plugins, and a bunch of prototyping,\nI'm pretty sure it's possible. It's just really annoying and a lot of work.\n\nSo that's the good news. The bad news is that this isn't going to happen without\nsomeone funding the work.\n\nI've now spent about a week of fairly solid work on this, and what I've got is\nquite promising: The core objective of running pytest fixtures for every examples\nworks fairly seamlessly.\n\nBut it's now in the long tail of problems that will need to be squashed before\nthis counts as an actual production ready releasable piece of work. A number of\nthings *don't* work. For example, currently it's running some module scoped\nfixtures once per example too, which it clearly shouldn't be doing. It also\ncurrently has some pretty major performance problems that are bad enough that\nI would consider them release blocking.\n\nAs a result I'd estimate there's easily another 2-3 weeks of work needed to\nget this out the door.\n\nWhich brings us to the crux of the matter: 2-3 additional weeks of free work\non top of the one I've already done is 3-4 weeks more free work than I\nparticularly want to do on this feature, so without sponsorship it's not\ngetting finished.\n\nI typically charge £400/day for work on Hypothesis (this is heavily discounted\noff my normal rates), so 2-3 weeks comes to £4000 to £6000 (roughly $5000\nto $8000) that has to come from somewhere.\n\nI know there are a number of companies out there using pytest and Hypothesis\ntogether. I know from the amount of complaining about this integration that\nthis is a real problem you're experiencing. So, I think this money should\ncome from those companies. Besides helping to support a tool you've already\ngot a lot of value out of, this will expand the scope of what you can easily\ntest with Hypothesis a lot, and will be hugely beneficial to your bug finding\nefforts.\n\nThis is a model that has worked well before with the funding of the recent\nstatistics work by [Jean-Louis Fuchs](https://github.com/ganwell) and\n[Adfinis-SyGroup](https://www.adfinis-sygroup.ch/), and I'm confident it can\nwork well again.\n\nIf you work at such a company and would like to talk about funding some or\npart of this development, please email me at\n[drmaciver@hypothesis.works](mailto:drmaciver@hypothesis.works).\n"
  },
  {
    "path": "website/content/2016-10-17-canonical-serialization.md",
    "content": "---\ntags: python, intro, technical, properties\ndate: 2016-10-17 06:00\ntitle: Another invariant to test for encoders\nauthor: drmaciver\n---\n\n[The encode/decode invariant](../encode-decode-invariant/)\nis one of the most important properties to know about for testing your code with Hypothesis\nor other property-based testing systems, because it captures a very common pattern and is\nvery good at finding bugs.\n\nBut how do you go beyond it? If encoders are that common, surely there must be other things\nto test with them?\n\n<!--more-->\n\nThe first thing that people tend to try is to simply reverse the order of operations. Continuing\nthe same example from the encode/decode post, this would look something like this:\n\n```python\nfrom hypothesis import given\nfrom hypothesis.strategies import characters, integers, lists, tuples\n\n\n@given(lists(tuples(characters(), integers(1, 10))))\ndef test_encode_inverts_decode(s):\n    assert encode(decode(s)) == s\n```\n\nBut unlike the other way around, this test can fail for reasons that are not obviously\nerrors in the system under test. In particular this will fail with the example [('0', 1), ('0', 1)],\nbecause this will be decoded into '00', which will then be encoded into [('0', 2)].\n\nIn general, it is quite common to have multiple non-canonical representations of data\nwhen encoding: e.g. JSON has non-significant whitespace, an IP address has a wide range\nof human readable representations, most compressors will evolve to improve their compression\nover time but will still be able to handle compressed files made with old versions of\nthe code, etc.\n\nSo this test *shouldn't* be expected to pass.\n\nTo rescue this, we might imagine we had some sort of function make\\_canonical which\ntook an encoded data representation and replaced it with a canonical version of that (e.g.\nby normalizing whitespace). The test could then look like this:\n\n\n```python\n@given(lists(tuples(characters(), integers(1, 10))))\ndef test_encode_inverts_decode(s):\n    assert make_canonical(encode(decode(s))) == make_canonical(s)\n```\n\nBut where would we get that make\\_canonical function from? It's not something we really\nwant to write ourselves.\n\nFortunately we can put together the pieces we already have to define such a function\nfairly easily. To see this, lets think about what properties make\\_canonical should have.\n\nThe following seem reasonable:\n\n1. encode should always produce canonical data. i.e. encode(t) == make_canonical(encode(t))\n2. Canonical data should represent the same value. i.e. decode(s) == decode(make_canonical(s))\n\nBut we already know that decode(encode(t)) == t from our original property, so we have a\nnatural source of data that is the output of encode: We just decode the data and then\nencode it again.\n\nThis gives us the following natural definition of make_canonical:\n\n```python\ndef make_canonical(data):\n    return encode(decode(data))\n```\n\nBut this is nearly the same as the thing we were testing, so we can rewrite our test as:\n\n```python\n@given(lists(tuples(characters(), integers(1, 10))))\ndef test_encode_inverts_decode(s):\n    assert make_canonical(make_canonical(s)) == make_canonical(s)\n```\n\nThis property is called\nbeing idempotent (annoyingly \"idempotent\" gets used to mean something subtly different\nin most API design, but this is the original mathematical meaning).\n\nIt's less obviously necessary than the original one, and you can certainly\nwrite encode/decode pairs that are arguably correct but don't have it (e.g. because\nthey change the order of keys in a dictionary, or include a timestamp or sequence\nnumber in the output), but I think it's\nstill worth having and testing. Enforcing consistency like this both helps with debugging\nwhen things go wrong and also tends to flush out other bugs along the way.\n\nEven if you don't want to enforce this property, it highlights an important issue: You\ndo need *some* sort of testing of the decoder that doesn't just operate on output from\nthe encoder, because the encoder will potentially only output a relatively small subset\nof the valid range of the format.\n\nOften however you'll get the property for free. If the encode and decode functions\nhave the property that whenever x == y then f(x) == f(y), then this property automatically\nholds, because make_canonical(x) is encode(decode(encode(decode(x)))), and we know from the\nfirst property that decode(encode(t)) == t, so with t = decode(x) this expression is\nencode(decode(x)), which is make_canonical(x) as required.\n\nMost encode/decode pairs will have this property, but not all.\n\nThe easiest ways to fail to have it are to have side-effects (the aforementioned sequence\nnumber or randomization), but even without side effects it's possible for it to fail\nif equality doesn't capture every detail about the type. For example in\nPython, if 1.0 was serialized as 1, then the two would compare equal and the property\nwould pass, but when re-encoding it might exhibit very different properties (although\nyou'd hope that it wouldn't). Another example is that in Python an OrderedDict and a\ndict compare equal regardless of iteration order, which means that two apparently\nequal types might encode to different things if they have different iteration orders\ndefined.\n\nUltimately these issues are probably quite niche. It's likely still worth testing for\nthis property, both because of these problems and also because often [mathematically\nequivalent properties can still catch different issues](../tests-as-complete-specifications/),\nbut it's significantly less important than the more general property we started\nwith.\n\n--------------------------------------\n\nThanks to [Georges Dubus](https://twitter.com/georgesdubus) who pointed out\nthe key insight behind the last section on this property following from the original\none.\n"
  },
  {
    "path": "website/content/2016-10-31-hypothesis-3.6.0-release.md",
    "content": "---\ntags: news, python, non-technical\ndate: 2016-10-31 00:00\ntitle: 3.6.0 Release of Hypothesis for Python\nauthor: drmaciver\n---\n\nThis is a release announcement for the 3.6.0 release of Hypothesis for\nPython. It's a bit of an emergency release.\n\nHypothesis 3.5.0 inadvertently added a dependency on GPLed code (see below\nfor how this happened) which this release removes. This means that if you\nare running Hypothesis 3.5.x then there is a good chance you are in violation\nof the GPL and you should update immediately.\n\nApologies for any inconvenience this may have caused.\n\n<!--more-->\n\n### From the Changelog\n\nThis release reverts Hypothesis to its old pretty printing of lambda functions\nbased on attempting to extract the source code rather than decompile the bytecode.\nThis is unfortunately slightly inferior in some cases and may result in you\noccasionally seeing things like `lambda x: <unknown>` in statistics reports and\nstrategy reprs.\n\nThis removes the dependencies on uncompyle6, xdis and spark-parser.\n\nThe reason for this is that the new functionality was based on uncompyle6, which\nturns out to introduce a hidden GPLed dependency - it in turn depended on xdis,\nand although the library was licensed under the MIT license, it contained some\nGPL licensed source code and thus should have been released under the GPL.\n\nMy interpretation is that Hypothesis itself was never in violation of the GPL\n(because the license it is under, the Mozilla Public License v2, is fully\ncompatible with being included in a GPL licensed work), but I have not consulted\na lawyer on the subject. Regardless of the answer to this question, adding a\nGPLed dependency will likely cause a lot of users of Hypothesis to inadvertently\nbe in violation of the GPL.\n\nAs a result, if you are running Hypothesis 3.5.x you really should upgrade to\nthis release immediately.\n\n### Notes\n\nThis Halloween release brought to you by the specter of inadvertent GPL\nviolations (but sadly this is entirely real and neither trick nor treat).\n\nThis dependency also caused a number of other problems, so in many ways its\nnot entirely a bad thing that it's gone, but it's still sad to remove\nfunctionality. At some point in the future I will try to restore the\nlost functionality, but doing it without access to uncompyle6 will be a\nmoderate amount of work, so it's not going to be high priority in the\nnear future.\n"
  },
  {
    "path": "website/content/2016-12-05-integrated-shrinking.md",
    "content": "---\ntags: technical, details, python, alternatives\ndate: 2016-12-05 10:00\ntitle: Integrated vs type based shrinking\nauthor: drmaciver\n---\n\nOne of the big differences between Hypothesis and Haskell QuickCheck is\nhow shrinking is handled.\n\nSpecifically, the way shrinking is handled in Haskell QuickCheck is bad\nand the way it works in Hypothesis (and also in test.check and EQC) is\ngood. If you're implementing a property based testing system, you should\nuse the good way. If you're using a property based testing system and it\ndoesn't use the good way, you need to know about this failure mode.\n\nUnfortunately many (and possibly most) implementations of property based\ntesting are based on Haskell's QuickCheck and so make the same mistake.\n\n<!--more-->\n\nThe big difference is whether shrinking is integrated into generation.\n\nIn Haskell's QuickCheck, shrinking is defined based on *types*: Any\nvalue of a given type shrinks the same way, regardless of how it is\ngenerated. In Hypothesis, test.check, etc. instead shrinking is part\nof the generation, and the generator controls how the values it produces\nshrinks (this works differently in Hypothesis and test.check, and probably\ndifferently again in EQC, but the user visible result is largely the\nsame)\n\nThis is not a trivial distinction. Integrating shrinking into generation\nhas two large benefits:\n\n* Shrinking composes nicely, and you can shrink anything you can generate\n  regardless of whether there is a defined shrinker for the type produced.\n* You can guarantee that shrinking satisfies the same invariants as generation.\n\nThe first is mostly important from a convenience point of view: Although\nthere are some things it let you do that you can't do in the type based\napproach, they're mostly of secondary importance. It largely just saves\nyou from the effort of having to write your own shrinkers.\n\nBut the second is *really* important, because the lack of it makes your\ntest failures potentially extremely confusing.\n\nTo see this, lets consider the following example in Hypothesis:\n\n```python\nfrom hypothesis import given\nfrom hypothesis.strategies import integers\n\neven_numbers = integers().map(lambda x: x * 2)\n\n\n@given(even_numbers)\ndef test_even_numbers_are_even(n):\n    assert n % 2 == 0\n```\n\nThis test always passes: We generate an even number by multiplying\nan integer we've generated by two. No problem.\n\nNow suppose we made the test fail:\n\n\n```python\nfrom hypothesis import given\nfrom hypothesis.strategies import integers\n\neven_numbers = integers().map(lambda x: x * 2)\n\n\n@given(even_numbers)\ndef test_even_numbers_are_even(n):\n    assert n % 2 == 0\n    assert n <= 4\n```\n\nThis test will of course fail: Any value of n which is at least 5 will\nfail the test.\n\nBut which assertion will fail, and what value will cause it to fail?\n\nIn Hypothesis it's the second one, and it will fail with n=6: The numbers\npassed in will still always be even integers, and the smallest even\ninteger which fails the test is 6.\n\nBut suppose Hypothesis implemented type based shrinking (very early\nversions of it *did* implement type based shrinking, but this stopped\nbeing the case somewhere well before 1.0 when the API looked very\ndifferent).\n\nIn that case Hypothesis would just know that these things that were\nfailing the tests were integers, so it would say \"How about 1? 1 is a\nperfectly valid integer. Lets try 1\".\n\nIt would pass in n=1, the first assertion would trigger, and the test\nwould promptly fail. A successful shrink!\n\nBut it's completely not what we wanted. We were just trying to test on\neven integers and the shrinking messed this up.\n\nThis is in some sense the classic\n[shrinkers are fuzzers](http://blog.regehr.org/archives/1284) problem\nwhere an error is reduced to a different error, but it's a particularly\nannoying version of that because an error we care about is being reduced\nto an error we don't care about.\n\nSo we have to duplicate\nthe constraint logic in our test to make this work:\n\n\n```python\nfrom hypothesis import assume, given\nfrom hypothesis.strategies import integers\n\neven_numbers = integers().map(lambda x: x * 2)\n\n\n@given(even_numbers)\ndef test_even_numbers_are_even(n):\n    assume(n % 2 == 0)\n    assert n % 2 == 0\n    assert n <= 4\n```\n\n(Having both the assume and the first assert there is of course\nredundant)\n\nIn this example the problem was relatively obvious and so easy to\nwork around, but as your invariants get more implicit and subtle\nit becomes really problematic: In Hypothesis it's easy and\nconvenient to\n[generate quite complex data](../generating-the-right-data/),\nand trying to recreate the invariants that are automatically\nsatisfied with that in your tests and/or your custom shrinkers would\nquickly become a nightmare.\n\nI don't think it's an accident that the main systems to get this right are\nin dynamic languages. It's certainly not *essential* - [the original proposal that\nled to the implementation for test.check was for\nHaskell](https://mail.haskell.org/pipermail/libraries/2013-November/021674.html),\nand [Jack](https://github.com/ambiata/disorder.hs/tree/master/disorder-jack) is\nan alternative property based system for Haskell that does this - but you\nfeel the pain much more quickly in dynamic languages because the typical\nworkaround for this problem in Haskell is to define a newtype, which lets you\nturn off the default shrinking for your types and possibly define your own.\n\nBut that's a workaround for a problem that shouldn't be there in the first place,\nand using it will still result in your having to encode the invariants into your\nyour shrinkers, which is more work and more brittle than just having it work\nautomatically.\n\nSo although (as far as I know) none of the currently popular property based\ntesting systems for statically typed languages implement this behaviour\ncorrectly, they absolutely can and they absolutely should. It will improve\nusers' lives significantly.\n\nThis of course goes doubly for dynamic languages, where even working around\nthis problem is hard.\n\nSo, in conclusion, just say no to type based shrinking. It's a bad idea,\nand failures your property based tests will become significantly harder\nto understand in its presence.\n"
  },
  {
    "path": "website/content/2016-12-08-compositional-shrinking.md",
    "content": "---\ntags: technical, details, python, alternatives\ndate: 2016-12-08 9:00\ntitle: Compositional shrinking\nauthor: drmaciver\n---\n\nIn [my last article about shrinking](../integrated-shrinking/),\nI discussed the problems with basing shrinking on the type of the values\nto be shrunk.\n\nIn writing it though I forgot that there was a halfway house which is\nalso somewhat bad (but significantly less so) that you see in a couple\nof implementations.\n\nThis is when the shrinking is not type based, but still follows the\nclassic shrinking API that takes a value and returns a lazy list of\nshrinks of that value. Examples of libraries that do this are\n[theft](https://github.com/silentbicycle/theft) and\n[QuickTheories](https://github.com/NCR-CoDE/QuickTheories).\n\nThis works reasonably well and solves the major problems with type\ndirected shrinking, but it's still somewhat fragile and importantly\ndoes not compose nearly as well as the approaches that Hypothesis\nor test.check take.\n\nIdeally, as well as not being based on the types of the values being\ngenerated, shrinking should not be based on the actual values generated\nat all.\n\nThis may seem counter-intuitive, but it actually works pretty well.\n\n<!--more-->\n\nRather than going into implementation details just yet, lets start\nwith why this is important.\n\nConsider the example from the last post:\n\n\n```python\nfrom hypothesis import given\nfrom hypothesis.strategies import integers\n\neven_numbers = integers().map(lambda x: x * 2)\n\n\n@given(even_numbers)\ndef test_even_numbers_are_even(n):\n    assert n % 2 == 0\n```\n\nWe took a strategy and composed it with a function mapping over\nthe values that that strategy produced to get a new strategy.\n\nSuppose the Hypothesis strategy implementation looked something\nlike the following:\n\n```python\nclass SearchStrategy:\n    def generate(self, random):\n        raise NotImplementedErro()\n\n    def shrink(self, value):\n        return ()\n```\n\ni.e. we can generate a value and we can shrink a value that we've\npreviously generated. By default we don't know how to generate values\n(subclasses have to implement that) and we can't shrink anything,\nwhich subclasses are able to fix if they want or leave as is if\nthey're fine with that.\n\n(This is in fact how a very early implementation of it looked)\n\nThis is essentially the approach taken by theft or QuickTheories,\nand the problem with it is that under this implementation the\n'map' function we used above is impossible to define in a way\nthat preserves shrinking: In order to shrink a generated value,\nyou need some way to invert the function you're composing with\n(which is in general impossible even if your language somehow\nexposed the facilities to do it, which it almost certainly\ndoesn't) so you could take the generated value, map it back\nto the value that produced it, shrink that and then compose\nwith the mapping function.\n\nHypothesis and test.check both support even more complicated\ncomposition of strategies (Hypothesis somewhat better than\ntest.check - both support the same operations, but Hypothesis's\nunderlying implementation works somewhat better for more\ncomplicated compositions), but even the simplest of compositions\nfails if you need to be able to shrink arbitrary values.\n\nThe key idea for fixing this is as follows: In order to shrink\n*outputs* it almost always suffices to shrink *inputs*. Although\nin theory you can get functions where simpler input leads to more\ncomplicated output, in practice this seems to be rare enough\nthat it's OK to just shrug and accept more complicated test\noutput in those cases.\n\nGiven that, the way to shrink the output of a mapped strategy\nis to just shrink the value generated from the first strategy\nand feed it to the mapping function.\n\nWhich means that you need an API that can support that sort\nof shrinking.\n\nThe way this works in test.check is that instead of generating\na single value it generates an entire (lazy) tree of values\nwith shrinks for them. See [Reid Draper's article on the\nsubject](http://reiddraper.com/writing-simple-check/) for slightly\nmore detail.\n\nThis supports mapping fairly easily: We just apply the mapping\nfunction to the rose tree - both the initial generated value,\nand all the shrunk child values.\n\nHypothesis's implementation is more complicated so will have to\nwait for another article, but the key idea behind it is that\nHypothesis takes the \"Shrinking outputs can be done by shrinking\ninputs\" idea to its logical conclusion and has a single unified\nintermediate representation that *all* generation is based off.\nStrategies can provide hints about possibly useful shrinks to\nperform on that representation, but otherwise have very little\ncontrol over the shrinking process at all. This supports mapping\neven more easily, because a strategy is just a function which\ntakes an IR object and returns a value, so the mapped strategy\njust does the same thing and applies the mapping function.\n\nObviously I think Hypothesis's implementation is better, but\ntest.check's implementation is entirely respectable too and\nis probably easier to copy right now if you're implementing\na property based testing system from scratch.\n\nBut I do think that whichever one you start from it's important\nto take away the key idea: You can shrink outputs by shrinking\ninputs, and strategies should compose in a way that preserves\nshrinking.\n\nThe result is significantly more convenient to use because it\nmeans that users will rarely or never have to write their own\nshrinking functions, and there are fewer possible places for\nshrinking and generation to get out of sync.\n"
  },
  {
    "path": "website/content/2016-12-10-how-hypothesis-works.md",
    "content": "---\ntags: python, details, technical\ndate: 2016-12-10 11:00\ntitle: How Hypothesis Works\nauthor: drmaciver\n---\n\nHypothesis has a very different underlying implementation to any other\nproperty-based testing system. As far as I know, it's an entirely novel\ndesign that I invented.\n\nCentral to this design is the following feature set which *every*\nHypothesis strategy supports automatically (the only way to break\nthis is by having the data generated depend somehow on external\nglobal state):\n\n1. All generated examples can be safely mutated\n2. All generated examples can be saved to disk (this is important because\n   Hypothesis remembers and replays previous failures).\n3. All generated examples can be shrunk\n4. All invariants that hold in generation must hold during shrinking (\n   though the probability distribution can of course change, so things\n   which are only supported with high probability may not be).\n\n(Essentially no other property based systems manage one of these claims,\nlet alone all)\n\nThe initial mechanisms for supporting this were fairly complicated, but\nafter passing through a number of iterations I hit on a very powerful\nunderlying design that unifies all of these features.\n\nIt's still fairly complicated in implementation, but most of that is\noptimisations and things needed to make the core idea work. More\nimportantly, the complexity is quite contained: A fairly small kernel\nhandles all of the complexity, and there is little to no additional\ncomplexity (at least, compared to how it normally looks) in defining\nnew strategies, etc.\n\nThis article will give a high level overview of that model and how\nit works.\n\n<!--more-->\n\nHypothesis consists of essentially three parts, each built on top\nof the previous:\n\n1. A low level interactive byte stream fuzzer called *Conjecture*\n2. A strategy library for turning Conjecture's byte streams into\n   high level structured data.\n3. A testing interface for driving test with data from Hypothesis's\n   strategy library.\n\nI'll focus purely on the first two here, as the latter is complex\nbut mostly a matter of plumbing.\n\nThe basic object exposed by Conjecture is a class called TestData,\nwhich essentially looks like an open file handle you can read\nbytes from:\n\n```python\nclass TestData:\n    def draw_bytes(self, n): ...\n```\n\n(note: The Python code in this article isn't an exact copy of what's\nfound in Hypothesis, but has been simplified for pedagogical reasons).\n\nA strategy is then just an object which implements a single abstract\nmethod from the strategy class:\n\n```python\nclass SearchStrategy:\n    def do_draw(self, data):\n        raise NotImplementedError()\n```\n\nThe testing interface then turns test functions plus the strategies\nthey need into something that takes a TestData object and returns\nTrue if the test fails and False if it passes.\n\nFor a simple example, we can implement a strategy for unsigned\n64-bit integers as follows:\n\n\n```python\nclass Int64Strategy:\n    def do_draw(self, data):\n        return int.from_bytes(data.draw_bytes(8), byteorder=\"big\", signed=False)\n```\n\nAs well as returning bytes, draw_bytes can raise an exception\nthat stops the test. This is useful as a way to stop examples\nfrom getting too big (and will also be necessary for shrinking,\nas we'll see in a moment).\n\nFrom this it should be fairly clear how we support saving and\nmutation: Saving every example is possible because we can just\nwrite the bytes that produced it to disk, and mutation is possible\nbecause strategies are just returning values that we don't\nin any way hang on to.\n\nBut how does shrinking work?\n\nWell the key idea is the one I mentioned in\n[my last article about shrinking\n](../compositional-shrinking/) -\nshrinking inputs suffices to shrink outputs. In this case the\ninput is the byte stream.\n\nOnce Hypothesis has found a failure it begins shrinking the\nbyte stream using a TestData object that looks like the following:\n\n```python\nclass ShrinkingTestData:\n    def __init__(self, data):\n        self.data = data\n        self.index = 0\n\n    def draw_bytes(self, n):\n        if self.index + n > len(self.data):\n            raise StopTest()\n        result = self.data[self.index : self.index + n]\n        self.index += n\n        return result\n```\n\nShrinking now reduces to shrinking the byte array that gets\npassed in as data, subject to the condition that our transformed\ntest function still returns True.\n\nShrinking of the byte array is designed to try to minimize it\naccording to the following rules:\n\n1. Shorter is always simpler.\n2. Given two byte arrays of the same length, the one which is\n   lexicographically earlier (considering bytes as unsigned 8\n   bit integers) is simpler.\n\nYou can imagine that some variant of [Delta Debugging](https://en.wikipedia.org/wiki/Delta_Debugging)\nis used for the purpose of shrinking the byte array,\nrepeatedly deleting data and lowering bytes until no\nbyte may be deleted or lowered. It's a lot more complicated\nthan that, but I'm mostly going to gloss over that part\nfor now.\n\nAs long as the strategy is well written (and to some extent\neven when it's not - it requires a certain amount of active\nsabotage to create strategies that produce more complex data\ngiven fewer bytes) this results in shrinks to the byte array\ngiving good shrinks to the generated data. e.g. our 64-bit\nunsigned integers are chosen to be big endian so that\nshrinking the byte data lexicographically shrinks the integer\ntowards zero.\n\nIn order to get really good deleting behaviour in our strategies\nwe need to be a little careful about how we arrange things, so\nthat deleting in the underlying bytestream corresponds to\ndeleting in generated data.\n\nFor example, suppose we tried to implement lists as follows:\n\n\n```python\nclass ListStrategy(SearchStrategy):\n    def __init__(self, elements):\n        super().__init__()\n        self.elements = elements\n\n    def do_draw(self, data):\n        n_elements = integers(0, 10).do_draw(self.elements)\n        return [self.elements.do_draw(data) for _ in range(n_elements)]\n```\n\nThe problem with this is that deleting data doesn't actually\nresult in deleting elements - all that will happen is that\ndrawing will run off the end of the buffer. You can\npotentially shrink n_elmements, but that only lets you\ndelete things from the end of the list and will leave a\nbunch of left over data at the end if you do - if this is\nthe last data drawn that's not a problem, and it might be\nOK anyway if the data usefully runs into the next strategy,\nbut it works fairly unreliably.\n\nI am in fact working on an improvement to how shrinking works\nfor strategies that are defined like this - they're quite\ncommon in user code, so they're worth supporting - but it's\nbetter to just have deletion of elements correspond to\ndeletion of data in the underlying bytestream. We can do\nthis as follows:\n\n\n```python\nclass ListStrategy(SearchStrategy):\n    def __init__(self, elements):\n        super().__init__()\n        self.elements = elements\n\n    def do_draw(self, data):\n        result = []\n        while booleans().do_draw(data):\n            result.append(self.elements.do_draw(data))\n        return result\n```\n\nWe now draw lists as a series True, element,\nTrue, element, ..., False, etc. So if you delete the\ninterval in the byte stream that starts with a True\nand finishes at the end of an element, that just deletes\nthat element from the list and shifts everything afterwards\nleft one space.\n\nGiven some careful strategy design this ends up working\npretty well. It does however run into problems in two\nminor cases:\n\n1. It doesn't generate very good data\n2. It doesn't shrink very well\n\nFortunately both of these are fixable.\n\nThe reason for the lack of good data is that Conjecture\ndoesn't know enough to produce a good distribution of bytes\nfor the specific special values for your strategy. e.g. in\nour unsigned 64 bit integer examples above it can probably\nguess that 0 is a special value, but it's not necessarily\nobvious that e.g. focusing on small values is quite useful.\n\nThis gets worse as you move further away from things that\nlook like unsigned integers. e.g. if you're turning bytes\ninto floats, how is Conjecture supposed to know that\nInfinity is an interesting value?\n\nThe simple solution is to allow the user to provide a\ndistribution hint:\n\n\n```python\nclass TestData:\n    def draw_bytes(self, n, distribution=None): ...\n```\n\nWhere a distribution function takes a Random object\nand a number of bytes.\n\nThis lets users specify the distribution of bytes. It\nwon't necessarily be respected - e.g. it certainly isn't\nin shrinking, but the fuzzer can and does mutate the\nvalues during generation too - but it provides a good\nstarting point which allows you to highlight special\nvalues, etc.\n\nSo for example we could redefine our integer strategy\nas:\n\n\n```python\nclass Int64Strategy:\n    def do_draw(self, data):\n        def biased_distribution(random, n):\n            if random.randint(0, 1):\n                return random.randint(0, 100).to_bytes(n, byteorder=\"big\", signed=False)\n            else:\n                return uniform(random, n)\n\n        return int.from_bytes(\n            data.draw_bytes(8, biased_distribution), byteorder=\"big\", signed=False\n        )\n```\n\nNow we have a biased integer distribution which will\nproduce integers between 0 and 100 half the time.\n\nWe then use the strategies to generate our initial\nbuffers. For example we could pass in a TestData\nimplementation that looked like this:\n\n```python\nclass GeneratingTestData(TestData):\n    def __init__(self, random, max_bytes):\n        self.max_bytes = max_bytes\n        self.random = random\n        self.record = bytearray()\n\n    def draw_bytes(self, n, distribution):\n        if n + len(self.record) > self.max_bytes:\n            raise StopTest()\n        result = distribution(self.random, n)\n        self.record.extend(result)\n        return result\n```\n\nThis draws data from the provided distribution\nand records it, so at the end we have a record of\nall the bytes we've drawn so that we can replay\nthe test afterwards.\n\nThis turns out to be mostly enough. I've got some\npending research to replace this API with something\na bit more structured (the ideal would be that instead\nof opaque distribution objects you draw from an explicit\nmixture of grammars), but for the moment research on\nbig changes like that is side lined because nobody is\nfunding Hypothesis development, so I've not got very far\nwith it.\n\nInitial designs tried to avoid this approach by using\ndata from the byte stream to define the distribution,\nbut this ended up producing quite opaque structures in\nthe byte stream that didn't shrink very well, and this\nturned out to be simpler.\n\nThe second problem of it not shrinking well is also\nfairly easily resolved: The problem is not that we\n*can't* shrink it well, but that shrinking ends up\nbeing slow because we can't tell what we need to\ndo: In our lists example above, the only way we\ncurrently have to delete elements is to delete the\ncorresponding intervals, and the only way we have\nto find the right intervals is to try *all* of them.\nThis potentially requires O(n^2) deletions to get the\nright one.\n\nThe solution is just to do a bit more book keeping as we\ngenerate data to mark useful intervals. TestData now\nlooks like this:\n\n```python\nclass TestData:\n    def start_interval(self): ...\n\n    def stop_interval(self): ...\n\n    def draw_bytes(self, n): ...\n\n    def draw(self, strategy):\n        self.start_interval()\n        result = strategy.do_draw(self)\n        self.stop_interval()\n        return result\n```\n\n\nWe then pass everything through data.draw instead\nof strategy.do_draw to maintain this bookkeeping.\n\nThese mark useful boundaries in the bytestram that\nwe can try deleting: Intervals which don't cross a\nvalue boundary are much more likely to be useful to\ndelete.\n\nThere are a large number of other details that are\nrequired to make Hypothesis work: The shrinker and\nthe strategy library are both carefully developed\nto work together, and this requires a fairly large\nnumber of heuristics and special cases to make things\nwork, as well as a bunch of book keeping beyond the\nintervals that I've glossed over.\n\nIt's not a perfect system, but it works and works well:\nThis has been the underlying implementation of Hypothesis\nsince the 3.0 release in early 2016, and the switch over\nwas nearly transparent to end users: the previous\nimplementation was much closer to a classic QuickCheck\nmodel (with a great deal of extra complexity to support\nthe full Hypothesis feature set).\n\nIn a lot of cases it even works better than heavily\ncustomized solutions: For example, a benefit of the byte\nbased approach is that all parts of the data are\nfully comprehensible to it. Often more structured\nshrinkers get stuck in local minima because shrinking\none part of the data requires simultaneously shrinking\nanother part of the data, whileas Hypothesis can just\nspot patterns in the data and speculatively shrink\nthem together to see if it works.\n\nThe support for chaining data generation together\nis another thing that benefits here. In Hypothesis\nyou can chain strategies together like this:\n\n\n```python\nclass SearchStrategy:\n    def do_draw(self, data):\n        raise NotImplementedError()\n\n    def flatmap(self, bind):\n        return FlatmappedStrategy(self, bind)\n\n\nclass FlatmappedStrategy(SearchStrategy):\n    def __init__(self, base, bind):\n        super().__init__()\n        self.base = base\n        self.bind = bind\n\n    def do_draw(self, data):\n        value = data.draw(self.base)\n        return data.draw(self.bind(value))\n```\n\nThe idea is that flatmap lets you chain strategy definitions together by\ndrawing data that is dependent on a value from other strategies.\n\nThis works fairly well in modern Hypothesis, but has historically (e.g. in\ntest.check or pre 3.0 Hypothesis) been a problem for integrated testing and\ngeneration.\n\nThe reason this is normally a problem is that if you shrink the first value\nyou've drawn then you essentially *have* to invalidate the value drawn from\nbind(value): There's no real way to retain it because it came from a completely\ndifferent generator. This potentially results in throwing away a lot of\nprevious work if a shrink elsewhere suddenly makes it to shrink the\ninitial value.\n\nWith the Hypothesis byte stream approach this is mostly a non-issue: As long as\nthe new strategy has roughly the same shape as the old strategy it will just\npick up where the old shrinks left off because they operate on the same\nunderlying byte stream.\n\nThis sort of structure *does* cause problems for Hypothesis if shrinking the\nfirst value would change the structure of the bound strategy too much, but\nin practice it usually seems to work out pretty well because there's enough\nflexibility in how the shrinks happen that the shrinker can usually work past\nit.\n\nThis model has proven pretty powerful even in its current form, but there's\nalso a lot of scope to expand it.\n\nBut hopefully not by too much. One of the advantages of the model in its\ncurrent form though is its simplicity. The [Hypothesis for Java\nprototype](https://github.com/HypothesisWorks/hypothesis-java) was written in\nan afternoon and is pretty powerful. The whole of the Conjecture implementation\nin Python is a bit under a thousand significant lines of fairly portable code.\nAlthough the strategy library and testing interface are still a fair bit of\nwork, I'm still hopeful that the Hypothesis/Conjecture approach is the tool\nneeded to bring an end to the dark era of property based testing libraries\nthat don't implement shrinking at all.\n"
  },
  {
    "path": "website/content/2017-03-09-hypothesis-for-researchers.md",
    "content": "---\ntags: python, details, technical\ndate: 2017-03-09 11:00\ntitle: Hypothesis for Computer Science Researchers\nauthor: drmaciver\n---\n\nI'm in the process of [trying to turn my work on Hypothesis into a PhD](http://www.drmaciver.com/2017/03/looking-into-starting-a-phd/)\nand I realised that I don't have a good self-contained summary as to why researchers should care about it.\n\nSo this is that piece. I'll try to give a from scratch introduction to the why and what of Hypothesis. It's primarily\nintended for potential PhD supervisors, but should be of general interest as well (especially if you\nwork in this field).\n\n### Why should I care about Hypothesis from a research point of view?\n\nThe short version:\n\nHypothesis takes an existing effective style of testing (property-based testing) which has proven highly effective in practice\nand makes it accessible to a much larger audience. It does so by taking several previously unconnected ideas from the existing\nresearch literature on testing and verification, and combining them to produce a novel implementation that has proven very effective\nin practice.\n\nThe long version is the rest of this article.\n\n<!--more-->\n\nThe remainder is divided into several sections:\n\n* [What is Hypothesis?](#what-is-hypothesis) is a from-scratch introduction to Hypothesis. If you are already familiar with\n  property-based testing (e.g. from QuickCheck) you can probably skip this.\n* [How is Hypothesis innovative?](#how-is-hypothesis-innovative) is about the current state of the art of Hypothesis and why\n  it's interesting. If you've already read [How Hypothesis Works](http://hypothesis.works/articles/how-hypothesis-works/) this\n  is unlikely to teach you anything new and you can skip it.\n* [What prior art is it based on?](#what-prior-art-is-it-based-on) is a short set of references for some of the inspirations\n  for Hypothesis. You probably shouldn't skip this, because it's short and the linked material is all interesting.\n* [What are some interesting research directions?](#what-are-some-interesting-research-directions) explores possible directions\n  I'm looking into for the future of Hypothesis, some of which I would hope to include in any PhD related to it that I worked\n  on. You probably shouldn't skip this if you care about this document at all.\n* [What should you do with this information?](#what-should-you-do-with-this-information) simply closes off the article and\n  winds things down.\n\nSo, without further ado, the actual content.\n\n### What is Hypothesis?\n\nHypothesis is an implementation of *property-based testing*, an idea that originated with a Haskell library called QuickCheck.\n\nProperty-based testing is a way to augment your unit tests with a source of structured random data that allows a tool to explore\nthe edge cases of your tests and attempt to find errors automatically. I've made a [longer and more formal discussion](http://hypothesis.works/articles/what-is-property-based-testing/)\nof this definition in the past.\n\nAn example of a property-based test using Hypothesis:\n\n```python\nfrom hypothesis import given, strategies as st\n\n\n@given(st.lists(st.integers()))\ndef test_sort_is_idempotent(ls):\n    sort1 = sorted(ls)\n    assert sorted(sort1) == sort1\n```\n\nThis exposes a normal function which can be picked up by a standard runner such as py.test. You can also just call it\ndirectly:\n\n```python\nif __name__ == \"__main__\":\n    test_sort_is_idempotent()\n```\n\nWhen the test is run, Hypothesis will generate random lists of integers\nand pass them to the test. The test sorts the integers, then sorts them again, and asserts that the two results are the same.\n\nAs long as the test passes for every input Hypothesis feeds it this will appear to be a normal test. If it fails however,\nHypothesis will then repeatedly rerun it with progressively simpler examples to try and find a minimal input that causes\nthe failure.\n\nTo see this, suppose we implemented the following rather broken implementation of sorted:\n\n```python\ndef sorted(ls):\n    return list(reversed(ls))\n```\n\nThen on running we would see the following output:\n\n```\n      @given(st.lists(st.integers()))\n      def test_sort_is_idempotent(ls):\n        sort1 = sorted(ls)\n  >     assert sorted(sort1) == sort1\n  E     assert [0, 1] == [1, 0]\n  E       At index 0 diff: 0 != 1\n  E       Use -v to get the full diff\n\n  sorting.py:12: AssertionError\n\n  ---- Hypothesis ----\n\n  Falsifying example: test_sort_is_idempotent(ls=[0, 1])\n```\n\nHypothesis probably started with a much more complicated example (the test fails for essentially any list with more\nthan one element) and then successfully reduced it to the simplest possible example: A list with two distinct elements.\n\nImportantly, when the test is rerun, Hypothesis will start from the falsifying example it found last time rather than\ntrying to generate and shrink a new one from scratch. In this particular case that doesn't matter very much - the\nexample is found very quickly and it always finds the same one - but for more complex and slower tests this is an\nvital part of the development workflow: It means that tests run much faster and don't stop failing until\nthe bug is actually fixed.\n\nTests can also draw more data as they execute:\n\n```python\n@given(st.lists(st.integers(), min_size=1), st.data())\ndef test_sort_is_idempotent(ls, data):\n    ls.sort()\n    i = data.draw(st.integers(0, len(ls) - 1))\n    assert ls[i - 1] <= ls[i]\n```\n\nThis fails because we've forgotten than `i` may be zero, and also about Python's negative indexing of lists:\n\n```\n      @given(st.lists(st.integers(), min_size=1), st.data())\n      def test_sort_is_idempotent(ls, data):\n          ls.sort()\n          i = data.draw(st.integers(0, len(ls) - 1))\n  >       assert ls[i - 1] <= ls[i]\n  E       assert 1 <= 0\n\n  sorting.py:15: AssertionError\n\n  ---- Hypothesis ----\n\n  Falsifying example: test_sort_is_idempotent(ls=[0, 1], data=data(...))\n  Draw 1: 0\n```\n\nSimplification and example saving work as normal for data drawn in this way.\n\nHypothesis also has a form of [model based testing](http://hypothesis.works/articles/rule-based-stateful-testing/),\nin which you specify a set of valid operations on your API and it attempts to generate whole programs using those\noperations and find a simple one that breaks.\n\n### How is Hypothesis innovative?\n\nFrom an end user point of view, Hypothesis adds several important things:\n\n* It exists at all and people use it. Historically this sort of testing has been found mostly within the functional\n  programming community, and attempts to make it work in other languages have not seen much success or widespread\n  adoption. Some of this is due to novel implementation details in Hypothesis, and some is due to design decisions\n  making it \"feel\" like normal testing instead of formal methods.\n* Specifying data generators is much easier than in traditional QuickCheck methods, and you get a great deal more\n  functionality \"for free\" when you do. This is similar to [test.check](https://github.com/clojure/test.check) for\n  Clojure, or indeed to the [Erlang version of QuickCheck](http://www.quviq.com/products/erlang-quickcheck/), but\n  some of the design decisions of Hypothesis make it significantly more flexible here.\n* The fact that arbitrary examples can be saved and replayed significantly improves the development work-flow. Other\n  implementations of property-based testing either don't do this at all, only save the seed, or rely on being able to\n  serialize the generated objects (which can break invariants when reading them back in).\n* The fact that you can generate additional data within the test is often extremely useful, and seems to be unique\n  to Hypothesis in this category of testing tool.\n\nThese have worked together well to fairly effectively bring property based testing \"to the masses\", and Hypothesis\nhas started to see increasingly widespread use within the Python community, and is being actively used in the\ndevelopment of tools and libraries, as well as in the development of both CPython and pypy, the two major implementations\nof Python.\n\nMuch of this was made possible by Hypothesis's novel implementation.\n\nFrom an implementation point of view, the novel feature of Hypothesis is this: Unlike other implementations of\nproperty-based testing, it does not need to understand the structure of the data it is generating at all (it sometimes\nhas to make guesses about it, but its correctness is not dependent on the accuracy of those guesses).\n\nHypothesis is divided into three logically distinct parts:\n\n1. A core engine called *Conjecture*, which can be thought of as an interactive fuzzer for lightly structured byte streams.\n2. A strategy library, which is designed to take Conjecture's output and turn it into arbitrary values representable\n   in the programming language.\n3. An interface to external test runners that takes tests built on top of the strategy library and runs them using Conjecture\n   (in Python this mostly just consists of exposing a function that the test runners can pick up, but in the\n   [Java Prototype](http://github.com/HypothesisWorks/hypothesis-java) this is more involved and ends up having\n   to interact with some interesting JUnit specific features.\n\nConjecture is essentially the interesting part of Hypothesis's implementation and is what supports most of its functionality:\nGeneration, shrinking, and serialization are all built into the core engine, so implementations of strategies do not require\nany awareness of these features to be correct. They simply repeatedly ask the Conjecture engine for blocks of bytes, which\nit duly provides, and they return the desired result.\n\nIf you want to know more about this, I have previously written\n[How Hypothesis Works](http://hypothesis.works/articles/how-hypothesis-works/), which provides a bit more detail\nabout Conjecture and how Hypothesis is built on top of it.\n\n### What prior art is it based on?\n\nI've done a fair bit of general reading of the literature in the course of working on Hypothesis.\n\nThe two main papers on which Hypothesis is based are:\n\n* [QuickCheck: a lightweight tool for random testing of Haskell programs](https://dl.acm.org/citation.cfm?id=351266) essentially\n  started the entire field of property-based testing. Hypothesis began life as a QuickCheck implementation, and its user facing\n  API continues to be heavily based on QuickCheck, even though the implementation has diverged very heavily from it.\n* [EXPLODE: a lightweight, general system for finding serious storage system errors](https://dl.acm.org/citation.cfm?id=1298469)\n  provided the key idea on which the Conjecture engine is based - instead of doing static data generation separate from the tests,\n  provide tests with an interactive primitive from which they can draw data.\n\nAdditionally, the following are major design inspirations in the Conjecture engine, although their designs are not currently\nused directly:\n\n* [American Fuzzy Lop](http://lcamtuf.coredump.cx/afl/) is an excellent security-oriented fuzzer, although one without much\n  academic connections. I've learned a fair bit about the design of fuzzers from it. For a variety of pragmatic reasons I don't\n  currently use its most important innovation (branch coverage metrics as a tool for corpus discovery), but I've successfully\n  prototyped implementations of that on top of Hypothesis which work pretty well.\n* [Swarm Testing](https://dl.acm.org/citation.cfm?id=2336763) drove a lot of the early designs of Hypothesis's data generation.\n  It is currently not explicitly present in the Conjecture implementation, but some of what Conjecture does to induce deliberate\n  correlations in data is inspired by it.\n\n### What are some interesting research directions?\n\nI have a large number of possible directions that my work on Hypothesis could be taken.\n\nNone of these are *necessarily* a thing that would be the focus of a PhD - in doing a PhD I would almost certainly\nfocus on a more specific research question that might include some or all of them. These are just areas that I am interested\nin exploring which I think might form an interesting starting point, and whatever focus I actually end up with will likely\nbe more carefully tailored in discussion with my potential supervisors.\n\nOne thing that's also worth considering: Most of these research directions are ones that would result in improvements\nto Hypothesis without changing its public interface. This results in a great practical advantage to performing the\nresearch because of the relatively large (and ever-growing) corpus of open source projects which are already using\nHypothesis - many of these changes could at least partly be validated by just running peoples' existing tests and seeing\nif any new and interesting bugs are found!\n\nWithout further ado, here are some of what I think are the most interesting directions to go next.\n\n#### More structured byte streams\n\nMy current immediate research focus on Hypothesis is to replace the core Conjecture primitive with a more structured one\nthat bears a stronger resemblance to its origins in EXPLODE. This is designed to address a number of practical problems\nthat Hypothesis users currently experience (mostly performance related), but it also opens up a number of other novel\nabstractions that can be built on top of the core engine.\n\nThe idea is to pare down the interface so that when calling in to Conjecture you simply draw a single byte, specifying\na range of possible valid bytes. This gives Conjecture much more fine-grained information to work with, which opens up\na number of additional features and abstractions that can be built on top of it.\n\nFrom this primitive you can then rebuild arbitrary weighted samplers that shrink correctly (using a variation of the\nAlias Method), and arbitrary grammars (probably using [Boltzmann Samplers](https://dl.acm.org/citation.cfm?id=1024669)\n or similar).\n\nThis will provide a much more thorough basis for high quality data generation than the current rather ad hoc method\nof specifying byte streams.\n\nThis is perhaps more engineering than research, but I think it would at the bare minimum make any paper I wrote about\nthe core approach of Hypothesis significantly more compelling, and it contains a number of interesting applications of\nthe theory.\n\n#### Glass box testing\n\nCurrently Conjecture treats the tests it calls as a black box and does not get much information about what the tests\nit executes are actually doing.\n\nOne obvious thing to do which brings in some more ideas from e.g. American Fuzzy Lop is to use more coverage information,\nbut so far I haven't had much success with making my prototypes of this idea suitable for real world use. The primary\nreason for this so far has been that all of the techniques I've found have worked well when tests are allowed\nto run for minutes or hours, but the current design focus of Hypothesis assumes tests have seconds to run at most,\nwhich limits the utility of these methods and means they haven't been a priority so far.\n\nBut in principle this should be an extremely profitable line of attack, even with that limitation, and I would like\nto explore it further.\n\nThe main idea would be to add a notion of \"tags\" to the core Conjecture engine which could be used to guide the\nsearch. Coverage would be one source of tags, but others are possible. For example, my previous work on\n[Schroedinteger](https://github.com/DRMacIver/schroedinteger) implements what is essentially a form of lightweight\n[Concolic testing](https://en.wikipedia.org/wiki/Concolic_testing) that would be another possibly interesting source\nof information to use.\n\nExactly how much of this is original research and how much is just applications of existing research is yet to be\ndetermined, but I think it very likely that at the very least figuring out how to make use of this sort of information\nin sharply bounded time is likely to bear interesting fruit. The opportunity to see how Concolic testing behaves in the\nwild is also likely to result in a number of additional questions.\n\n#### Making the Conjecture engine smarter\n\nA thing I've looked into in the past is the possible use of grammar inference to improve shrinking and data generation.\n\nAt the time the obstacle I ran into was that the algorithm I was using -\n[an optimized variation of L\\* search](https://dl.acm.org/citation.cfm?id=73047) - did not get good performance in\npractice on the problems I tried it on.\n\n[Synthesizing Program Input Grammars](https://arxiv.org/abs/1608.01723) promises to lift this restriction by providing\nmuch better grammar inference in practical scenarios that are quite closely related to this problem domain, so I would\nlike to revisit this and see if it can prove useful.\n\nThere are likely a number of other ways that the Conjecture engine can probe the state of the system under test\nto determine interesting potential behaviours, especially in combination with glass box testing features.\n\nI think there are a lot of potentially interesting research directions in here - especially if this is combined with\nthe glass box testing. Given that I haven't even been able to make this perform acceptably in the past, the first\none would be to see if I can!\n\nThis will also require a fair bit of practical experimentation to see what works well at actually finding bugs and what\ndoesn't. This is one area in particular where a corpus of open source projects tested with Hypothesis will be extremely\nhelpful.\n\n#### Other testing abstractions\n\nDespite Hypothesis primarily being a library for property based testing, the core Conjecture engine actually has\nvery little to do with property-based testing and is a more powerful low-level testing abstraction. It would be interesting\nto see how far that could be taken - the existing stateful/model-based testing is one partial step in that direction,\nbut it could also potentially be used more directly for other things. e.g. in tandem with some of the above features\nit could be used for low-level fuzzing of binaries, or using it to drive thread scheduling.\n\nThe nice thing about the Conjecture separation is that because it is so self-contained, it can be used as the core\nbuilding block on which other tools can be rebuilt and gain a lot of its major features for free.\n\nI don't currently have any concrete plans in this direction, but it seems likely there are some interesting possibilities\nhere that will emerge after more review of the testing literature.\n\nThis is probably just engineering unless some particularly interesting application emerges, but I think the basic\npotential of the technology would probably give pretty good odds of such an application.\n\n### What should you do with this information?\n\nIt depends who you are.\n\n* If I'm already talking to you because you're a potential PhD supervisor, tell me what about this interests you and\n  ask me lots of questions.\n* If you're a potential PhD supervisor who I'm *not* already talking to but you'd like me to, please let me know!\n* If you're somebody else, it's rather up to you. Feel free to send me papers, questions, etc.\n\nWhoever you are, if you found this document interesting I'd love to hear from you. Drop me an email at\n[david@drmaciver.com](mailto:david@drmaciver.com).\n"
  },
  {
    "path": "website/content/2017-04-05-how-not-to-die-hard-with-hypothesis.md",
    "content": "---\ntags: python, technical, intro\ndate: 2017-04-05 10:00\ntitle: Solving the Water Jug Problem from Die Hard 3 with TLA+ and Hypothesis\nauthor: nchammas\n---\n\n_This post was originally published on [the author's personal site](http://nchammas.com/writing/how-not-to-die-hard-with-hypothesis).\nIt is reproduced here with his permission._\n\nIn the movie [Die Hard with a Vengeance](https://en.wikipedia.org/wiki/Die_Hard_with_a_Vengeance)\n(aka Die Hard 3), there is\n[this famous scene](https://www.youtube.com/watch?v=6cAbgAaEOVE) where\nJohn McClane (Bruce Willis) and Zeus Carver (Samuel L. Jackson)\nare forced to solve a problem or be blown up: Given a 3 gallon jug and\n5 gallon jug, how do you measure out exactly 4 gallons of water?\n\n<div style=\"text-align: center;\">\n<iframe\n    width=\"560\"\n    height=\"315\"\n    src=\"https://www.youtube.com/embed/6cAbgAaEOVE?rel=0\"\n    frameborder=\"0\"\n    allowfullscreen>\n</iframe>\n<p>\n(The video title is wrong. It's Die Hard 3.)\n</p>\n</div>\n\n<!--more-->\n\nApparently, you can solve this problem using a formal specification\nlanguage like [TLA+](https://en.wikipedia.org/wiki/TLA%2B). I don't know\nmuch about this topic, but it appears that a [formal specification language](https://en.wikipedia.org/wiki/Formal_specification)\nis much like a programming language in that it lets you describe the\nbehavior of a system. However, it's much more rigorous and builds\non mathematical techniques that enable you to reason more effectively\nabout the behavior of the system you're describing than you can with\na typical programming language.\n\nIn a recent discussion on Hacker News about TLA+,\nI came across [this comment](https://news.ycombinator.com/item?id=13919251)\nwhich linked to a fun and simple example\nshowing [how to solve the Die Hard 3 problem with TLA+](https://github.com/tlaplus/Examples/blob/master/specifications/DieHard/DieHard.tla).\nI had to watch the first two lectures from [Leslie Lamport's video course on TLA+](http://lamport.azurewebsites.net/video/videos.html)\nto understand the example well, but once I did I was reminded of the\nidea of property-based testing and, specifically, [Hypothesis](http://hypothesis.works/).\n\nSo what's property-based testing? It's a powerful way of testing your\nlogic by giving your machine a high-level description of how your code\nshould behave and letting it generate test cases automatically to see\nif that description holds. Compare that to traditional unit testing,\nfor example, where you manually code up specific inputs and outputs\nand make sure they match.\n\n## How not to Die Hard with Hypothesis\n\nHypothesis has an excellent implementation of property-based testing\n[for Python](https://github.com/HypothesisWorks/hypothesis-python).\nI thought to myself: I wonder if you can write that\nDie Hard specification using Hypothesis? As it turns out, Hypothesis\nsupports [stateful testing](https://hypothesis.readthedocs.io/en/latest/stateful.html),\nand I was able to port the [TLA+ example](https://github.com/tlaplus/Examples/blob/master/specifications/DieHard/DieHard.tla)\nto Python pretty easily:\n\n```python\nfrom hypothesis import note, settings\nfrom hypothesis.stateful import RuleBasedStateMachine, invariant, rule\n\n\n# The default is not always enough for Hypothesis to find a failing example.\n@settings(max_examples=2000)\nclass DieHardProblem(RuleBasedStateMachine):\n    small = 0\n    big = 0\n\n    @rule()\n    def fill_small(self):\n        self.small = 3\n\n    @rule()\n    def fill_big(self):\n        self.big = 5\n\n    @rule()\n    def empty_small(self):\n        self.small = 0\n\n    @rule()\n    def empty_big(self):\n        self.big = 0\n\n    @rule()\n    def pour_small_into_big(self):\n        old_big = self.big\n        self.big = min(5, self.big + self.small)\n        self.small = self.small - (self.big - old_big)\n\n    @rule()\n    def pour_big_into_small(self):\n        old_small = self.small\n        self.small = min(3, self.small + self.big)\n        self.big = self.big - (self.small - old_small)\n\n    @invariant()\n    def physics_of_jugs(self):\n        assert 0 <= self.small <= 3\n        assert 0 <= self.big <= 5\n\n    @invariant()\n    def die_hard_problem_not_solved(self):\n        note(f\"> small: {self.small} big: {self.big}\")\n        assert self.big != 4\n\n\nDieHardTest = DieHardProblem.TestCase\n```\n\nCalling `pytest` on this file quickly digs up a solution:\n\n```\nself = DieHardProblem({})\n\n    @invariant()\n    def die_hard_problem_not_solved(self):\n        note(\"> small: {s} big: {b}\".format(s=self.small, b=self.big))\n>       assert self.big != 4\nE       AssertionError: assert 4 != 4\nE        +  where 4 = DieHardProblem({}).big\n\nhow-not-to-die-hard-with-hypothesis.py:17: AssertionError\n----------------------------- Hypothesis -----------------------------\n> small: 0 big: 0\nStep #1: fill_big()\n> small: 0 big: 5\nStep #2: pour_big_into_small()\n> small: 3 big: 2\nStep #3: empty_small()\n> small: 0 big: 2\nStep #4: pour_big_into_small()\n> small: 2 big: 0\nStep #5: fill_big()\n> small: 2 big: 5\nStep #6: pour_big_into_small()\n> small: 3 big: 4\n====================== 1 failed in 0.22 seconds ======================\n```\n\n## What's Going on Here\n\nThe code and test output are pretty self-explanatory, but here's a\nrecap of what's going on:\n\nWe're defining a state machine. That state machine has an initial\nstate (two empty jugs) along with some possible transitions. Those\ntransitions are captured with the `rule()` decorator. The initial\nstate and possible transitions together define how our system works.\n\nNext we define invariants, which are properties that must always hold\ntrue in our system. Our first invariant, `physics_of_jugs`, says that\nthe jugs must hold an amount of water that makes sense. For example,\nthe big jug can never hold more than 5 gallons of water.\n\nOur next invariant, `die_hard_problem_not_solved`, is where it gets\ninteresting. Here we're declaring that the problem of getting exactly\n4 gallons in the big jug _cannot_ be solved. Since Hypothesis's job\nis to test our logic for bugs, it will give our state machine a\nthorough shake down and see if we ever violate our invariants.\nIn other words, we're basically goading Hypothesis into solving the\nDie Hard problem for us.\n\nI'm not entirely clear on how Hypothesis does its work, but I know\nthe basic summary is this: It takes the program properties we've\nspecified -- including things like rules, invariants, data types, and\nfunction signatures -- and generates data or actions to probe the\nbehavior of our program. If Hypothesis finds a piece of data or\nsequence of actions that get our program to violate its stated properties, it\ntries to whittle that down to a _minimum falsifying example_---i.e.\nsomething that exposes the same problem but with a minimum number of\nsteps. This makes it much easier for you to understand how Hypothesis\nbroke your code.\n\nHypothesis's output above tells us that it was able to violate the\n`die_hard_problem_not_solved` invariant and provides us with a\nminimal reproduction showing exactly how it did so. That reproduction\nis our solution to the problem. It's also how McClane and Carver did\nit in the movie!\n\n## Final Thoughts\n\nAll in all, I was pretty impressed with how straightforward it was to\ntranslate the TLA+ example into Python using Hypothesis. And when\nHypothesis spit out the solution, I couldn't help but smile. It's\npretty cool to see your computer essentially generate a program that\nsolves a problem for you. And the Python version of the Die Hard\n\"spec\" is not much more verbose than the\noriginal in TLA+, though TLA+'s notation for current vs. next value\n(e.g. `small` vs. `small'`) is elegant and cuts out the need to have\nvariables like `old_small` and `old_big`.\n\nI don't know how Hypothesis compares to TLA+ in a general sense. I've\nonly just started to learn about property-based testing and TLA+, and\nI wonder if they have a place in the work that I do these days, which\nis mostly Data Engineering-type stuff. Still, I found this little\nexercise fun, and I hope you learned something interesting from it.\n\n_Thanks to [Julia], [Dan], Laura, Anjana, and Cip for reading drafts\nof this post._\n\n[Julia]: http://jvns.ca/\n[Dan]: https://danluu.com/\n"
  },
  {
    "path": "website/content/2017-07-16-types-and-properties.md",
    "content": "---\ntags: technical, details, python, alternatives\ndate: 2017-07-16 10:00\ntitle: Moving Beyond Types\nauthor: drmaciver\n---\n\nIf you look at the original property-based testing library, the Haskell version of QuickCheck,\ntests are very closely tied to types: The way you typically specify a property is by inferring\nthe data that needs to be generated from the types the test function expects for its arguments.\n\nThis is a bad idea.\n\n<!--more-->\n\nThe first part of why\n[I've talked about already](../integrated-shrinking/) -\nyou don't want to tie the shrinking of the data to its type, because it makes testing\nsignificantly more brittle.\n\nBut you could solve that and still have data generation be tied to type, and it would still\nbe a bad idea.\n\nThe reason for this is very simple: Often you want to generate something much more specific\nthan any value of a given type.\n\nIf you look at the [Hypothesis strategies module](https://hypothesis.readthedocs.io/en/latest/data.html)\nand what you can generate, many of these look like types. But if you look closer, nearly\nevery single one of them has options to configure them to be more specific.\n\nConsider something like the following:\n\n```python\nfrom statistics import mean\n\nfrom hypothesis import given, strategies as st\n\n\n@given(st.lists(st.floats(allow_nan=False, allow_infinity=False), min_size=1))\ndef test_mean_is_in_bounds(ls):\n    assert min(ls) <= mean(ls) <= max(ls)\n```\n\nIn this test we've restricted the domain we're testing on so we can focus on a property\nthat doesn't hold in generality:  The mean of an empty list is an\nerror, so that needs a special case test for it, and calculations with `NaN` or infinity\nare special cases that don't always have a well-defined result and even when they do\ndon't necessarily satisfy this property.\n\nThis happens a lot: Frequently there are properties that only hold in some restricted\ndomain, and so you want more specific tests for that domain to complement your other\ntests for the larger range of data.\n\nWhen this happens you need tools to generate something more specific, and those requirements\ndon't map naturally to types.\n\nConsider writing this code based on types instead:\n\n```python\nfrom statistics import mean\n\nfrom hypothesis import given, strategies as st\n\n\n@given(ls=...)\ndef test_mean_is_in_bounds(ls: list[float]):\n    assert min(ls) <= mean(ls) <= max(ls)\n```\n\n(this code doesn't work at the time of this writing, but it will soon -\n[the pull request to implement it](https://github.com/HypothesisWorks/hypothesis-python/pull/643)\nis in fairly late-stage review).\n\nBut this doesn't do the right thing: We've dropped the conditions from the\nprevious test that our floats are all finite and our lists are all non-empty. So now\nwe have to add a precondition to make the test valid:\n\n```python\nimport math\nfrom statistics import mean\n\nfrom hypothesis import assume, given, strategies as st\n\n\n@given(ls=...)\ndef test_mean_is_in_bounds(ls: list[float]):\n    assume(len(ls) > 1)\n    assume(all(math.isfinite(x) for x in ls))\n    assert min(ls) <= mean(ls) <= max(ls)\n```\n\nBut this is now substantially longer and less readable than the original approach!\n\nIn Haskell, traditionally we would fix this with a newtype declaration which wraps the type.\nWe could find a newtype NonEmptyList and a newtype FiniteFloat and then say that we actually\nwanted a NonEmptyList[FiniteFloat] there.\n\nIn Python we could probably do more or less the same thing, either by creating new wrapper\ntypes or by subclassing list and float (which you shouldn't do. Subclassing builtins in Python\nleads to really weird behaviour) if we wanted to save a few lines, but it's much more noisy.\n\nBut why should we bother? Especially if we're only using these in one test, we're not actually\ninterested in these types at all, and it just adds a whole bunch of syntactic noise when you\ncould just pass the data generators directly. Defining new types for the data you want to generate\nis purely a workaround for a limitation of the API.\n\nIf you were working in a dependently typed language where you could already naturally express\nthis in the type system it *might* be OK (I don't have any direct experience of working in\ntype systems that strong), but I'm sceptical of being able to make it work well - you're unlikely\nto be able to automatically derive data generators in the general case, because the needs of\ndata generation \"go in the opposite direction\" from types (a type is effectively a predicate which\nconsumes a value, where a data generator is a function that produces a value, so in order to produce\na generator for a type automatically you need to basically invert the predicate). I suspect most\napproaches here  will leave you with a bunch of sharp edges, but I would be interested to see\nexperiments in this direction.\n\nThat being said, I don't think it's that useful to do. Where stronger types are naturally\npresent in the program, taking advantage of them to get better testing is certainly worth\ndoing, but creating a specific type to represent the exact range of valid inputs to a\nspecific test isn't because for tests the impact of a run time error that you could have caught at\ncompile time is substantially reduced (all it causes is a spurious test failure - where your\ntests are long running or non-deterministic as in property-based testing this *does* matter,\nbut it still doesn't cause a problem in production).\n\nBut this is creating hard problems where none need exist, and beside which it's not the situation\nwith most of the current generation of languages and property based libraries for them.\nHere, using explicit data generators is a clear improvement, and just as well-typed\n(in a statically typed language each data generator has a return type after all).\n\nYou *can* use data generators directly in Haskell QuickCheck too, with an explicit\n[forAll](https://hackage.haskell.org/package/QuickCheck-2.10.0.1/docs/Test-QuickCheck-Property.html#v:forAll)\nbut it's almost as awkward as the newtype approach, particularly if you want more than one\ndata generator (it's even more awkward if you want shrinking - you have to use forAllWithShrink and\nexplicitly pass a shrink function).\n\nThis is more or less intrinsic to the type based approach. If you want tinkering with the\ndata generation to be non-awkward, starting from data generators needs to become the default.\n\nAnd experience suggests that when you make customising the data generation easy, people do\nit. It's nice to be able to be more specific in your testing, but if you make it too high\neffort people either don't do it, or do it using less effective methods like adding\npreconditions to tests (assume in Hypothesis, or `==>` in QuickCheck), either of which reduces\nthe quality of your testing and causes more bugs to slip through as a result.\n\nFortunately, it already *is* the default in most of the newer implementations of\nproperty-based testing. The only holdouts are ones that directly copied Haskell QuickCheck.\n\nOriginally this was making a virtue of a necessity - most of the implementations\nwhich started off the trend of data generator first tests are either for dynamic languages\n(e.g. Erlang, Clojure, Python) or languages with very weak type systems (e.g. C) where\ntype first is more or less impossible, but it's proven to be a much more usable design.\n\nAnd it's perfectly compatible with static typing too. [Hedgehog](https://hackage.haskell.org/package/hedgehog)\nis a relatively recent property-based testing library for Haskell that takes this approach,\nand it works just as well in Haskell as it does in any language.\n\nIt's also perfectly compatible with being able to derive a data generator from a type\nfor the cases where you really want to. We saw a hint at that with the upcoming\nHypothesis implementation above. You could easily do the same by having something\nlike the following in Haskell (mimicking the type class of QuickCheck):\n\n```haskell\nclass Arbitrary a where\n  arbitrary :: Gen a\n```\n\nYou can then simply use `arbitrary` like you would any other data generator. As far as I know\nHedgehog doesn't do this anywhere (but you can use QuickCheck's Arbitrary with\nthe hedgehog-quickcheck package), but in principle there's nothing stopping it.\n\nHaving this also makes it much easier to define new data generators. I'm unlikely to use the\nsupport for `@given` much, but I'm much more excited that it will also\nwork with `builds`, which will allow for a fairly seamless transition between\ninferring the default strategy for a type and writing a custom generator. You\nwill, for example, be able to do `builds(MyType)` and have every constructor\nargument automatically filled in (if it's suitably annotated), but you can\nalso do e.g. `builds(MyType, some_field=some_generator)` to override a particular\ndefault while leaving the others alone.\n\n(This API is somewhere where the dynamic nature of Python helps a fair bit, but you\ncould almost certainly do something equivalent in Haskell with a bit more noise\nor a bit more template Haskell)\n\nSo this approach doesn't have to be data generator-only, even if it's data generator first,\nbut if you're going to pick one the flexibility of the data generator based test specification\nis hard to beat, regardless of how good your type system is.\n"
  },
  {
    "path": "website/content/2017-09-14-multi-bug-discovery.md",
    "content": "---\ntags: technical, details, python\ndate: 2017-09-26 12:00\ntitle: When multiple bugs attack\nauthor: drmaciver\n---\n\nWhen Hypothesis finds an example triggering a bug, it tries to shrink the example\ndown to something simpler that triggers it. This is a pretty common feature, and\nmost property-based testing libraries implement something similar (though there\nare a number of differences between them). Stand-alone test case reducers are\nalso fairly common, as it's a useful thing to be able to do when reporting bugs\nin external projects - rather than submitting a giant file triggering the bug,\na good test case reducer can often shrink it down to a couple of lines.\n\nBut there's a problem with doing this: How do you know that the bug you started\nwith is the same as the bug you ended up with?\n\nThis isn't just an academic question. [It's very common for the bug you started\nwith to slip to another one](https://blog.regehr.org/archives/1284).\n\nConsider for example, the following test:\n\n```python\nfrom hypothesis import given, strategies as st\n\n\ndef mean(ls):\n    return sum(ls) / len(ls)\n\n\n@given(st.lists(st.floats()))\ndef test(ls):\n    assert min(ls) <= mean(ls) <= max(ls)\n```\n\nThis has a number of interesting ways to fail: We could pass `NaN`, we could\npass `[-float('inf'), +float('inf')]`, we could pass numbers which trigger a\nprecision error, etc.\n\nBut after test case reduction, we'll pass the empty list and it will fail\nbecause we tried to take the min of an empty sequence.\n\nThis isn't necessarily a huge problem - we're still finding a bug after all\n(though in this case as much in the test as in the code under test) -\nand sometimes it's even desirable - you find more bugs this way, and sometimes\nthey're ones that Hypothesis would have missed - but often it's not, and an\ninteresting and rare bug slips to a boring and common one.\n\nHistorically Hypothesis has had a better answer to this than most - because\nof the Hypothesis example database, all intermediate bugs are saved and a\nselection of them will be replayed when you rerun the test. So if you fix\none bug then rerun the test, you'll find the other bugs that were previously\nbeing hidden from you by that simpler bug.\n\nBut that's still not a great user experience - it means that you're not getting\nnearly as much information as you could be, and you're fixing bugs in\nHypothesis's priority order rather than yours. Wouldn't it be better if Hypothesis\njust told you about all of the bugs it found and you could prioritise them yourself?\n\nWell, as of Hypothesis 3.29.0, released a few weeks ago, now it does!\n\nIf you run the above test now, you'll get the following:\n\n```\nFalsifying example: test(ls=[nan])\nTraceback (most recent call last):\n  File \"/home/david/hypothesis-python/src/hypothesis/core.py\", line 671, in run\n    print_example=True, is_final=True\n  File \"/home/david/hypothesis-python/src/hypothesis/executors.py\", line 58, in default_new_style_executor\n    return function(data)\n  File \"/home/david/hypothesis-python/src/hypothesis/core.py\", line 120, in run\n    return test(*args, **kwargs)\n  File \"broken.py\", line 8, in test\n    def test(ls):\n  File \"/home/david/hypothesis-python/src/hypothesis/core.py\", line 531, in timed_test\n    result = test(*args, **kwargs)\n  File \"broken.py\", line 9, in test\n    assert min(ls) <= mean(ls) <= max(ls)\nAssertionError\n\nFalsifying example: test(ls=[])\nTraceback (most recent call last):\n  File \"/home/david/hypothesis-python/src/hypothesis/core.py\", line 671, in run\n    print_example=True, is_final=True\n  File \"/home/david/hypothesis-python/src/hypothesis/executors.py\", line 58, in default_new_style_executor\n    return function(data)\n  File \"/home/david/hypothesis-python/src/hypothesis/core.py\", line 120, in run\n    return test(*args, **kwargs)\n  File \"broken.py\", line 8, in test\n    def test(ls):\n  File \"/home/david/hypothesis-python/src/hypothesis/core.py\", line 531, in timed_test\n    result = test(*args, **kwargs)\n  File \"broken.py\", line 9, in test\n    assert min(ls) <= mean(ls) <= max(ls)\nValueError: min() arg is an empty sequence\n\nYou can add @seed(67388524433957857561882369659879357765) to this test to reproduce this failure.\nTraceback (most recent call last):\n  File \"broken.py\", line 12, in <module>\n    test()\n  File \"broken.py\", line 8, in test\n    def test(ls):\n  File \"/home/david/hypothesis-python/src/hypothesis/core.py\", line 815, in wrapped_test\n    state.run()\n  File \"/home/david/hypothesis-python/src/hypothesis/core.py\", line 732, in run\n    len(self.falsifying_examples,)))\nhypothesis.errors.MultipleFailures: Hypothesis found 2 distinct failures.\n```\n\n(The stack traces are a bit noisy, I know.\n[We have an issue open about cleaning them up](https://github.com/HypothesisWorks/hypothesis-python/issues/848)).\n\nAll of the different bugs are minimized simultaneously and take full advantage of Hypothesis's\nexample shrinking, so each bug is as easy (or hard) to read as if it were the only bug we'd found.\n\nThis isn't perfect: The heuristic we use for determining if two bugs are the same is whether they\nhave the same exception type and the exception is thrown from the same line. This will necessarily\nconflate some bugs that are actually different - for example, `[float('nan')]`,\n`[-float('inf'), float('inf')]` and `[3002399751580415.0, 3002399751580415.0, 3002399751580415.0]`\neach trigger the assertion in the test, but they are arguably \"different\" bugs.\n\nBut that's OK. The heuristic is deliberately conservative - the point is not that it can\ndistinguish whether any two examples are the same bug, just that any two examples it distinguishes\nare different enough that it's interesting to show both, and this heuristic definitely manages that.\n\nAs far as I know this is a first in property-based testing libraries (though something like it is\ncommon in fuzzing tools, and [theft is hot on our tail with something similar](\nhttps://github.com/silentbicycle/theft/compare/develop-failure_tagging)) and there's been\n[some interesting related but mostly orthogonal research](\nhttp://www.cse.chalmers.se/~nicsma/papers/more-bugs.pdf) in Erlang QuickCheck.\n\nIt was also surprisingly easy.\n\nA lot of things went right in writing this feature, some of them technical, some of them social,\nsomewhere in between.\n\nThe technical ones are fairly straightforward: Hypothesis's core model turned out to be very\nwell suited to this feature. Because Hypothesis has a single unified intermediate representation\nwhich defines a total ordering for simplicity, adapting Hypothesis to shrink multiple things at\nonce was quite easy - whenever we attempt a shrink and it produces a different bug than the one\nwe were looking for, we compare it to our existing best example for that bug and replace it if\nthe current one is better (or we've discovered a new bug). We then just repeatedly run the shrinking\nprocess for each bug we know about until they've all been fully shrunk.\n\nThis is in a sense not surprising - I've been thinking about the problem of multiple-shrinking for\na long time and, while this is the first time it's actually appeared in Hypothesis, the current\nchoice of model was very much informed by it.\n\nThe social ones are perhaps more interesting. Certainly I'm very pleased with how they turned\nout here.\n\nThe first is that this work emerged tangentially from\n[the recent Stripe funded work](https://stripe.com/blog/hypothesis) - Stripe paid me\nto develop some initial support for testing Pandas code with Hypothesis, and I observed\na bunch of bug slippage happening in the wild while I was testing that (it turns out there\nare quite a lot of ways to trigger exceptions from Pandas - they weren't really Pandas\nbugs so much as bugs in the Pandas integration, but they still slipped between several\ndifferent exception types), so that was what got me thinking about this problem again.\n\nNot by accident, this feature also greatly simplified the implementation\nof [the new deadline feature](https://hypothesis.readthedocs.io/en/latest/settings.html#hypothesis.settings.deadline)\nthat [Smarkets](https://smarkets.com/) funded, which was going to have to have a lot of\nlogic about how deadlines and bugs interacted, but all that went away as soon as we were\nable to handle multiple bugs sensibly.\n\nThis has been a relatively consistent theme in Hypothesis development - practical problems\ntend to spark related interesting theoretical developments. It's not a huge exaggeration\nto say that the fundamental Hypothesis model exists because I wanted to support testing\nDjango nicely. So the recent funded development from Stripe and Smarkets has been a\ngreat way to spark a lot of seemingly unrelated development and improve Hypothesis\nfor everyone, even outside the scope of the funded work.\n\nAnother thing that really helped here is our review process, and [the review from Zac\nin particular](https://github.com/HypothesisWorks/hypothesis-python/pull/836).\n\nThis wasn't the feature I originally set out to develop. It started out life as a\nmuch simpler feature that used much of the same machinery, and just had a goal of\navoiding slipping to new errors all together. Zac pushed back with some good questions\naround whether this was really the correct thing to do, and after some experimentation\nand feedback I eventually hit on the design that lead to displaying all of the errors.\n\nOur [review handbook](https://github.com/HypothesisWorks/hypothesis-python/blob/master/guides/review.rst)\nemphasises that code review is a collaborative design process, and I feel this was\na particularly good example of that. We've created a great culture of code review,\nand we're reaping the benefits (and if you want to get in on it, we could always\nuse more people able and willing to do review...).\n\nAll told, I'm really pleased with how this turned out. I think it's a nice example\nof getting a lot of things right up front and this resulting in a really cool new\nfeature.\n\nI'm looking forward to seeing how it behaves in the wild. If you notice any\nparticularly fun examples, do [let me know](mailto:david@drmaciver.com), or write\nup a post about them yourself!\n"
  },
  {
    "path": "website/content/2017-09-28-threshold-problem.md",
    "content": "---\ntags: technical, details, python\ndate: 2017-09-28 11:00\ntitle: The Threshold Problem\nauthor: drmaciver\n---\n\nIn [my last post](../multi-bug-discovery/) I mentioned\nthe problem of bug slippage: When you start with one bug, reduce the test case, and end\nup with another bug.\n\nI've run into another related problem twice now, and it's not one I've seen talked about\npreviously.\n\nThe problem is this: Sometimes shrinking makes a bug seem much less interesting than it\nactually is.\n\n<!--more-->\n\nI first noticed this problem when [Ned Batchelder](https://nedbatchelder.com/) asked me\nabout some confusing behaviour he was seeing: He was testing some floating point code and\nhad an assertion that the error was not greater than some threshold. Let's say 0.5 (I could\ndig up the IRC logs, but the exact number doesn't matter).\n\nHypothesis said \"Ah ha! Here is an example where the error is 0.500001. A bug!\".\n\nNed sighed and thought \"Oh great, floating point precision issues\", but on further\ninvestigation it turned out that that wasn't it at all. The error could be arbitrarily large,\nit's just that Hypothesis reliably gave an example where it was almost as small as it could\npossibly be and still fail.\n\nThis wasn't a bug, either. This is how Hypothesis, QuickCheck, and all of the other tools\nin this family are designed to work.\n\nThe problem is that test case reduction is designed to produce the simplest example\npossible to demonstrate the bug. If the bug can be expressed as happening when some\nscore exceeds some threshold, and the score is one that tends to increase with example\nsize, then the failing example that a property-based testing library gives you will tend\nto be one where the score is barely above that threshold, making the problem look much\nless bad than it actually is.\n\nThis isn't even a bug in Hypothesis - QuickCheck or any other property-based testing would\ndo the same. It's literally working as intended.\n\nArguably it's not even really a problem: Hypothesis has demonstrated the bug, and it's\ndone so with a simple example which should thus be easy to understand.\n\nBut I can't help but feel that we could do better. It definitely produces misleading\nexamples even if they technically demonstrate the right problem, and misleading examples\nare a great way to waste the user's time.\n\nI also ran into this problem again recently, where it was more of a problem because it\nwas resulting in flaky tests.\n\nI recently introduced [a deadline feature](https://hypothesis.readthedocs.io/en/latest/settings.html?highlight=deadline#hypothesis.settings.deadline)\nas part of the work on Hypothesis performance legibility that [Smarkets](https://smarkets.com/)\nare funding. This causes slow examples to be treated as failures: If an example passes\nbut took longer than your deadline to run, it raises `DeadlineExceeded`. This is treated\nas a normal error and Hypothesis shrinks it like anything else (including allowing it to\nparticipate in the multi-shrinking process).\n\nThe problem is that it's exactly this sort of threshold problem: You literally have a\nscore (the run time) and a threshold (the deadline) such that when the score exceeds\nthe threshold the test fails. Large examples are certainly likely to be slower, so you\nwill consistently get examples which are right on the boundary of being too slow.\n\nWhich is fine, except that  Hypothesis relies on repeatability to display test errors -\nonce it has a minimized example, it replays the test so it can show you the example,\nprint the exception, etc. And test run times are not actually repeatable - a test that\ntakes 201ms on first running might take 199ms on the next run. This then results in\nHypothesis thinking the test is flaky - it previously raised `DeadlineExceeded`, and now it\ndoesn't. This lead to [Issue 892](http://github.com/HypothesisWorks/hypothesis-python/issues/892),\nwhere Florian Bruhin ran into precisely this problem when testing [Qutebrowser](https://www.qutebrowser.org/).\n\nThe [solution I've ended up opting for there](https://github.com/HypothesisWorks/hypothesis-python/pull/899)\nis to temporarily raise the deadline during shrinking\nto something halfway between the actual deadline and the largest runtime we've seen. This\nensures that we shrink to a larger threshold than the deadline, and then when we replay\nwe should comfortably exceed the real deadline unless the test performance actually *is*\nreally flaky (in which case I've also improved the error message).\n\nThis solution is currently very specific to the problem of the deadlines, and that's\nfine - there's no need to rush to a fully general solution, and deadlines have slightly\ndifferent constraints than other variants of this due to the unreliability of timing -\nbut it is something I'd like to see solved more generally.\n\nOne thing I have thought about for a while is adding some notion of scoring to\nHypothesis - e.g. letting people record some score that recorded your progress\nin testing (testing games where the score could be e.g. the level you've reached, or\nyour literal score in the game, was one use case I had in mind). This would seem to be\nanother good example for that - if you could make your score available to Hypothesis\nin some way (or if Hypothesis could figure it out automatically!), then a similar\nsolution to the above could be used: If Hypothesis notices that the score of the\nshrunk example is drastically different from the score of the starting example, it\ncould try rerunning the shrinking process with the additional constraint that the\nscore should stay closer to that of the original example, and display the newly shrunk\nexample with the larger (or smaller) score alongside it. This would work as part\nof the new multiple failures reporting, so you would see both examples side by side.\n\nThis needs more thought before I jump in and implement something, but I think this is\nan important problem to solve to improve the usability of Hypothesis in particular and\nproperty-based testing in general. Shrinking is a great start to making the problems\ntesting exposes legible to users, but it's only a start, and we need to do more to\ntry to improve developers' productivity when debugging the problems we show them.\n"
  },
  {
    "path": "website/content/2018-01-08-smarkets.md",
    "content": "---\ntags: python\ndate: 2018-01-08 06:00\ntitle: Smarkets's funding of Hypothesis\nauthor: drmaciver\n---\n\nHappy new year everybody!\n\nIn this post I'd like to tell you about one of the nice things that happened in 2017:\nThe Hypothesis work that was funded by [Smarkets](https://smarkets.com/careers).\nSmarkets are an exchange for peer-to-peer trading of bets but, more importantly for us,\nthey are fairly heavy users of Hypothesis for the Python part of their stack.\n\n<!--more-->\n\nSmarkets approached me a while back to talk about possibly funding some Hypothesis development.\nWe talked a bit about what their biggest pain points with Hypothesis were,\nand it emerged that they were having a lot of trouble with Hypothesis performance.\n\nWe talked a bit about how to speed Hypothesis up, and I suggested some diagnostic tests\nthey could do to see where the problem was, and it fairly quickly emerged that in fact\nthey mostly *weren't* having trouble with Hypothesis performance - Hypothesis indeed was\nmuch slower than it should have been in their use case, but more than an order of magnitude\nmore time was spent in their test code rather than in Hypothesis.\n\nSo on further discussion we decided that actually their big problem was not the performance\nof Hypothesis per se, but instead the *legibility* of Hypothesis performance problems - when\ntests using Hypothesis were slow, it was non-obvious why that might be the case, and it\nmight be extremely difficult to reproduce the problem.\n\nThis is the sort of problem where it's really useful to have user feedback and funding,\nbecause it's more or less a non-problem for me and - to a lesser extent - anyone who already\nworks on Hypothesis. Because we've got much deeper knowledge of the internals and the failure\nmodes, we're largely just used to working around these issues. More feedback from Hypothesis\nwould be *helpful*, but it's not *essential*.\n\nSo, given that in the normal course of things Hypothesis development is mostly driven by what\nwe feel like working on, this is really the sort of work that will only happen with a source\nof external funding for it. Thus it's really great that Smarkets were willing to step up and\nfund it!\n\nAfter some discussion we ended up settling on four features that would significantly improve\nthe situation for them:\n\n### Identification of examples causing slow tests\n\nThis was the introduction of the [deadline](https://hypothesis.readthedocs.io/en/latest/settings.html#hypothesis.settings.deadline)\nfeature, which causes Hypothesis to treat slow tests as failures - when set, a test that takes\nlonger than its set deadline (not counting data generation) raises a `DeadlineExceeded` error.\n\nThis is a bit of a blunt instrument, but it is *very* effective at getting test runtime under control!\n\nThere turned out to be some amusing complications in developing it, so this feature was spread over a\nnumber of releases as we found and worked out its various kinks (3.27.0, 3.31.1, 3.38.2).\n\nOne of the interesting problems we found was that deadlines have a\n[threshold problem](../threshold-problem/) - because the shrinking\nprocess tends to find examples which are just on the cusp of failure, often when you rerun a fully shrunk example it doesn't fail!\n\nI went back and forth on the best solution for this for a while, but in the end the best solution turned out to be a simple one -\nraise the deadline during example generation and shrinking, then replay with the actual set deadline.\n\nThis does mean that tests that are *right* on the cusp of being too slow may pass artificially, but that's substantially better\nthan introducing flaky failures.\n\nOn top of this we also needed to make this feature play well with [inline data generation](https://hypothesis.readthedocs.io/en/latest/data.html#drawing-interactively-in-tests) -\nthe complicating factor was that data generation is much faster when replaying examples or shrinking than it is during generation\n(the generation logic is rather too complicated. I have some long-term plans to make it simpler, which would make this difference largely go away).\nFortunately, the work done for the next feature made this easy to do.\n\n### Breakdown of generation time in statistics\n\nThis was a fairly simple change, prompted by the initial confusion we had in diagnosing\nSmarket's test problems: If you can't tell the difference between slow data generation and\nslow tests, your initial guesses about performance may be very misleading! So this change\nupdated [the statistics reporting system](https://hypothesis.readthedocs.io/en/latest/details.html#statistics)\nto report what fraction of time is spent in data generation. If you run tests with statistics\nyou'll now see a line like the following:\n\n```\n- Fraction of time spent in data generation: ~ 12%\n```\n\nA small change, but a very helpful one! This came in in Hypothesis 3.38.4.\n\n### Health check overhaul\n\nHypothesis has had a health check system for a while. Its general goal is to suggest that\nyou might not want to do that thing you're doing - roughly analogous to compiler warnings.\nIt's useful for guiding you into correct use of Hypothesis and helping you avoid things that\nmight degrade the quality of your testing.\n\nIt's historically had some problems: In particular the main source of health checks did not\nactually run your tests! They just run the data generation with the test stubbed out.\nThis meant that you could very easily accidentally bypass the health checks by e.g.\nusing inline data generation, or doing your filtering with assume.\n\nIt also had the problem that it wasn't running the real data generation algorithm but instead\nan approximation to it.\nThis meant that things that  would work fine in practice would sometimes fail health checks.\n\nThis piece of work was an overhaul of the health check system to solve these problems and to expand the scope of the problems it could find.\n\nIt ended up working very well. So well in fact that it found some problems in Hypothesis's built in library of strategies!\n\nIt was split across a number of releases:\n\n* In 3.37.0 we deprecated a number of existing health checks that no longer did anything useful.\n* In 3.38.0 I overhauled the health check system to be based on actual test execution, solving the existing limitations of it.\n* In 3.39.0 I added a new health check that tests whether the smallest example of the test was too large to allow reasonable testing -\n  accidentally generating very large examples being a common source of performance bugs.\n\nThe health check in 3.39.0 turned out to catch a major problem in Hypothesis's handling of blacklist\\_characters and some\nregular expression constructs, so prior to that we had to release 3.38.8 to fix those!\n\nOver all I'm much happier with the new health check system and think it does a much better job of shaping user behaviour to get better results out of Hypothesis.\n\n### Printing reproduction steps\n\nHistorically output from Hypothesis has looked something like this:\n\n```\nFalsifying example: test_is_minimal(ls=[0], v=1)\n```\n\nOr, if you had a failed health check, like the following:\n\n```\nhypothesis.errors.FailedHealthCheck: It looks like your strategy is filtering out a lot of data. Health check found 50 filtered examples but only\n0 good ones. This will make your tests much slower, and also will probably distort the data generation quite a lot. You should adapt your strategy\n to filter less. This can also be caused by a low max_leaves parameter in recursive() calls.\n\nSee https://hypothesis.readthedocs.io/en/latest/reference/api.html#hypothesis.HealthCheck for more information about this. If you want to disable just this health check,\nadd HealthCheck.filter_too_much to the suppress_health_check settings for this test.\n```\n\nThis is fine if you're running the tests locally, but if your failure is on CI this can be difficult to reproduce.\nIf you got a falsifying example, you're only able to reproduce it if all of your arguments have sensible reprs (which may not be the case even if you restrict yourself to Hypothesis's built in strategies - e.g. using inline data generation prevents it!).\nIf you got a health check failure, there's nothing that helps you reproduce it at all!\n\nSo the proposed feature for this was to print out the random seed that produced this:\n\n```\nYou can add @seed(302934307671667531413257853548643485645) to this test or run pytest with --hypothesis-seed=302934307671667531413257853548643485645 to reproduce this failure.\n```\n\nThis was a great idea, and seemed to work out pretty well when we introduced it in 3.30.0, but on heavier use in the wild turned out to have some fairly major problems!\n\nThe big issue is that in order to reproduce Hypothesis's behaviour on a given run you need to know not\njust the random seed that got you there, but also the state of Hypothesis's example database!\nHypothesis [maintains a cache of many of the previously run examples](https://hypothesis.readthedocs.io/en/latest/database.html),\nand uses it to inform the testing by replaying test cases that e.g. failed the last time they were run,\nor covered some hard to reach line in the code.\nEven for examples that don't come from the database, Hypothesis under the hood is a mutation based\nfuzzer, so all the examples it finds will depend on the examples it loaded.\n\nThe initial solution to this (3.40.0) was just to turn off seed printing when its output would be misleading.\nThis worked, but was fairly non-ideal even just for Smarkets - they *do* use the database in their CI, so this would result in a lot of failures to print.\n\nAfter some discussion, I decided that given that the feature wasn't nearly as useful as intended,\nso I threw in an extra freebie feature to make up the gap in functionality:\n[@reproduce\\_failure](https://hypothesis.readthedocs.io/en/latest/reproducing.html#reproducing-an-example-with-with-reproduce-failure).\nThis uses Hypothesis's internal format to replicate the functionality of the database in a way that is easy to copy and paste into your code.\nIt took some careful designing to make it usable - my big concern was that people would leave this in their code, blocking future upgrades to Hypothesis - but in the end I'm *reasonably* happy with the result.\n\nAs a bonus, the work here allowed me to sort out one big concern about seed printing: We still needed a way to reproduce health check failures when the database was being used.\nThe solution was in the end easy: We just don't use the examples from the database in the part where the main health checks are running.\nThis still leaves a few health checks which could theoretically be hard to reproduce (the main one is the hung test health check, but that one tends to reproduce fairly reliably on any seed if you have deadlines on).\n\nSo this leaves us with a state where health check failures will suggest `@seed` and example failures will suggest `@reproduce_failure` (where necessary. The linked documentation spells this out in more detail).\n\n### Ten releases later\n\nIn the end the Smarkets work came to a total of exactly 10 releases, some larger than other.\n\nThe end result has been very beneficial, and not just to Smarkets!\nI've had several users report back improvements to their tests as a result of the new health checks,\nand I've personally found the `@reproduce_failure` feature remarkably useful.\n\nI'm very happy to have done this work, and am grateful to Smarkets for funding it.\n\nI think this sort of thing where commercial users fund the \"boring\" features that are very useful for people using the tool at scale but maintainers are unlikely to work on under their own initiative is a\nvery good one, and I hope we'll do more of it in future.\n\nAs a bonus, Smarkets kindly agreed to put online the talk I gave them about Hypothesis (largely intended\nto raise awareness of it and property-based testing among their teams who aren't using it yet).\nIf you want to learn more about some of the philosophy and practice behind using this sort of\ntesting, or want something to send to people who aren't convinced yet, you can watch it\n[here](https://smarketshq.com/a-talk-on-hypothesis-e7182b95ced1).\n"
  },
  {
    "path": "website/content/2018-02-27-continuous-releases.md",
    "content": "---\ntags: development-process\ndate: 2018-02-27 07:00\ntitle: The Hypothesis continuous release process\nauthor: alexwlchan\n---\n\nIf you watch [the Hypothesis changelog][changelog], you'll notice the rate of releases sped up dramatically in 2017.\nWe released over a hundred different versions, sometimes multiple times a day.\n\nThis is all thanks to our continuous release process.\nWe've completely automated the process of releasing, so every pull request that changes code gets a new release, without any human input.\nIn this post, I'll explain how our continuous releases work, and why we find it so useful.\n\n[changelog]: https://hypothesis.readthedocs.io/en/latest/changelog.html\n\n<!--more-->\n\n## How it works\n\nIn the past, Hypothesis was released manually.\nSomebody had to write a changelog, tag a new release on GitHub, and run some manual pip commands to publish a new version to PyPI -- and only David had the credentials for the latter.\n\nThis meant that releases were infrequent, and features spent a long time in master before they were available to `pip install`.\nThe pace of development picked up in 2017 -- partly as new maintainers arrived, and partly groundwork for [David's upcoming (now started) PhD][phd] -- and we wanted to be able to release more frequently.\nWe decided to automate the entire release process.\n\nNow, when you create a pull request that changes the Hypothesis code -- anything that gets installed by pip -- you have to include a `RELEASE.rst` file which describes your change.\nHere's an example from [a recent pull request][recent]:\n\n    RELEASE_TYPE: patch\n\n    This release changes the way in which Hypothesis tries to shrink the size of\n    examples. It probably won't have much impact, but might make shrinking faster\n    in some cases. It is unlikely but not impossible that it will change the\n    resulting examples.\n\nThe first line says whether this is a major, minor, or patch release (using [semantic versioning][semver]).\nThe rest is a description of the changes in your patch.\n\nWe have a test in CI that checks for this file -- any change to the core code needs a release file, even [fixing a typo][typo].\nIf you need a release file but haven't written one, the tests fail and your pull request won't be merged.\n\nSometimes we write a release file even if there aren't changes to the core code, but we think it's worth a release anyway.\nFor example, changes to the installation code in `setup.py`, or larger changes to our test code for the benefit of downstream packagers.\n\nOnce you've written a release file and the pull request is merged into master, and after all the other tests have passed, our CI uses this file to create a new release.\n\nFirst, it works out the new version number, and updates it in [version.py][version.py].\nThen it copies the release description into the changelog, including the new version number and the current date.\nFor example:\n\n    --------------------\n    3.44.25 - 2018-02-05\n    --------------------\n\n    This release changes the way in which Hypothesis tries to shrink the size of\n    examples. It probably won't have much impact, but might make shrinking faster\n    in some cases. It is unlikely but not impossible that it will change the\n    resulting examples.\n\nThese two changes are saved as a new commit, and that commit gets tagged as the new release.\nThe tag and the commit are pushed to GitHub, and then CI builds a new package and publishes it to PyPI.\n\nSo with no very little extra work, every code change triggers a new release, and it's usually available within half an hour of merging the pull request.\n\nThis exact system might not scale to larger teams.\nIn particular, you can't merge new features until the code in master has been released -- you get conflicts around `RELEASE.rst` -- so you can only merge one pull request at a time.\nAnd in Hypothesis, we never backport bugfixes to old major or minor releases -- you'd need some changes to support that.\n\nBut Hypothesis only has one full-time contributor, and everybody else works on it in their free time, we don't create patches fast enough for this to be a problem.\nFor us, it works exceptionally well.\n\n[phd]: http://www.drmaciver.com/2017/04/life-changes-announcement-academia-edition/\n[recent]: https://github.com/HypothesisWorks/hypothesis-python/pull/1101\n[semver]: https://semver.org/\n[typo]: https://github.com/HypothesisWorks/hypothesis-python/pull/1069\n[version.py]: https://github.com/HypothesisWorks/hypothesis-python/blob/master/src/hypothesis/version.py\n\n## Why bother?\n\nMoving to continuous releases has been amazing.\n\nThe big benefit is that nobody has to do manual releases any more.\nBefore we had this system, changelogs had to be assembled and written by hand, which meant reading the commit log since the last release.\nThis is both boring and prone to error -- in the past, a release might contain multiple changes, and it was easy to overlook or forget something in the changelog.\nNo more!\n\nAnother benefit is that our releases happen much more quickly.\nEvery patch is available as soon as our tests confirm it's okay, not when somebody remembers to do a release.\nIf something's been merged, it's either available for download, or it will be very shortly.\n\nReleasing more often means each individual release is much smaller, which makes it much easier to find the source of bugs or regressions.\nIf somebody finds a bug, we can trace it to a specific release (and corresponding pull request), and there's a relatively small amount of code to inspect.\n\nAutomation also makes our release process more reliable.\nManual steps have scope for error, and we've had a few dodgy releases in the past.\nThis process has cut over 100 releases near flawlessly.\n\nFinally, every contributor gets to make a release.\nIf you submit a patch that gets accepted, your change is available immediately, and it's entirely your work.\nThis may less of tangible benefit, but it gives off nice fuzzy feelings, especially if it's your first patch.\n(Speaking of which, we're always looking [for new contributors][contributors]!)\n\n[contributors]: https://github.com/HypothesisWorks/hypothesis-python/blob/master/CONTRIBUTING.rst\n\n## I'm ruined for everything else\n\nI've become used to code being available almost immediately after it's merged into master -- which isn't true for the vast majority of projects.\nWhen I go to a repo with a bug report, see that a bugfix was merged two weeks ago, but there's yet to be a new release, it's hard not to feel a little impatient.\n\nI've started using this in my other repos -- both these scripts exactly, and derivatives of the same idea.\n\nIf you'd like to try this yourself (and I'd really encourage you to do so!), all the scripts for this process are under the same MPL license as Hypothesis itself.\nLook in the [scripts directory][scripts] of the main repo.\nIn particular, `check-release-file.py` looks for a release note on pull requests, and `deploy.py` is what actually cuts the release.\nThe code will probably need tweaking for your repo (it's closely based on the Hypothesis repo), but hopefully it provides a useful starting point.\n\n[scripts]: https://github.com/HypothesisWorks/hypothesis-python/tree/master/scripts\n"
  },
  {
    "path": "website/content/2020-06-08-complex-data-strategies.md",
    "content": "---\ntags: python intro technical properties\ndate: 2020-06-08 15:00\ntitle: Property Testing with Complex Inputs\nauthor: hwayne\n---\n\nOnce you learn the basics, there are two hard parts to using property-based testing:\n\n* What are good properties to test?\n* How do I generate complex inputs?\n\nThese are also the _main_ parts of property-based testing! And both require some skill and creativity to solve. This post is to help you get some basics on the second question, how we generate complex inputs. Often we're working with data that has lots of preconditions and we want to actually generate inputs that satisfies the preconditions. We also often need to create data that depends on other data, or data with extra conditions, or [independent-but-similar](https://www.hillelwayne.com/post/metamorphic-testing/) data. We need some way to build more complex strategies.\n\nThere are a few different ways to do this, so let's go into each of them.\n\n## The problem\n\nWe have an Exam which consists of a set of questions and multiple-choice answers. Students take ExamInstances, which consists of the exam they took and the answers they gave. For each question they may either list an answer or leave it blank. There are many things we could test here, but the first step is actually generating the data.\n\nFor the purposes of this tutorial we will make the data classes as simple as possible:\n\n```py\nfrom dataclasses import dataclass\n\n@dataclass\nclass Exam:\n    \"\"\"The abstract exam. Students take ExamInstances.\"\"\"\n    name: str\n    answer_key: list[int]\n\n@dataclass\nclass ExamInstance:\n    \"\"\"The instantiation of the exam.\"\"\"\n    student: int\n    exam: Exam\n    answers: list[int | None]  # must be same length, but answers may be blank\n```\n\nFor our property tests we need to generate both Exams and ExamInstances. We have some restrictions on the Exam, and we need the ExamInstances to match the Exam in terms of answer length. This makes it somewhat more complex than the usual \"generate an integer\" case.\n\n## Generating Exams\n\n### Type inference\n\nWe don't _have to_ write a special generator for Exam. We've already type-annotated every field of Exam, so Hypothesis is smart enough to generate valid Exams via the `from_type` strategy.\n\n```py\nfrom hypothesis import given\nimport hypothesis.strategies as st\n\n@given(st.from_type(Exam))\ndef test_1(exam):\n    ...\n```\n\nIn fact, it can even generate valid ExamInstances, as all those fields are typed, too:\n\n```py\n@given(st.from_type(ExamInstance))\ndef test_2(ei):\n    ...\n```\n\nSometimes this is good enough. In our case it is not for a couple of reasons:\n\n* The state space is huge. Hypothesis is using the default generators for each of the fields, when for our purposes they should be more constrained. The more narrowly we can constrain the search space the more likely we are to get interesting edge cases.\n* Hypothesis is going to generate a lot of \"nonsensical\" exams. You might get something where the answer key is `[-45, 0, 800002]`. We want to use stricter strategies for the fields of Exam.\n\n### Simple customizations\n\nIf our requirements are simple and we know that most generated inputs will be correct, we can usually get away with using `filter` and `assume`. `filter` is a method on all strategies, while `assume` goes in the body of the test itself. Both of them, when false, tell hypothesis to discard the invalid data and make a new draw. We can also use `assume` to relate several parameters to each other.\n\n```py\n# very inefficient - don't do this!\n@given(st.from_type(Exam).filter(lambda x: x.answer_key and min(x.answer_key) >= 0))\ndef test_2(exam):\n    assume(max(exam.answer_key) <= 5)\n    ...\n```\n\nThe upside of `filter` and `assume` is that they're easy to write and clearly express what our constraints are. The downside is that we are still generating bad inputs- we're just throwing it away right after. This makes the testing slower and Hypothesis might not find enough valid inputs.\n\nWe're better off writing a customized generator that _always_ generates good inputs. Fortunately that's a lot easier than it sounds.\n\n### `builds`\n\nThe `builds` strategy takes in an object and a set of initialization strategies, draws the corresponding values, and passes them into the object's `__init__`. Let's say we want to make sure that `answer_key` only uses numbers between 1 and 5. We can use `builds` to do this.\n\n```py\n@given(st.builds(Exam, answer_key=st.lists(st.integers(1, 5))))\ndef test_3(exam):\n    for x in exam.answer_key:\n        assert x in range(6)\n```\n\nWe haven't specified what `name` is, so Hypothesis will use the default generator for text. If we want to always use the same name, we can use the `just` strategy:\n\n```py\n@given(st.builds(Exam, name=st.just(\"\"), answer_key=st.lists(st.integers(1, 5))))\ndef test_3(exam):\n    # same\n```\n\nAt this point we should probably pull it into its own function:\n\n```py\ndef exam_strategy(names=st.just(\"\"), n_options=5):\n    return st.builds(\n        Exam,\n        name=names,\n        answer_key=st.lists(st.integers(1, n_options)),\n    )\n\n@given(exam_strategy())\ndef test_3(exam):\n    # same\n```\n\n### `register_type_strategy`\n\nNow that we have a custom builder, we can tell Hypothesis to always use it when inferring Exams. We do this with `register_type_strategy`.\n\n```py\ndef exam_strategy():\n    ...\n\nst.register_type_strategy(Exam, exam_strategy())\n```\n\nThis will now be used any time Hypothesis infers that it needs to build an Exam, even if it needs to do so as part of generating something else, like an ExamInstance.\n\n```py\n@given(st.from_type(Exam))\ndef test_4(exam):\n    ...\n```\n\nThat takes care of the Exam. But we still have a problem with the ExamInstance: its `answer` must have the same length as its exam's `answer_key`. But there's no way to guarantee that with our builder. We can't link strategies to each other.\n\n```py\n# This will fail\n@given(st.from_type(ExamInstance))\ndef test_5(ei):\n    assert len(ei.answers) == len(ei.exam.answer_key)\n```\n\nIn order to combine multiple strategies we need to use something a little more powerful: `composite`.\n\n## `composite`\n\nComposite strategies are user-written functions \"lifted\" into full strategies. They can be a little bit unintuitive at first, so let's start with a simple example. This composite strategy returns a list of numbers where the first element of the list is always the smallest number in the list:\n\n```py\n@st.composite\ndef example(draw):\n    i = draw(st.integers())\n    l = draw(st.lists(st.integers(min_value=i)))\n    return [i] + l\n```\n\nLet's break down what's going on here. First we have the inner function. **The inner function does not return a strategy.** It returns regular Python values. The `@composite` decorator is what converts this function into a strategy. In addition to its usual parameters, the inner function also has a `draw` parameter. Calling this function on a strategy draws a concrete value. We need this because, again, the inner function only returns values, not strategies. We do not explicitly include `draw` when calling the full function; the decorator takes care of that. So we would call this function in a test like:\n\n```py\n@given(example())\ndef test_example(l):\n    assert min(l) == l[0]\n```\n\nWe can do anything we want inside the body of the composite function, making it an exceptionally powerful tool. Here's how we can make sure that our Exam and ExamInstance have the same length:\n\n```py\n# Helper function to make the following examples terser\ndef ei_answers_strategy(exam):\n    return st.lists(\n        st.none() | st.integers(1, 5),\n        min_size=len(exam.answer_key),\n        max_size=len(exam.answer_key),\n    )\n\n@st.composite\ndef exam_instance_strategy(draw):\n    exam = draw(st.from_type(Exam))\n    answers = ei_answers_strategy(exam)\n    return ExamInstance(student=1, exam=exam, answers=draw(answers))\n```\n\nWe use it like any other strategy.\n\n```py\n@given(exam_instance_strategy())\ndef test_6(ei):\n    assert len(ei.answers) == len(ei.exam.answer_key)\n```\n\n### More with `composite`\n\nComposite strategies are just functions and can be called in other strategies. This means you can use it to create complex connected data. Let's say we want to generate several `ExamInstances` for the same student and exam. We can break this into several composable pieces:\n\n```py\n@st.composite\ndef exam_instance_for_exam(draw, exam, student=\"\"):\n    answers = ei_answers_strategy(exam)\n    return ExamInstance(student=student, exam=exam, answers=draw(answers))\n\n@st.composite\ndef many_exam_instances(draw, student=\"\"):\n    exam = draw(st.from_type(Exam))\n    exams = st.lists(exam_instance_for_exam(exam, student), min_size=1)\n    return draw(exams)\n\n@given(many_exam_instances(\"brian\"))\ndef test_7(eis):\n    ...\n```\n\nIn this case we're only passing raw values into the composite. This means we can't randomize the name of the student. In some cases this is an advantage, as it restricts the state space we have to search. In other cases this is a disadvantage, as it  goes against the spirit of property testing. If you want the more thorough testing, you can pass in strategies instead into the composite and draw values in the body of the function.\n\n```py\n@st.composite\ndef exam_instance_for_exam(draw, exam, student=st.just(\"\")):\n    student = draw(student)\n    exam = draw(exam)\n    answers = ei_answers_strategy(exam)\n    return ExamInstance(student=student, exam=exam, answers=draw(answers))\n\n# many_exam_instances is the same... for now\n```\n\nThere's a usability problem with this, though. Imagine we have `many_exam_instances` pass in complex strategies for `exam` and `student`. How do we know what values we drew? In this _particular_ case we can extract them from the returned ExamInstance, but we can't always rely on that, especially if we do more complex transformations. For this reason it's usually a good idea to pass back all the draws from the composite.\n\n```diff\n@st.composite\ndef exam_instance_for_exam(draw, exam, student=st.just(\"\")):\n-  return ExamInstance(student=student, exam=exam, answers=draw(answers))\n+  return exam, student, ExamInstance(student=student, exam=exam, answers=draw(answers))\n```\n\nWe also have to adjust `many_exam_instances` and our test. In particular we can't pass `exam_instance_for_exam` directly to the `lists` strategy anymore, as that assumed it only returned an ExamInstance. Now that we're returning a tuple of data it gets a bit messier.\n\n```py\n@st.composite\ndef many_exam_instances(draw, student=st.just(\"\")):\n    exam = draw(st.from_type(Exam))\n    student = draw(student)\n\n    # Unidiomatic/inefficient: getting the values in a loop\n    number = draw(st.integers(1, 5))\n    instances = []\n    for _ in range(number):\n        ei_strategy = exam_instance_for_exam(exam=st.just(exam), student=st.just(student))\n        _, _, ei = draw(ei_strategy)\n        instances.append(ei)\n\n    # Best practice: use lists(), in this case after .map()\n    instance_strat = exam_instance_for_exam(exam, student).map(lambda x: x[2])\n    instances = draw(st.lists(instance_strat, min_size=1))\n\n    return number, exam, student, instances\n\n@given(many_exam_instances(student=st.characters()))\ndef test_8(stuff):\n    _, exam, _, eis = stuff\n    ...\n```\n\nAs you can see, this leads to a bit more boilerplate. Whether the tradeoffs are worth it depends on your specific case.\n\n## `data`\n\nThe last way to generate complex inputs is the `data` strategy. Like `composite`, it gives us a `draw` function that we can use to interactively pick values. Unlike `composite`, we can use it in the test body! Instead of `exam_instance_strategy`, we can do this instead:\n\n```py\n@given(st.data(), st.from_type(Exam))\ndef test_data(data, exam):\n    answers = data.draw(ei_answers_strategy(exam))\n\n    ei = ExamInstance(student=1, exam=exam, answers=answers)\n    assert len(ei.answers) == len(ei.exam.answer_key)\n```\n\nThe main benefit of `data` is that you can customize your strategy based on the behavior inside the test. Something like:\n\n```py\nif f(x):\n    y = data.draw(st.integers(min_value=1, max_value=10))\nelse:\n    y = data.draw(st.integers(min_value=6, max_value=20))\n```\n\nThe downside is that `data` doesn't play well with some other Hypothesis features, like the `@example()` decorator, and error reporting is a bit more complicated. If you can generate all your data ahead of time then you're better off using composites.\n\n## Summary\n\nHypothesis can infer a lot using `from_type`. If most random inputs are valid and you just need to rule out rare edge cases, then `assume` and `filter` are simple and effective. Past that, you can use `builds` to generate data with complex invariants. The `composite` strategy gives you even more control and lets you relate multiple draws to each other, making it possible to create lots of interdependent data. Finally, the `data` strategy lets you interactively pick values in the test itself. And all custom strategies can be associated with a type via `register_type_strategy`.\n\nHypothesis provides a lot of mechanisms to create complex data. Learning how to use them well is a bit of an art, but well worth it. Hopefully this makes \"what to use when\" a little more clear.\n\n_Thanks to Zac Hatfield-Dodds and Oskar Wickström for feedback._\n"
  },
  {
    "path": "website/content/2025-08-07-thread-safe.md",
    "content": "---\ndate: 2025-08-07 00:00\ntitle: Hypothesis is now thread-safe\nauthor: liam\n---\n\n*TL;DR: as of [version 6.136.9](https://hypothesis.readthedocs.io/en/latest/changelog.html#v6-136-9), Hypothesis supports running the same test simultaneously from multiple threads.*\n\nHypothesis has historically had the following thread-safety policy:\n\n* Running tests in multiple processes: fully supported.\n* Running separate tests in multiple threads: not officially supported, but mostly worked.\n* Running the same test in multiple threads: not supported, and didn't work.\n\nNo longer! In a series of releases spanning from [v6.135.17](https://hypothesis.readthedocs.io/en/latest/changelog.html#v6-135-17) to [v6.136.9](https://hypothesis.readthedocs.io/en/latest/changelog.html#v6-136-9), Hypothesis has gained official support for all three of these cases. You can read about the details of what we now guarantee [here](https://hypothesis.readthedocs.io/en/latest/compatibility.html#thread-safety-policy). The now-historic tracking issue is [here](https://github.com/HypothesisWorks/hypothesis/issues/4451).\n\n## Why now?\n\nWhile we of course would always have loved for Hypothesis to be thread-safe, thread-safety has historically not been a priority, because running Hypothesis tests under multiple threads is not something we see often.\n\nThat changed recently. Python—as both a language, and a community—is gearing up to [remove the global interpreter lock (GIL)](https://peps.python.org/pep-0703/), in a build called [free threading](https://docs.python.org/3/howto/free-threading-python.html). Python packages, especially those that interact with the C API, will need to test that their code still works under the free threaded build. A great way to do this is to run each test in the suite in two or more threads simultaneously.\n\nWhere does Hypothesis fit into this? When I was at [PyCon 2025](https://us.pycon.org/2025/) in May earlier this year, I talked with [Nathan Goldbaum](https://github.com/ngoldbaum) from [Quansight](https://quansight.com/), who is one of the people working on community free threading compatibility. Nathan mentioned that because Hypothesis is not thread-safe, Hypothesis tests in community packages have to be skipped when testing free threaded compatibility, which removes a substantial battery of coverage.\n\nAs a result, Quansight contracted me to work on making Hypothesis thread-safe. I enjoy contributing to Hypothesis in my free time even without a monetary incentive, so this was a pleasure to do, and Nathan and Quansight were great to work with. (Seriously: it's thanks to them funding my time that Hypothesis is now thread-safe!)\n\n\n## A note on compatibility\n\nFree threading may have been the impetus for making Hypothesis thread-safe, but the thread-safety of Hypothesis is not tied to it. Even in the unlikely event that free threading is rolled back tomorrow by the Steering Council, Hypothesis will continue to remain thread-safe.\n\nNow, go forth and run Hypothesis in parallel!\n"
  },
  {
    "path": "website/content/2025-11-01-claude-code-plugin.md",
    "content": "---\ndate: 2025-11-01 00:00\ntitle: A Claude Code command for Hypothesis\nauthors: liam, maaz, zac-hd, carlini\n---\n\n<div class=\"cta-buttons\">\n  <a href=\"https://github.com/HypothesisWorks/hypothesis/blob/master/.claude/commands/hypothesis.md\" class=\"cta-button\">\n    <img src=\"/theme/icon-code.svg\" alt=\"icon-code\" class=\"cta-icon\">\n    View the command\n  </a>\n  <a href=\"https://mmaaz-git.github.io/agentic-pbt-site/\" class=\"cta-button\">\n    <img src=\"/theme/icon-paper.svg\" alt=\"icon-paper\" class=\"cta-icon\">\n    Read the paper\n  </a>\n</div>\n\n*We wrote a paper using Claude to autonomously write and run Hypothesis tests, and found real bugs in numpy, pandas, and other packages. We've extracted this to a Claude Code command for writing Hypothesis tests, which we're sharing today. We hope you find it useful.*\n\n*(Not familiar with property-based testing? [Learn more here](https://increment.com/testing/in-praise-of-property-based-testing/)).*\n\n---\n\nHypothesis has shipped with [the ghostwriter](https://hypothesis.readthedocs.io/en/latest/reference/integrations.html#ghostwriter) for quite a while, which automatically writes Hypothesis tests for your code. It uses nothing but good old fashioned heuristics, and is a nice way to stand up Hypothesis tests with minimal effort.\n\nRecently, we explored what this same idea might look like with modern AI tools, like Anthropic's Claude Sonnet 4.5 and OpenAI's GPT-5, and the results have been pretty compelling. So we're happy to release `/hypothesis`, a [Claude Code](https://www.claude.com/product/claude-code) command that we developed to automate writing Hypothesis tests.\n\nThe `/hypothesis` command instructs the model to automatically read your code, infer testable properties, and add Hypothesis tests to your test suite. The idea is that if you wanted to add Hypothesis tests for a file `mypackage/a/utils.py`, you could run `/hypothesis mypackage/a/utils.py`, go get a coffee, and then come back to see some new newly-added tests. You can alternatively give more complex instructions, like `/hypothesis focus on the database implementation; add tests to test_db.py`.\n\nWe've found `/hypothesis` pretty useful when combined with modern AI models, for tasks ranging from setting up tests in fresh repositories, to augmenting existing test suites, to standing up a full fuzzing workflow with [HypoFuzz](https://hypofuzz.com/).\n\nSince `/hypothesis` doesn't (yet) make sense to release in Hypothesis itself, we're releasing it here. [You can find the full command here](https://github.com/HypothesisWorks/hypothesis/blob/master/.claude/commands/hypothesis.md), install it by copying into `~/.claude/commands/`, and run it with `/hypothesis` inside of Claude Code[^1].\n\n# Designing the `/hypothesis` command\n\nThe broad goal of the `/hypothesis` command is to: (1) look at some code; (2) discover properties that make sense to test; and (3) write Hypothesis tests for those properties.\n\nAs many developers will attest, often the trickiest part of property-based testing is figuring out what property to test. This is true for modern AI models as well. We therefore design the instructions of `/hypothesis` around gathering as much context about potential properties as it can, before writing any tests. This ensures that the tests the model writes are strongly supported by factual evidence, for example in type hints, docstrings, usage patterns, or existing unit tests.\n\nThe flow of the `/hypothesis` instructions looks like this:\n\n1. Explore the provided code and identify candidate properties.\n2. Explore how the codebases calls that code in practice.\n3. Grounded in this understanding, write corresponding Hypothesis tests.\n4. Run the new Hypothesis tests, and reflect on any failures. Is it a genuine bug, or is the test incorrect? Refactor the test if necessary.\n\nThe legwork that `/hypothesis` instructs the model to do both before and after writing a test is critical for deriving high-quality tests. For example, the model might discover in step 2 that a function is called with two different input formats, and both should be tested. Or it might discover in step 4 that it wrote an unsound test, by generating test inputs the function didn't expect, like `math.nan`.\n\n## Failure modes\n\nWe observed a few failure modes while developing `/hypothesis`. For example, AI models like to write strategies with unnecessary restrictions, like limiting the maximum length of a list even when the property should hold for all lengths of lists. We added explicit instructions in `/hypothesis` not to do this, though that doesn't appear to have fixed the problem entirely.\n\nBy far the most fundamental failure mode is that the model might simply misunderstand a property in the code. For example, we ran `/hypothesis` on [python-dateutil](https://github.com/dateutil/dateutil); specifically, `/hypothesis src/easter.py`. The model determined that a property of the `easter` function is that it should always return a date on a Sunday, no matter the `method` argument, of which dateutil provides three: `method=EASTER_JULIAN`, `method=EASTER_ORTHODOX`, `method=EASTER_WESTERN`. The model wrote a test saying as much, which then failed, and it proudly claimed it had found a bug.\n\nIn fact, the model had not found a bug. In reality, `dateutil.easter` computes the date for Easter in the calendar corresponding to the passed `method`, but always returns that date in the Gregorian calendar—which might not be a Sunday. The test written by the model assumed the computation occurred in the Gregorian calendar from start to finish, which was incorrect.\n\nThis kind of subtle semantic reasoning remains difficult for models, and it's important to keep it in mind as a limitation.\n\n# Using `/hypothesis` for bug hunting\n\nArmed with a test-writing command, one natural extension is to use it to find real bugs in open-source repositories. To explore this, we used Claude Opus 4.1 to automatically write and run Hypothesis tests for a number of popular Python packages. The results were promising—we found bugs in NumPy, pandas, and Google and Amazon SDKs, and [submitted](https://github.com/numpy/numpy/pull/29609) [patches](https://github.com/aws-powertools/powertools-lambda-python/pull/7246) [for](https://github.com/aws-cloudformation/cloudformation-cli/pull/1106) [several](https://github.com/huggingface/tokenizers/pull/1853) of them. You can [read more in our paper](https://mmaaz-git.github.io/agentic-pbt-site/); it's quite short, so do give it a read if you're interested.\n\nIt's insightful to walk through one bug we found in particular: a bug in [NumPy's `numpy.random.wald`](https://numpy.org/doc/stable/reference/random/generated/numpy.random.wald.html) function (also called the inverse Gaussian distribution).\n\nTo start, we ran `/hypothesis numpy.random` to kick off the model. This directs the model to write tests for the entire `numpy.random` module. The model starts by reading the source code of `numpy.random` as well as any relevant docstrings. It sees the function `wald`, realizes from its background knowledge that the mathematical `wald` function should only produce positive values, and tracks that as a potential property. It reads further and discovers from the docstring of `wald` that both the `mean` and `scale` parameters must be greater than 0.\n\nBased on this understanding, and a few details from docstrings that we've omitted, the model proposes a range of properties:\n\n1. All outputs of `wald` are positive.\n2. No `math.nan` or `math.inf` values are returned on valid inputs.\n3. The returned array shape matches the `size` parameter.\n4. The `mean` and `scale` arrays broadcasts correctly.\n5. Seeding the distribution produces deterministic results.\n\nAnd then goes about writing Hypothesis tests for them. Here's one of the (slightly formatted) tests it writes:\n\n```python\nimport numpy as np\n\nfrom hypothesis import given, strategies as st\n\npositive_floats = st.floats(\n    min_value=1e-10, max_value=1e6, allow_nan=False, allow_infinity=False\n)\n\n\n@given(\n    mean=positive_floats,\n    scale=positive_floats,\n    size=st.integers(min_value=1, max_value=1000),\n)\ndef test_wald_all_outputs_positive(mean, scale, size):\n    \"\"\"Test that all Wald distribution samples are positive.\"\"\"\n    samples = np.random.wald(mean, scale, size)\n    assert np.all(samples > 0), f\"Found non-positive values: {samples[samples <= 0]}\"\n```\n\nIt then runs this test. And the test fails! After reflection, the model decides this is a real bug, leaves the test in the test suite, and reports the failure to the developer.\n\nWhat's going on here? We tracked this bug down to catastrophic cancellation in NumPy's `wald` implementation, which could sometimes result in negative values. We reported this to the NumPy maintainers alongside a patch with a more numerically stable algorithm. The NumPy maintainers confirmed the bug, and our fix was released in [v2.3.4](https://github.com/numpy/numpy/releases/tag/v2.3.4). You can [check out the PR here](https://github.com/numpy/numpy/pull/29609).\n\nWe think this is a really neat confirmation of both the power of property-based testing, and the ability of current AI models to reason about code.\n\n# Conclusion\n\nWe hope you find `/hypothesis` useful in adding Hypothesis tests to your test suites! Developing AI prompts is more of an art than a science; so we encourage you to give any feedback on `/hypothesis` by [opening an issue in the Hypothesis repository](https://github.com/HypothesisWorks/hypothesis/issues/new), even if it's just some open-ended thoughts.\n\n[^1]: While Claude Code is currently the most popular tool that supports custom commands, `/hypothesis` is just a markdown file, and works equally as well with any AI framework that supports commands.\n"
  },
  {
    "path": "website/content/2025-11-16-introducing-hypofuzz.md",
    "content": "---\ndate: 2025-11-16 00:01\ntitle: Introducing HypoFuzz\nauthors: liam, zac-hd\n---\n\nIf you're reading this blog, you probably know and hopefully love Hypothesis - we've been helping users write better test functions for over a decade now, which you can run with `pytest`, or `unittest`, or any other way you can call a Python function.\n\nGetting called just like a traditional unit test is great for interactive development and for CI, but those aren't the only great workflows.  What if you could get much more out of your existing tests, with no new work?\n\n**That's why we've built [HypoFuzz](https://hypofuzz.com/), which you can use today to find deep bugs and understand your tests**.\n\n<div class=\"cta-buttons\">\n  <a href=\"https://hypofuzz.com/docs/quickstart.html\" class=\"cta-button\">Quickstart</a>\n  <a href=\"https://hypofuzz.com/example-dashboard/\" class=\"cta-button\">Online demo</a>\n</div>\n\n\n# Dream workflows\n\nNelson Elhage writes about [two kinds of testing](https://blog.nelhage.com/post/two-kinds-of-testing/): *finding bugs* vs. *catching regressions*.  (and also [about PBT and fuzzing](https://blog.nelhage.com/post/property-testing-like-afl/))\nTo find bugs, you'd want to generate as many random inputs as possible; to catch regressions you'd want a fast and deterministic test suite.\n\nHypothesis can be configured to serve each of these roles, with the `phases=` setting, and database or `@example()` decorator making it easy to move valuable test cases found during the slow and random search into a fast deterministic configuration.  This is in fact how CPython uses Hypothesis: in most configurations, their tests *only* run the `@example` cases; and then there are separate CI workers which use the same tests to search for new failing inputs.\n\nHypoFuzz lets you push this even further: you can dedicate a server to looking for interesting inputs - whether failing, or just covering some under-tested behavior.  We usually give dev machines read-only access to the fuzzing database, so that any failures can be reproduced simply by running the tests locally, but keep CI machines more isolated to avoid blocking work in flight when latent bugs are eventually discovered.\n\n\n# Finding deeper bugs\n\nWhen it comes to finding deep bugs, HypoFuzz has several advantages over Hypothesis - even if you're running them for the same length of time.  These are due to either solving a different problem, or using heuristics and techniques which pay off in longer runs but have too much overhead to use in an interactive or CI-style workflow.\n\nHypoFuzz uses a more expensive, more powerful approach to input generation, organized around coverage-guided fuzzing.  At a high level, we record the code coverage from each input, and can generate new inputs either from scratch, or as variations on a previously generated input.  This is particularly useful because once we discover how to trigger rare behavior, we can search that area until the behavior is no longer rare.  Even our earliest, very basic implementations of this approach found novel bugs in `hypothesis-jsonschema` which Hypothesis had missed for hundreds of hours.\n\nHypoFuzz also dynamically optimizes the allocation of search time *between* test functions, to maximize the overall bug discovery rate.  Tests for very simple code can \"saturate\" relatively quickly; and as they do we'll spend more and more runtime on the remaining tests where more coverage (and bugs) remain to be found.  This also allows us to flexibly autoscale the whole system, so you can run HypoFuzz on anything from your laptop, to a dedicated server, to a pool of spot instances or fragments of idle CPU.\n\n<img src=\"{static}/images/hypofuzz_dashboard.png\" alt=\"HypoFuzz dashboard\" style=\"max-width: 100%;\" />\n\nCheck out [our literature review](https://hypofuzz.com/docs/literature.html) to read more about these techniques!\n\n\n# Understand your tests\n\nEver written a test and been suspicious when it passes first-try? The dashboard shows input distributions and lets you inspect individual test cases. For particularly interesting tests, you can add custom events for HypoFuzz to graph.\n\n<img src=\"{static}/images/hypofuzz_observability.webp\" alt=\"HypoFuzz observability\" style=\"max-width: 100%;\" />\n\n[The Tyche vscode extension](https://marketplace.visualstudio.com/items?itemName=HarrisonGoldstein.tyche) gives you similar feedback live in your editor, while the HypoFuzz dashboard can collect, store, and analyze a larger volume of data - including from other machines.  We recommend both :-)\n\n\n# Why not open source?\n\nWe love open source as much as anyone else, and have spent full-time-years worth of work maintaining and improving Hypothesis for free.  It's great to hear from middle-schoolers, open-source maintainers, researchers, hobbyists, and professional engineers using Hypothesis, and Hypothesis itself will remain open-source forever.  Non-commercial use of HypoFuzz is completely free, too--the more people who can build ambitious things with the confidence fuzzing brings, the happier we'll be.\n\nThe pitch for *HypoFuzz* though is that we can offer a way to turn money spent on compute into discovered bugs - and we think it's fair for businesses who spend money running HypoFuzz to pay some of that money to us, not just their cloud provider.\n\nFinally... if we could pay the bills by working on Hypothesis and HypoFuzz, we'd both have a lot of fun and advance the state of the art a lot faster!  The low-hanging fruit is long gone from [our issue tracker](https://github.com/HypothesisWorks/hypothesis/issues), and the remaining issues are often pretty gnarly or require deep enough context that external contributors are rare.\n\n\n# Call to fuzzing!\n\n* **[Start using HypoFuzz](https://hypofuzz.com/docs/quickstart.html)**: it's free for non-commercial use, and businesses can [get in touch](mailto:sales@hypofuzz.com?subject=Evaluation%20HypoFuzz%20licence) for a no-cost evaluation license.\n* **We want to hear from you**, so we can help make HypoFuzz work for you: [get in touch](mailto:hello@hypofuzz.com?subject=HypoFuzz) or [book a chat](https://calendar.app.google/XDBzPvxbLaP2tQLE8) to tell us what you want to see in HypoFuzz, or in general fuzzing / PBT workflows!\n"
  },
  {
    "path": "website/content/pages/testimonials.md",
    "content": "---\ntitle: Testimonials\ndate: 2015-04-25 22:03\n---\n\n<blockquote class=\"testimonial blockquote-reverse pull\" id='alex-stapleton'>\n<p>\nHypothesis is easy to learn and powerful implementation of property based testing,\nand generally an invaluable tool. At Lyst we've used it in a wide variety of\nsituations, from testing APIs to machine learning algorithms and in all\ncases it's given us a great deal more confidence in that code.\n</p>\n<footer>Alex Stapleton, Lead Backend Engineer at <a href=\"https://www.lyst.com/\">Lyst</a></footer></cite>\n</blockquote>\n\n<blockquote class=\"testimonial blockquote-reverse pull\" id='cory-benfield'>\n<p>\nHypothesis is the single most powerful tool in my toolbox for working with\nalgorithmic code, or any software that produces predictable output from a wide\nrange of sources. When using it with <a href=\"http://python-hyper.org/priority/\">Priority</a>, Hypothesis consistently found\nerrors in my assumptions and extremely subtle bugs that would have taken months\nof real-world use to locate. In some cases, Hypothesis found subtle deviations\nfrom the correct output of the algorithm that may never have been noticed at\nall.\n</p>\n<p>\nWhen it comes to validating the correctness of your tools, nothing comes close\nto the thoroughness and power of Hypothesis.\n</p>\n <footer><a href=\"https://github.com/Lukasa\">Cory Benfield</a></footer></cite>\n</blockquote>\n\n<blockquote class=\"testimonial blockquote-reverse pull\" id='kristian-glass'>\n<p>Hypothesis has been brilliant for expanding the coverage of our test cases,\nand also for making them much easier to read and understand,\nso we're sure we're testing the things we want in the way we want.</p>\n <footer><a href=\"/testimonials/#kristian-glass\">Kristian Glass</a>, Director of Technology at <a href=\"https://www.laterpay.net/\">LaterPay</a></footer></cite>\n</blockquote>\n\n<blockquote class=\"testimonial blockquote-reverse pull\" id='sixty-north'>\n<p>\nAt Sixty North we use Hypothesis for testing\n<a href=\"https://github.com/sixty-north/segpy\">Segpy</a>, an open source Python library for\nshifting data between Python data structures and SEG Y files which contain\ngeophysical data from the seismic reflection surveys used in oil and gas\nexploration.</p>\n\n<p>This is our first experience of property-based testing – as opposed to example-based\ntesting.  Not only are our tests more powerful, they are also much better\nexplanations of what we expect of the production code. In fact, the tests are much\ncloser to being specifications.  Hypothesis has located real defects in our code\nwhich went undetected by traditional test cases, simply because Hypothesis is more\nrelentlessly devious about test case generation than us mere humans!  We found\nHypothesis particularly beneficial for Segpy because SEG Y is an antiquated format\nthat uses legacy text encodings (EBCDIC) and even a legacy floating point format\nwe implemented from scratch in Python.</p>\n\n<p>\nHypothesis is sure to find a place in most of our future Python codebases and many\nexisting ones too.\n</p>\n <footer>Rob Smallshire, <a href=\"http://sixty-north.com/\">Sixty North</a></footer></cite>\n</blockquote>\n\n\n<blockquote class=\"testimonial blockquote-reverse pull\" id='seth-morton'>\n<p>\nWhen I first heard about Hypothesis, I knew I had to include it in my two\nopen-source Python libraries, <a href=\"https://github.com/SethMMorton/natsort\">natsort</a>\nand <a href=\"https://github.com/SethMMorton/fastnumbers\">fastnumbers</a>.</p>\n\n<p>Quite frankly,\nI was a little appalled at the number of bugs and \"holes\" I found in the code. I can\nnow say with confidence that my libraries are more robust to \"the wild.\" In\naddition, Hypothesis gave me the confidence to expand these libraries to fully\nsupport Unicode input, which I never would have had the stomach for without such\nthorough testing capabilities. Thanks!\n</p>\n\n <footer><a href=\"https://github.com/SethMMorton\">Seth Morton</a></footer></cite>\n\n</blockquote>\n\n<blockquote class=\"testimonial blockquote-reverse pull\" id='mulkieran'>\n<p>\nJust found out about this excellent QuickCheck for Python implementation and\nran up a few tests for my <a href=\"https://github.com/mulkieran/bytesize\">bytesize</a>\npackage last night. Refuted a few hypotheses in the process.\n</p>\n\n<p>\nLooking forward to using it with a bunch of other projects as well.\n</p>\n<footer>\n<a href=\"https://github.com/mulkieran\">mulkieran</a>\n</footer>\n</blockquote>\n\n\n<blockquote class=\"testimonial blockquote-reverse pull\" id='adam-johnson'>\n<p> I have written a small library to serialize dicts to MariaDB's dynamic columns binary format, <a href=https://github.com/adamchainz/mariadb-dyncol\">mariadb-dyncol</a>. When I first\ndeveloped it, I thought I had tested it really well - there were hundreds of\ntest cases, some of them even taken from MariaDB's test suite itself. I was\nready to release.\n</p>\n\n<p>\nLucky for me, I tried Hypothesis with David at the PyCon UK sprints. Wow! It\nfound bug after bug after bug. Even after a first release, I thought of a way\nto make the tests do more validation, which revealed a further round of bugs!\nMost impressively, Hypothesis found a complicated off-by-one error in a\ncondition with 4095 versus 4096 bytes of data - something that I would never\nhave found.\n</p>\n<p>\nLong live Hypothesis! (Or at least, property-based testing).\n</p>\n<footer>\n<a href=\"https://github.com/adamchainz\">Adam Johnson</a>\n</footer>\n</blockquote>\n\n<blockquote class=\"testimonial blockquote-reverse pull\" id='adam-johnson'>\n<p>\nAdopting Hypothesis improved <a href=\"https://github.com/jab/bidict\">bidict</a>'s\ntest coverage and significantly increased our ability to make changes to\nthe code with confidence that correct behavior would be preserved.\nThank you, David, for the great testing tool.\n</p>\n<footer>\n<a href=\"https://github.com/jab\">Josh Bronson</a>\n</footer>\n</blockquote>\n\n\n<blockquote class=\"testimonial blockquote-reverse pull\" id='jon-moore'>\n<p>\nOne extremely satisfied user here. Hypothesis is a really solid implementation\nof property-based testing, adapted well to Python, and with good features\nsuch as failure-case shrinkers. I first used it on a project where we needed\nto verify that a vendor's Python and non-Python implementations of an algorithm\nmatched, and it found about a dozen cases that previous example-based testing\nand code inspections had not. Since then I've been evangelizing for it at our firm.\n</p>\n<footer>\n<a href=\"https://github.com/jonmoore\">Jon Moore</a>\n</footer>\n</blockquote>\n\n<h3>Your name goes here</h3>\n<p>\nWant to add to the list by telling us about your Hypothesis experience? Drop us\nan email at <a href=\"mailto:testimonials@hypothesis.works\">testimonials@hypothesis.works</a>\nand we'll add it to the list!\n</p>\n<p>\n\n</p>"
  },
  {
    "path": "website/pelicanconf.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nSITENAME = AUTHOR = \"Hypothesis\"\nSITESUBTITLE = \"The property-based testing library for Python\"\n# SITEURL = \"https://hypothesis.works\"\n\nPATH = \"content\"\nTIMEZONE = \"UTC\"\nDELETE_OUTPUT_DIRECTORY = True\n\n# Feed generation is usually not desired when developing\nFEED_ALL_ATOM = None\nCATEGORY_FEED_ATOM = None\nTRANSLATION_FEED_ATOM = None\nAUTHOR_FEED_ATOM = None\nAUTHOR_FEED_RSS = None\n\nARTICLE_URL = \"{category}/{slug}/\"\nARTICLE_SAVE_AS = \"{category}/{slug}/index.html\"\nDEFAULT_CATEGORY = \"articles\"\nDISPLAY_PAGES_ON_MENU = False\n\nCATEGORY_URL = \"articles/\"\nCATEGORY_SAVE_AS = \"articles/index.html\"\n\n# Disable the default archives page\nARCHIVES_SAVE_AS = \"\"\n\nFILENAME_METADATA = r\"(?P<date>\\d{4}-\\d{2}-\\d{2})-(?P<slug>.+)\"\n\nTHEME = \"./theme/\"\nSTATIC_PATHS = [\n    \"images\",\n    \"../../brand/favicon.ico\",\n    \"../../brand/dragonfly-rainbow.svg\",\n    \"../archive-redirect.html\",\n]\nEXTRA_PATH_METADATA = {\n    \"../../brand/favicon.ico\": {\"path\": \"favicon.ico\"},\n    \"../../brand/dragonfly-rainbow.svg\": {\"path\": \"dragonfly-rainbow.svg\"},\n    \"../archive-redirect.html\": {\"path\": \"archives.html\"},\n}\nPROFILE_IMAGE_URL = \"/dragonfly-rainbow.svg\"\n\nMENUITEMS = (\n    (\"Blog\", \"/articles\"),\n    (\"Docs\", \"https://hypothesis.readthedocs.io/en/latest/\"),\n    (\"GitHub\", \"https://github.com/HypothesisWorks/hypothesis/\"),\n    (\"PyPI\", \"https://pypi.org/project/hypothesis/\"),\n)\n\n# Author information - map from short alias to full name and URL\nAUTHOR_NAMES = {\n    \"alexwlchan\": \"Alex Chan\",\n    \"carlini\": \"Nicholas Carlini\",\n    \"drmaciver\": \"David R. MacIver\",\n    \"giorgiosironi\": \"Giorgio Sironi\",\n    \"hwayne\": \"Hillel Wayne\",\n    \"jml\": \"Jonathan M. Lange\",\n    \"liam\": \"Liam DeVoe\",\n    \"maaz\": \"Muhammad Maaz\",\n    \"nchammas\": \"Nicholas Chammas\",\n    \"zac-hd\": \"Zac Hatfield-Dodds\",\n}\n\nAUTHOR_URLS = {\n    \"alexwlchan\": \"https://alexwlchan.net\",\n    \"carlini\": \"https://nicholas.carlini.com/\",\n    \"drmaciver\": \"http://www.drmaciver.com\",\n    \"giorgiosironi\": \"http://giorgiosironi.com\",\n    \"hwayne\": \"https://www.hillelwayne.com/\",\n    \"jml\": \"https://jml.io\",\n    \"liam\": \"https://tybug.dev\",\n    \"maaz\": \"https://www.mmaaz.ca/\",\n    \"nchammas\": \"http://nchammas.com\",\n    \"zac-hd\": \"https://zhd.dev\",\n}\nassert set(AUTHOR_URLS).issubset(AUTHOR_NAMES)\n\nDEFAULT_PAGINATION = False\n\n# same as the default from https://docs.getpelican.com/en/latest/settings.html#MARKDOWN,\n# but with use_pygments = False, since we use prism.js for syntax highlighting\n# instead.\nMARKDOWN = {\n    \"extension_configs\": {\n        \"markdown.extensions.codehilite\": {\n            \"use_pygments\": False,\n            \"css_class\": \"highlight\",\n        },\n        \"markdown.extensions.extra\": {},\n        \"markdown.extensions.meta\": {},\n    },\n    \"output_format\": \"html5\",\n}\n\n# Uncomment following line if you want document-relative URLs when developing\n# RELATIVE_URLS = True\n"
  },
  {
    "path": "website/theme/static/prism.css",
    "content": "/* PrismJS 1.17.1  https://prismjs.com/download.html#themes=prism&languages=python\n* prism.js default theme for JavaScript, CSS and HTML by Lea Verou, based on dabblet.com\n* Modified by Zac Hatfield-Dodds; removed background, match github's python colors closer, etc.\n*/\n\npre[class*=\"language-\"]::-moz-selection,\npre[class*=\"language-\"] ::-moz-selection {\n  text-shadow: none;\n}\n\n@media print {\n  pre[class*=\"language-\"] {\n    text-shadow: none;\n  }\n}\n\n/* Code blocks */\npre[class*=\"language-\"] {\n  overflow: auto;\n}\n\n/* Ensure tokens don't override line-height */\npre[class*=\"language-\"] * {\n  line-height: inherit;\n}\n\n.token.comment,\n.token.prolog,\n.token.doctype,\n.token.cdata {\n  color: #6a737d;\n}\n\n.token.punctuation {\n  color: #24292e;\n}\n\n.namespace {\n  opacity: 0.7;\n}\n\n.token.property,\n.token.tag,\n.token.boolean,\n.token.number,\n.token.constant,\n.token.symbol,\n.token.deleted {\n  color: #005cc5;\n}\n\n.token.selector,\n.token.attr-name,\n.token.string,\n.token.char,\n.token.builtin,\n.token.inserted {\n  color: #032f62;\n}\n\n.token.operator,\n.token.entity,\n.token.url,\n.language-css .token.string,\n.style .token.string {\n  color: #24292e;\n}\n\n.token.atrule,\n.token.attr-value,\n.token.keyword {\n  color: #d73a49;\n}\n\n.token.function,\n.token.class-name,\n.token.decorator {\n  color: #6f42c1;\n}\n\n.token.regex,\n.token.important,\n.token.variable {\n  color: #e36209;\n}\n\n.token.important,\n.token.bold {\n  font-weight: bold;\n}\n\n.token.italic {\n  font-style: italic;\n}\n"
  },
  {
    "path": "website/theme/static/prism.js",
    "content": "/* PrismJS 1.30.0\nhttps://prismjs.com/download.html#themes=prism-coy&languages=markup+css+clike+javascript+python */\nvar _self=\"undefined\"!=typeof window?window:\"undefined\"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(e){var n=/(?:^|\\s)lang(?:uage)?-([\\w-]+)(?=\\s|$)/i,t=0,r={},a={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof i?new i(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/\\u00a0/g,\" \")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,\"__id\",{value:++t}),e.__id},clone:function e(n,t){var r,i;switch(t=t||{},a.util.type(n)){case\"Object\":if(i=a.util.objId(n),t[i])return t[i];for(var l in r={},t[i]=r,n)n.hasOwnProperty(l)&&(r[l]=e(n[l],t));return r;case\"Array\":return i=a.util.objId(n),t[i]?t[i]:(r=[],t[i]=r,n.forEach((function(n,a){r[a]=e(n,t)})),r);default:return n}},getLanguage:function(e){for(;e;){var t=n.exec(e.className);if(t)return t[1].toLowerCase();e=e.parentElement}return\"none\"},setLanguage:function(e,t){e.className=e.className.replace(RegExp(n,\"gi\"),\"\"),e.classList.add(\"language-\"+t)},currentScript:function(){if(\"undefined\"==typeof document)return null;if(document.currentScript&&\"SCRIPT\"===document.currentScript.tagName)return document.currentScript;try{throw new Error}catch(r){var e=(/at [^(\\r\\n]*\\((.*):[^:]+:[^:]+\\)$/i.exec(r.stack)||[])[1];if(e){var n=document.getElementsByTagName(\"script\");for(var t in n)if(n[t].src==e)return n[t]}return null}},isActive:function(e,n,t){for(var r=\"no-\"+n;e;){var a=e.classList;if(a.contains(n))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!t}},languages:{plain:r,plaintext:r,text:r,txt:r,extend:function(e,n){var t=a.util.clone(a.languages[e]);for(var r in n)t[r]=n[r];return t},insertBefore:function(e,n,t,r){var i=(r=r||a.languages)[e],l={};for(var o in i)if(i.hasOwnProperty(o)){if(o==n)for(var s in t)t.hasOwnProperty(s)&&(l[s]=t[s]);t.hasOwnProperty(o)||(l[o]=i[o])}var u=r[e];return r[e]=l,a.languages.DFS(a.languages,(function(n,t){t===u&&n!=e&&(this[n]=l)})),l},DFS:function e(n,t,r,i){i=i||{};var l=a.util.objId;for(var o in n)if(n.hasOwnProperty(o)){t.call(n,o,n[o],r||o);var s=n[o],u=a.util.type(s);\"Object\"!==u||i[l(s)]?\"Array\"!==u||i[l(s)]||(i[l(s)]=!0,e(s,t,o,i)):(i[l(s)]=!0,e(s,t,null,i))}}},plugins:{},highlightAll:function(e,n){a.highlightAllUnder(document,e,n)},highlightAllUnder:function(e,n,t){var r={callback:t,container:e,selector:'code[class*=\"language-\"], [class*=\"language-\"] code, code[class*=\"lang-\"], [class*=\"lang-\"] code'};a.hooks.run(\"before-highlightall\",r),r.elements=Array.prototype.slice.apply(r.container.querySelectorAll(r.selector)),a.hooks.run(\"before-all-elements-highlight\",r);for(var i,l=0;i=r.elements[l++];)a.highlightElement(i,!0===n,r.callback)},highlightElement:function(n,t,r){var i=a.util.getLanguage(n),l=a.languages[i];a.util.setLanguage(n,i);var o=n.parentElement;o&&\"pre\"===o.nodeName.toLowerCase()&&a.util.setLanguage(o,i);var s={element:n,language:i,grammar:l,code:n.textContent};function u(e){s.highlightedCode=e,a.hooks.run(\"before-insert\",s),s.element.innerHTML=s.highlightedCode,a.hooks.run(\"after-highlight\",s),a.hooks.run(\"complete\",s),r&&r.call(s.element)}if(a.hooks.run(\"before-sanity-check\",s),(o=s.element.parentElement)&&\"pre\"===o.nodeName.toLowerCase()&&!o.hasAttribute(\"tabindex\")&&o.setAttribute(\"tabindex\",\"0\"),!s.code)return a.hooks.run(\"complete\",s),void(r&&r.call(s.element));if(a.hooks.run(\"before-highlight\",s),s.grammar)if(t&&e.Worker){var c=new Worker(a.filename);c.onmessage=function(e){u(e.data)},c.postMessage(JSON.stringify({language:s.language,code:s.code,immediateClose:!0}))}else u(a.highlight(s.code,s.grammar,s.language));else u(a.util.encode(s.code))},highlight:function(e,n,t){var r={code:e,grammar:n,language:t};if(a.hooks.run(\"before-tokenize\",r),!r.grammar)throw new Error('The language \"'+r.language+'\" has no grammar.');return r.tokens=a.tokenize(r.code,r.grammar),a.hooks.run(\"after-tokenize\",r),i.stringify(a.util.encode(r.tokens),r.language)},tokenize:function(e,n){var t=n.rest;if(t){for(var r in t)n[r]=t[r];delete n.rest}var a=new s;return u(a,a.head,e),o(e,a,n,a.head,0),function(e){for(var n=[],t=e.head.next;t!==e.tail;)n.push(t.value),t=t.next;return n}(a)},hooks:{all:{},add:function(e,n){var t=a.hooks.all;t[e]=t[e]||[],t[e].push(n)},run:function(e,n){var t=a.hooks.all[e];if(t&&t.length)for(var r,i=0;r=t[i++];)r(n)}},Token:i};function i(e,n,t,r){this.type=e,this.content=n,this.alias=t,this.length=0|(r||\"\").length}function l(e,n,t,r){e.lastIndex=n;var a=e.exec(t);if(a&&r&&a[1]){var i=a[1].length;a.index+=i,a[0]=a[0].slice(i)}return a}function o(e,n,t,r,s,g){for(var f in t)if(t.hasOwnProperty(f)&&t[f]){var h=t[f];h=Array.isArray(h)?h:[h];for(var d=0;d<h.length;++d){if(g&&g.cause==f+\",\"+d)return;var v=h[d],p=v.inside,m=!!v.lookbehind,y=!!v.greedy,k=v.alias;if(y&&!v.pattern.global){var x=v.pattern.toString().match(/[imsuy]*$/)[0];v.pattern=RegExp(v.pattern.source,x+\"g\")}for(var b=v.pattern||v,w=r.next,A=s;w!==n.tail&&!(g&&A>=g.reach);A+=w.value.length,w=w.next){var P=w.value;if(n.length>e.length)return;if(!(P instanceof i)){var E,S=1;if(y){if(!(E=l(b,A,e,m))||E.index>=e.length)break;var L=E.index,O=E.index+E[0].length,C=A;for(C+=w.value.length;L>=C;)C+=(w=w.next).value.length;if(A=C-=w.value.length,w.value instanceof i)continue;for(var j=w;j!==n.tail&&(C<O||\"string\"==typeof j.value);j=j.next)S++,C+=j.value.length;S--,P=e.slice(A,C),E.index-=A}else if(!(E=l(b,0,P,m)))continue;L=E.index;var N=E[0],_=P.slice(0,L),M=P.slice(L+N.length),W=A+P.length;g&&W>g.reach&&(g.reach=W);var I=w.prev;if(_&&(I=u(n,I,_),A+=_.length),c(n,I,S),w=u(n,I,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),S>1){var T={cause:f+\",\"+d,reach:W};o(e,n,t,w.prev,A,T),g&&T.reach>g.reach&&(g.reach=T.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a<t&&r!==e.tail;a++)r=r.next;n.next=r,r.prev=n,e.length-=a}if(e.Prism=a,i.stringify=function e(n,t){if(\"string\"==typeof n)return n;if(Array.isArray(n)){var r=\"\";return n.forEach((function(n){r+=e(n,t)})),r}var i={type:n.type,content:e(n.content,t),tag:\"span\",classes:[\"token\",n.type],attributes:{},language:t},l=n.alias;l&&(Array.isArray(l)?Array.prototype.push.apply(i.classes,l):i.classes.push(l)),a.hooks.run(\"wrap\",i);var o=\"\";for(var s in i.attributes)o+=\" \"+s+'=\"'+(i.attributes[s]||\"\").replace(/\"/g,\"&quot;\")+'\"';return\"<\"+i.tag+' class=\"'+i.classes.join(\" \")+'\"'+o+\">\"+i.content+\"</\"+i.tag+\">\"},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener(\"message\",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute(\"data-manual\")&&(a.manual=!0)),!a.manual){var h=document.readyState;\"loading\"===h||\"interactive\"===h&&g&&g.defer?document.addEventListener(\"DOMContentLoaded\",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);\"undefined\"!=typeof module&&module.exports&&(module.exports=Prism),\"undefined\"!=typeof global&&(global.Prism=Prism);\nPrism.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\\s\\S])*?-->/,greedy:!0},prolog:{pattern:/<\\?[\\s\\S]+?\\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>\"'[\\]]|\"[^\"]*\"|'[^']*')+(?:\\[(?:[^<\"'\\]]|\"[^\"]*\"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\\]\\s*)?>/i,greedy:!0,inside:{\"internal-subset\":{pattern:/(^[^\\[]*\\[)[\\s\\S]+(?=\\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/\"[^\"]*\"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\\]]/,\"doctype-tag\":/^DOCTYPE/i,name:/[^\\s<>'\"]+/}},cdata:{pattern:/<!\\[CDATA\\[[\\s\\S]*?\\]\\]>/i,greedy:!0},tag:{pattern:/<\\/?(?!\\d)[^\\s>\\/=$<%]+(?:\\s(?:\\s*[^\\s>\\/=]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))|(?=[\\s/>])))+)?\\s*\\/?>/,greedy:!0,inside:{tag:{pattern:/^<\\/?[^\\s>\\/]+/,inside:{punctuation:/^<\\/?/,namespace:/^[^\\s>\\/:]+:/}},\"special-attr\":[],\"attr-value\":{pattern:/=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:\"attr-equals\"},{pattern:/^(\\s*)[\"']|[\"']$/,lookbehind:!0}]}},punctuation:/\\/?>/,\"attr-name\":{pattern:/[^\\s>\\/]+/,inside:{namespace:/^[^\\s>\\/:]+:/}}}},entity:[{pattern:/&[\\da-z]{1,8};/i,alias:\"named-entity\"},/&#x?[\\da-f]{1,8};/i]},Prism.languages.markup.tag.inside[\"attr-value\"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside[\"internal-subset\"].inside=Prism.languages.markup,Prism.hooks.add(\"wrap\",(function(a){\"entity\"===a.type&&(a.attributes.title=a.content.replace(/&amp;/,\"&\"))})),Object.defineProperty(Prism.languages.markup.tag,\"addInlined\",{value:function(a,e){var s={};s[\"language-\"+e]={pattern:/(^<!\\[CDATA\\[)[\\s\\S]+?(?=\\]\\]>$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^<!\\[CDATA\\[|\\]\\]>$/i;var t={\"included-cdata\":{pattern:/<!\\[CDATA\\[[\\s\\S]*?\\]\\]>/i,inside:s}};t[\"language-\"+e]={pattern:/[\\s\\S]+/,inside:Prism.languages[e]};var n={};n[a]={pattern:RegExp(\"(<__[^>]*>)(?:<!\\\\[CDATA\\\\[(?:[^\\\\]]|\\\\](?!\\\\]>))*\\\\]\\\\]>|(?!<!\\\\[CDATA\\\\[)[^])*?(?=</__>)\".replace(/__/g,(function(){return a})),\"i\"),lookbehind:!0,greedy:!0,inside:t},Prism.languages.insertBefore(\"markup\",\"cdata\",n)}}),Object.defineProperty(Prism.languages.markup.tag,\"addAttribute\",{value:function(a,e){Prism.languages.markup.tag.inside[\"special-attr\"].push({pattern:RegExp(\"(^|[\\\"'\\\\s])(?:\"+a+\")\\\\s*=\\\\s*(?:\\\"[^\\\"]*\\\"|'[^']*'|[^\\\\s'\\\">=]+(?=[\\\\s>]))\",\"i\"),lookbehind:!0,inside:{\"attr-name\":/^[^\\s=]+/,\"attr-value\":{pattern:/=[\\s\\S]+/,inside:{value:{pattern:/(^=\\s*([\"']|(?![\"'])))\\S[\\s\\S]*(?=\\2$)/,lookbehind:!0,alias:[e,\"language-\"+e],inside:Prism.languages[e]},punctuation:[{pattern:/^=/,alias:\"attr-equals\"},/\"|'/]}}}})}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend(\"markup\",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml;\n!function(s){var e=/(?:\"(?:\\\\(?:\\r\\n|[\\s\\S])|[^\"\\\\\\r\\n])*\"|'(?:\\\\(?:\\r\\n|[\\s\\S])|[^'\\\\\\r\\n])*')/;s.languages.css={comment:/\\/\\*[\\s\\S]*?\\*\\//,atrule:{pattern:RegExp(\"@[\\\\w-](?:[^;{\\\\s\\\"']|\\\\s+(?!\\\\s)|\"+e.source+\")*?(?:;|(?=\\\\s*\\\\{))\"),inside:{rule:/^@[\\w-]+/,\"selector-function-argument\":{pattern:/(\\bselector\\s*\\(\\s*(?![\\s)]))(?:[^()\\s]|\\s+(?![\\s)])|\\((?:[^()]|\\([^()]*\\))*\\))+(?=\\s*\\))/,lookbehind:!0,alias:\"selector\"},keyword:{pattern:/(^|[^\\w-])(?:and|not|only|or)(?![\\w-])/,lookbehind:!0}}},url:{pattern:RegExp(\"\\\\burl\\\\((?:\"+e.source+\"|(?:[^\\\\\\\\\\r\\n()\\\"']|\\\\\\\\[^])*)\\\\)\",\"i\"),greedy:!0,inside:{function:/^url/i,punctuation:/^\\(|\\)$/,string:{pattern:RegExp(\"^\"+e.source+\"$\"),alias:\"url\"}}},selector:{pattern:RegExp(\"(^|[{}\\\\s])[^{}\\\\s](?:[^{};\\\"'\\\\s]|\\\\s+(?![\\\\s{])|\"+e.source+\")*(?=\\\\s*\\\\{)\"),lookbehind:!0},string:{pattern:e,greedy:!0},property:{pattern:/(^|[^-\\w\\xA0-\\uFFFF])(?!\\s)[-_a-z\\xA0-\\uFFFF](?:(?!\\s)[-\\w\\xA0-\\uFFFF])*(?=\\s*:)/i,lookbehind:!0},important:/!important\\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\\()/i,lookbehind:!0},punctuation:/[(){};:,]/},s.languages.css.atrule.inside.rest=s.languages.css;var t=s.languages.markup;t&&(t.tag.addInlined(\"style\",\"css\"),t.tag.addAttribute(\"style\",\"css\"))}(Prism);\nPrism.languages.clike={comment:[{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\\\:])\\/\\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},\"class-name\":{pattern:/(\\b(?:class|extends|implements|instanceof|interface|new|trait)\\s+|\\bcatch\\s+\\()[\\w.\\\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\\\]/}},keyword:/\\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\\b/,boolean:/\\b(?:false|true)\\b/,function:/\\b\\w+(?=\\()/,number:/\\b0x[\\da-f]+\\b|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\\+\\+?|&&?|\\|\\|?|[?*/~^%]/,punctuation:/[{}[\\];(),.:]/};\nPrism.languages.javascript=Prism.languages.extend(\"clike\",{\"class-name\":[Prism.languages.clike[\"class-name\"],{pattern:/(^|[^$\\w\\xA0-\\uFFFF])(?!\\s)[_$A-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\\})\\s*)catch\\b/,lookbehind:!0},{pattern:/(^|[^.]|\\.\\.\\.\\s*)\\b(?:as|assert(?=\\s*\\{)|async(?=\\s*(?:function\\b|\\(|[$\\w\\xA0-\\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\\s*(?:\\{|$))|for|from(?=\\s*(?:['\"]|$))|function|(?:get|set)(?=\\s*(?:[#\\[$\\w\\xA0-\\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\\b/,lookbehind:!0}],function:/#?(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*(?:\\.\\s*(?:apply|bind|call)\\s*)?\\()/,number:{pattern:RegExp(\"(^|[^\\\\w$])(?:NaN|Infinity|0[bB][01]+(?:_[01]+)*n?|0[oO][0-7]+(?:_[0-7]+)*n?|0[xX][\\\\dA-Fa-f]+(?:_[\\\\dA-Fa-f]+)*n?|\\\\d+(?:_\\\\d+)*n|(?:\\\\d+(?:_\\\\d+)*(?:\\\\.(?:\\\\d+(?:_\\\\d+)*)?)?|\\\\.\\\\d+(?:_\\\\d+)*)(?:[Ee][+-]?\\\\d+(?:_\\\\d+)*)?)(?![\\\\w$])\"),lookbehind:!0},operator:/--|\\+\\+|\\*\\*=?|=>|&&=?|\\|\\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\\.{3}|\\?\\?=?|\\?\\.?|[~:]/}),Prism.languages.javascript[\"class-name\"][0].pattern=/(\\b(?:class|extends|implements|instanceof|interface|new)\\s+)[\\w.\\\\]+/,Prism.languages.insertBefore(\"javascript\",\"keyword\",{regex:{pattern:RegExp(\"((?:^|[^$\\\\w\\\\xA0-\\\\uFFFF.\\\"'\\\\])\\\\s]|\\\\b(?:return|yield))\\\\s*)/(?:(?:\\\\[(?:[^\\\\]\\\\\\\\\\r\\n]|\\\\\\\\.)*\\\\]|\\\\\\\\.|[^/\\\\\\\\\\\\[\\r\\n])+/[dgimyus]{0,7}|(?:\\\\[(?:[^[\\\\]\\\\\\\\\\r\\n]|\\\\\\\\.|\\\\[(?:[^[\\\\]\\\\\\\\\\r\\n]|\\\\\\\\.|\\\\[(?:[^[\\\\]\\\\\\\\\\r\\n]|\\\\\\\\.)*\\\\])*\\\\])*\\\\]|\\\\\\\\.|[^/\\\\\\\\\\\\[\\r\\n])+/[dgimyus]{0,7}v[dgimyus]{0,7})(?=(?:\\\\s|/\\\\*(?:[^*]|\\\\*(?!/))*\\\\*/)*(?:$|[\\r\\n,.;:})\\\\]]|//))\"),lookbehind:!0,greedy:!0,inside:{\"regex-source\":{pattern:/^(\\/)[\\s\\S]+(?=\\/[a-z]*$)/,lookbehind:!0,alias:\"language-regex\",inside:Prism.languages.regex},\"regex-delimiter\":/^\\/|\\/$/,\"regex-flags\":/^[a-z]+$/}},\"function-variable\":{pattern:/#?(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*[=:]\\s*(?:async\\s*)?(?:\\bfunction\\b|(?:\\((?:[^()]|\\([^()]*\\))*\\)|(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*)\\s*=>))/,alias:\"function\"},parameter:[{pattern:/(function(?:\\s+(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*)?\\s*\\(\\s*)(?!\\s)(?:[^()\\s]|\\s+(?![\\s)])|\\([^()]*\\))+(?=\\s*\\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(^|[^$\\w\\xA0-\\uFFFF])(?!\\s)[_$a-z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*=>)/i,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(\\(\\s*)(?!\\s)(?:[^()\\s]|\\s+(?![\\s)])|\\([^()]*\\))+(?=\\s*\\)\\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\\b|\\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\\w\\xA0-\\uFFFF]))(?:(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*\\s*)\\(\\s*|\\]\\s*\\(\\s*)(?!\\s)(?:[^()\\s]|\\s+(?![\\s)])|\\([^()]*\\))+(?=\\s*\\)\\s*\\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\\b[A-Z](?:[A-Z_]|\\dx?)*\\b/}),Prism.languages.insertBefore(\"javascript\",\"string\",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:\"comment\"},\"template-string\":{pattern:/`(?:\\\\[\\s\\S]|\\$\\{(?:[^{}]|\\{(?:[^{}]|\\{[^}]*\\})*\\})+\\}|(?!\\$\\{)[^\\\\`])*`/,greedy:!0,inside:{\"template-punctuation\":{pattern:/^`|`$/,alias:\"string\"},interpolation:{pattern:/((?:^|[^\\\\])(?:\\\\{2})*)\\$\\{(?:[^{}]|\\{(?:[^{}]|\\{[^}]*\\})*\\})+\\}/,lookbehind:!0,inside:{\"interpolation-punctuation\":{pattern:/^\\$\\{|\\}$/,alias:\"punctuation\"},rest:Prism.languages.javascript}},string:/[\\s\\S]+/}},\"string-property\":{pattern:/((?:^|[,{])[ \\t]*)([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\2)[^\\\\\\r\\n])*\\2(?=\\s*:)/m,lookbehind:!0,greedy:!0,alias:\"property\"}}),Prism.languages.insertBefore(\"javascript\",\"operator\",{\"literal-property\":{pattern:/((?:^|[,{])[ \\t]*)(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*:)/m,lookbehind:!0,alias:\"property\"}}),Prism.languages.markup&&(Prism.languages.markup.tag.addInlined(\"script\",\"javascript\"),Prism.languages.markup.tag.addAttribute(\"on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)\",\"javascript\")),Prism.languages.js=Prism.languages.javascript;\nPrism.languages.python={comment:{pattern:/(^|[^\\\\])#.*/,lookbehind:!0,greedy:!0},\"string-interpolation\":{pattern:/(?:f|fr|rf)(?:(\"\"\"|''')[\\s\\S]*?\\1|(\"|')(?:\\\\.|(?!\\2)[^\\\\\\r\\n])*\\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\\{\\{)*)\\{(?!\\{)(?:[^{}]|\\{(?!\\{)(?:[^{}]|\\{(?!\\{)(?:[^{}])+\\})+\\})+\\}/,lookbehind:!0,inside:{\"format-spec\":{pattern:/(:)[^:(){}]+(?=\\}$)/,lookbehind:!0},\"conversion-option\":{pattern:/![sra](?=[:}]$)/,alias:\"punctuation\"},rest:null}},string:/[\\s\\S]+/}},\"triple-quoted-string\":{pattern:/(?:[rub]|br|rb)?(\"\"\"|''')[\\s\\S]*?\\1/i,greedy:!0,alias:\"string\"},string:{pattern:/(?:[rub]|br|rb)?(\"|')(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/i,greedy:!0},function:{pattern:/((?:^|\\s)def[ \\t]+)[a-zA-Z_]\\w*(?=\\s*\\()/g,lookbehind:!0},\"class-name\":{pattern:/(\\bclass\\s+)\\w+/i,lookbehind:!0},decorator:{pattern:/(^[\\t ]*)@\\w+(?:\\.\\w+)*/m,lookbehind:!0,alias:[\"annotation\",\"punctuation\"],inside:{punctuation:/\\./}},keyword:/\\b(?:_(?=\\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\\b/,builtin:/\\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\\b/,boolean:/\\b(?:False|None|True)\\b/,number:/\\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\\b|(?:\\b\\d+(?:_\\d+)*(?:\\.(?:\\d+(?:_\\d+)*)?)?|\\B\\.\\d+(?:_\\d+)*)(?:e[+-]?\\d+(?:_\\d+)*)?j?(?!\\w)/i,operator:/[-+%=]=?|!=|:=|\\*\\*?=?|\\/\\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\\];(),.:]/},Prism.languages.python[\"string-interpolation\"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python;\n"
  },
  {
    "path": "website/theme/static/style.css",
    "content": ":root {\n  --primary-h: 217;\n  --primary-s: 100%;\n  --primary-l: 19%;\n\n  --text-h: 0;\n  --text-s: 0%;\n\n  --color-primary: hsl(var(--primary-h), var(--primary-s), var(--primary-l));\n  --link-color: hsl(var(--primary-h), 100%, 35%);\n  --font-family: 'Lato', -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n  --text-color: hsl(var(--text-h), var(--text-s), 2%);\n\n  --nav-link-hover-color: #e9ecef\n}\n\n/* start css reset */\n\n*,\n*::before,\n*::after {\n  box-sizing: border-box;\n}\n\n* {\n  margin: 0;\n}\n\ninput,\nbutton,\ntextarea,\nselect {\n  font: inherit;\n}\n/* end css reset */\n\nbody {\n  font-family: var(--font-family);\n  background-color: white;\n}\n\nh1,\nh2,\nh3 {\n  line-height: 1.2;\n}\n\ncode {\n  background-color: #f5f5f5;\n  padding: 0.058rem 0.25rem;\n  border-radius: 4px;\n  color: #c7254e;\n  font-size: 0.92em;\n}\n\npre {\n  background-color: #f5f5f5;\n  padding: 0.9rem;\n  border-radius: 6px;\n  overflow-x: auto;\n  margin: 1.5rem 0;\n  border: 1px solid #ddd;\n  line-height: 1.1;\n}\n\npre code {\n  padding: 0;\n  color: var(--text-color);\n  font-size: 0.85rem;\n}\n\n@media only screen and (max-width: 25em) {\n  .profile {\n    max-width: 100%;\n  }\n}\n\n@media print {\n  body {\n    max-width: none;\n  }\n}\n\n.page {\n  font-family: var(--font-family);\n  background-color: white;\n  color: var(--text-color);\n  line-height: 1.6;\n}\n\n.page__container {\n  min-height: 100vh;\n  display: flex;\n  flex-direction: column;\n}\n\n.header {\n  background-color: #f8f9fa;\n  padding: 0.5rem 0;\n  color: var(--text-color);\n  border-bottom: 1px solid #dee2e6;\n}\n\n.header__container {\n  max-width: 1200px;\n  margin: 0 auto;\n  padding: 0 1rem;\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  flex-wrap: wrap;\n  gap: 1rem;\n}\n\n.header__brand {\n  flex-shrink: 0;\n}\n\n.brand__link {\n  display: flex;\n  align-items: center;\n  gap: 0.3rem;\n  text-decoration: none;\n  color: inherit;\n  padding: 0rem 0.4rem;\n  border-radius: 4px;\n  transition: color 0.05s ease;\n}\n\n.brand__link:hover {\n  background-color: var(--nav-link-hover-color);\n  border-radius: 4px;\n}\n\n.brand__logo {\n  flex-shrink: 0;\n}\n\n.brand__image {\n  width: 80px;\n  height: 80px;\n  display: block;\n}\n\n.brand__text {\n  display: flex;\n  flex-direction: column;\n}\n\n.brand__title {\n  font-size: 1.5rem;\n  font-weight: 600;\n  line-height: 1.2;\n  color: var(--color-primary);\n}\n\n.brand__subtitle {\n  font-size: 1rem;\n  font-weight: 400;\n  color: hsl(var(--primary-h), 0%, 35%);\n}\n\n.nav__list {\n  display: flex;\n  list-style: none;\n  margin: 0;\n  padding: 0;\n}\n\n.nav__link {\n  color: var(--link-color);\n  text-decoration: none;\n  font-weight: 600;\n  font-size: 1.15rem;\n  padding: 0.75rem 1rem;\n  border-radius: 4px;\n}\n\n.nav__link:hover {\n  color: hsl(var(--primary-h), var(--primary-s), 20%);\n  background-color: var(--nav-link-hover-color);\n  border-radius: 4px;\n}\n\n.main {\n  flex: 1;\n  padding: 3rem 0;\n}\n\n.main__container {\n  max-width: 1200px;\n  margin: 0 auto;\n  padding: 0 1rem;\n}\n\n.home-page {\n  max-width: 850px;\n  margin: 0 auto;\n}\n\n.main-page__header {\n  text-align: center;\n  margin-bottom: 3rem;\n}\n\n.main-page__header-text {\n  font-size: 4.5rem;\n  color: var(--color-primary);\n  line-height: 1.1;\n  margin: 0;\n}\n\n.newsletter-box {\n  background-color: #f8f9fa;\n  border: 1px solid #dee2e6;\n  border-radius: 8px;\n  padding: 2rem;\n  margin-top: 2rem;\n}\n\n.newsletter-box h2 {\n  margin-top: 0;\n  margin-bottom: 1rem;\n  color: var(--color-primary);\n}\n\n.newsletter-box p {\n  margin-bottom: 1.5rem;\n}\n\n.newsletter-form__content {\n  display: flex;\n  gap: 1rem;\n  flex-wrap: wrap;\n}\n\n.newsletter-form__input {\n  padding-left: 1rem;\n  padding-right: 1rem;\n  border: 1px solid #ddd;\n  border-radius: 6px;\n  font-size: 1rem;\n  flex: 1;\n  min-width: 250px;\n  max-width: 350px;\n}\n\n.newsletter-form__input:focus {\n  outline: none;\n  border-color: var(--color-primary);\n  box-shadow: 0 0 0 2px hsl(var(--primary-h), var(--primary-s), var(--primary-l), 0.1);\n}\n\n.newsletter-form__button {\n  padding: 0.75rem 1.5rem;\n  background-color: var(--color-primary);\n  color: white;\n  border: none;\n  border-radius: 4px;\n  font-size: 1rem;\n  font-weight: 500;\n  cursor: pointer;\n  transition: background-color 0.2s ease;\n}\n\n.newsletter-form__button:hover {\n  background-color: hsl(var(--primary-h), var(--primary-s), 10%);\n}\n\n.articles-page {\n  max-width: 1000px;\n  margin: 0 auto;\n}\n\n.articles-page__header {\n  text-align: center;\n  margin-bottom: 2rem;\n}\n\n.articles-page__title {\n  font-size: 2.5rem;\n  font-weight: 600;\n  color: var(--color-primary);\n  margin-bottom: 0.5rem;\n}\n\n.articles-page__subtitle {\n  font-size: 1.125rem;\n  color: #6c757d;\n  line-height: 1.5;\n}\n\n.articles-grid {\n  display: flex;\n  flex-direction: column;\n  gap: 2rem;\n}\n\n.articles__list {\n  display: flex;\n  flex-direction: column;\n  gap: 2rem;\n}\n\n.article-card {\n  background-color: white;\n  border-radius: 8px;\n  border: 1px solid #ddd;\n  padding-top: 2rem;\n  padding-left: 2rem;\n  padding-right: 2rem;\n  padding-bottom: 1rem;\n  transition: transform 0.05s ease, box-shadow 0.05s ease;\n  cursor: pointer;\n  box-shadow: 0 1.5px 4.5px rgba(0, 0, 0, 0.1);\n}\n\n.article-card:hover {\n  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n}\n\n.article-card__header {\n  margin-bottom: 0.75rem;\n}\n\n.article-card__title {\n  font-size: 1.5rem;\n  font-weight: 600;\n  line-height: 1.3;\n  color: var(--color-primary);\n}\n\n\n.article-card__content ul,\n.article-card__content ol {\n  margin-bottom: 1rem;\n  padding-left: 2rem;\n}\n\n.article-card__content li {\n  margin-bottom: 0.25rem;\n}\n\n.article-card__content a {\n  color: var(--link-color);\n  text-decoration: none;\n}\n\n\n.article-card__content p {\n  margin-bottom: 1rem;\n}\n\n.article-card__content a:hover {\n  text-decoration: underline;\n}\n\n.article-card-meta {\n  display: flex;\n  gap: 0.5rem;\n  flex-wrap: wrap;\n  align-items: center;\n  margin-bottom: 0.75rem;\n}\n\n.article-card-meta__separator {\n  font-size: 0.75rem;\n  color: var(--color-primary);\n}\n\n.article-card-meta__item {\n  display: flex;\n  gap: 0.25rem;\n  align-items: center;\n}\n\n.article-card-meta__value {\n  font-size: 1rem;\n  color: var(--color-primary);\n}\n\n.article-card-meta__value a {\n  color: inherit;\n  text-decoration: none;\n}\n\n.article-card-meta__value a:hover {\n  text-decoration: underline;\n}\n\n.article-page {\n  max-width: 850px;\n  margin: 0 auto;\n}\n\n.article__header {\n  margin-bottom: 2rem;\n  padding-bottom: 2rem;\n  border-bottom: 2px solid #e2e2e2;\n}\n\n.article__title {\n  font-size: 2.5rem;\n  font-weight: 600;\n  line-height: 1.2;\n  margin-bottom: 1.5rem;\n  color: var(--color-primary);\n}\n\n.article-meta {\n  display: flex;\n  gap: 0.5rem;\n  flex-wrap: wrap;\n  align-items: center;\n}\n\n.article-meta__separator {\n  font-size: 0.75rem;\n  color: var(--color-primary);\n}\n\n.article-meta__item {\n  display: flex;\n  gap: 0.25rem;\n  align-items: center;\n}\n\n.article-meta__value {\n  font-size: 1.2rem;\n  color: var(--color-primary);\n}\n\n.article-meta__value a {\n  color: inherit;\n  text-decoration: none;\n}\n\n.article-meta__value a:hover {\n  text-decoration: underline;\n}\n\n.article-content {\n  line-height: 1.6;\n  font-size: 1.125rem;\n  color: var(--text-color);\n}\n\n.article-content h1,\n.article-content h2,\n.article-content h3,\n.article-content h4,\n.article-content h5,\n.article-content h6 {\n  margin-top: 2rem;\n  margin-bottom: 1rem;\n  line-height: 1.3;\n  color: var(--color-primary);\n}\n\n.article-content h1 {\n  font-size: 2rem;\n}\n\n.article-content h2 {\n  font-size: 1.5rem;\n}\n\n.article-content h3 {\n  font-size: 1.25rem;\n}\n\n.article-content p {\n  margin-bottom: 1rem;\n}\n\n.article-content ul,\n.article-content ol {\n  margin-bottom: 1rem;\n  padding-left: 2rem;\n}\n\n.article-content li {\n  margin-bottom: 0.25rem;\n}\n\n.article-content a {\n  color: var(--link-color);\n  text-decoration: none;\n}\n\n.article-content a:hover {\n  text-decoration: underline;\n}\n\n.article-content hr {\n  margin-top: 1.5rem;\n  margin-bottom: 1.5rem;\n  border: 1px solid #e2e2e2;\n}\n\n.cta-buttons {\n  display: flex;\n  gap: 1.5rem;\n  justify-content: center;\n  align-items: center;\n  margin: 2rem 0;\n}\n\n.cta-button {\n  display: inline-flex;\n  align-items: center;\n  gap: 0.75rem;\n  padding: 0.8rem 1.2rem;\n  background-color: hsl(var(--primary-h), 80%, 56%);\n  color: white !important;\n  text-decoration: none !important;\n  font-weight: 600;\n  font-size: 1.1rem;\n  border: none;\n  border-radius: 6px;\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n  text-align: center;\n  cursor: pointer;\n}\n\n.cta-icon {\n  width: 1.2rem;\n  height: 1.2rem;\n  filter: brightness(0) invert(1);\n}\n\n.cta-button:hover {\n  background-color: hsl(var(--primary-h), 80%, 51%);\n  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);\n}\n\n.footnote {\n  padding-top: 1.25rem;\n}\n\n.static-page {\n  max-width: 850px;\n  margin: 0 auto;\n}\n\n.page-content__header {\n  margin-bottom: 2rem;\n  padding-bottom: 2rem;\n  border-bottom: 1px solid #eee;\n}\n\n.page-content__title {\n  font-size: 2.5rem;\n  font-weight: 600;\n  line-height: 1.2;\n  color: var(--color-primary);\n}\n\n.page-body {\n  line-height: 1.7;\n  color: var(--text-color);\n}\n\n.page-body h1,\n.page-body h2,\n.page-body h3,\n.page-body h4,\n.page-body h5,\n.page-body h6 {\n  margin-top: 2rem;\n  margin-bottom: 1rem;\n  line-height: 1.3;\n  color: var(--color-primary);\n}\n\n.page-body h1 {\n  font-size: 2rem;\n}\n\n.page-body h2 {\n  font-size: 1.5rem;\n}\n\n.page-body h3 {\n  font-size: 1.25rem;\n}\n\n.page-body p {\n  margin-bottom: 1rem;\n}\n\n.page-body ul,\n.page-body ol {\n  margin-bottom: 1rem;\n  padding-left: 2rem;\n}\n\n.page-body li {\n  margin-bottom: 0.25rem;\n}\n\n.page-body a {\n  color: var(--link-color);\n  text-decoration: none;\n}\n\n.page-body a:hover {\n  text-decoration: underline;\n}\n\n.footer {\n  background-color: #f8f8f8;\n  border-top: 1px solid #ddd;\n  margin-top: auto;\n}\n\n.footer__container {\n  max-width: 1200px;\n  margin: 0 auto;\n  padding: 1rem;\n}\n\n.footer__content {\n  text-align: center;\n}\n\n.footer__text {\n  color: #666;\n  font-size: 0.875rem;\n}\n\n.separator {\n  border-bottom: 2px solid #cccccc;\n}\n\n@media (max-width: 768px) {\n  .header__container {\n    flex-direction: column;\n    text-align: center;\n  }\n\n  .nav__list {\n    flex-wrap: wrap;\n    justify-content: center;\n  }\n\n  .brand__link {\n    flex-direction: column;\n    text-align: center;\n  }\n\n  .article__title {\n    font-size: 2rem;\n  }\n\n  .article-card-meta,\n  .article-meta {\n    flex-direction: column;\n    gap: 0.5rem;\n  }\n\n  .newsletter-form__content {\n    flex-direction: column;\n    align-items: center;\n  }\n\n  .newsletter-form__input {\n    max-width: 100%;\n  }\n\n  .articles__title {\n    font-size: 1.75rem;\n  }\n\n  .cta-buttons {\n    flex-direction: column;\n    gap: 1rem;\n  }\n}\n"
  },
  {
    "path": "website/theme/templates/article-card.html",
    "content": "<div class=\"article-card\" data-url=\"{{ SITEURL }}/{{ article.url }}\"\n     title=\"Read {{ article.title|striptags }}\">\n\n  <div class=\"article-card__header\">\n    <div class=\"article-card__title\">\n      {{ article.title }}\n    </div>\n  </div>\n\n  <div class=\"article-card-meta\">\n    <div class=\"article-card-meta__item\">\n      <span class=\"article-card-meta__value\" title=\"{{ article.date.isoformat() }}\">\n        {{ article.date.strftime('%B %d, %Y') }}\n      </span>\n    </div>\n\n    {% if article.authors or article.author %}\n    <span class=\"article-card-meta__separator\">•</span>\n    <div class=\"article-card-meta__item\">\n      <span class=\"article-card-meta__value\">\n        {% if article.authors %}\n          {% for author in article.authors %}\n            {% set author_name = AUTHOR_NAMES.get(author|string|trim, author|string|trim) %}\n            {% set author_url = AUTHOR_URLS.get(author|string|trim) %}\n            {% if author_url %}<a href=\"{{ author_url }}\">{{ author_name }}</a>{% else %}{{ author_name }}{% endif %}{% if not loop.last %}{% if loop.revindex == 2 %}{% if loop.length > 2 %}, and {% else %} and {% endif %}{% else %}, {% endif %}{% endif %}\n          {% endfor %}\n        {% else %}\n          {% set author_name = AUTHOR_NAMES.get(article.author, article.author) %}\n          {% set author_url = AUTHOR_URLS.get(article.author) %}\n          {% if author_url %}\n          <a href=\"{{ author_url }}\">{{ author_name }}</a>\n          {% else %}\n          {{ author_name }}\n          {% endif %}\n        {% endif %}\n      </span>\n    </div>\n    {% endif %}\n  </div>\n\n  <div class=\"article-card__content\">\n    {{ article.summary }}\n  </div>\n\n</div>\n"
  },
  {
    "path": "website/theme/templates/article.html",
    "content": "{% extends \"base.html\" %}\n\n{% block content %}\n\n<div class=\"article-page\">\n\n  <div class=\"article\">\n    <div class=\"article__header\">\n      <div class=\"article__title\">{{ article.title }}</div>\n\n      <div class=\"article__meta\">\n        <div class=\"article-meta\">\n\n          <div class=\"article-meta__item\">\n            <span class=\"article-meta__value\" title=\"{{ article.date.isoformat() }}\">\n              {{ article.date.strftime('%B %d, %Y') }}\n            </span>\n          </div>\n\n          {% if article.authors or article.author %}\n          <span class=\"article-meta__separator\">•</span>\n          <div class=\"article-meta__item\">\n            <span class=\"article-meta__value\">\n              {% if article.authors %}\n                {% for author in article.authors %}\n                  {% set author_name = AUTHOR_NAMES.get(author|string|trim, author|string|trim) %}\n                  {% set author_url = AUTHOR_URLS.get(author|string|trim) %}\n                  {% if author_url %}<a href=\"{{ author_url }}\">{{ author_name }}</a>{% else %}{{ author_name }}{% endif %}{% if not loop.last %}{% if loop.revindex == 2 %}{% if loop.length > 2 %}, and {% else %} and {% endif %}{% else %}, {% endif %}{% endif %}\n                {% endfor %}\n              {% else %}\n                {% set author_name = AUTHOR_NAMES.get(article.author, article.author) %}\n                {% set author_url = AUTHOR_URLS.get(article.author) %}\n                {% if author_url %}\n                <a href=\"{{ author_url }}\">{{ author_name }}</a>\n                {% else %}\n                {{ author_name }}\n                {% endif %}\n              {% endif %}\n            </span>\n          </div>\n          {% endif %}\n        </div>\n      </div>\n    </div>\n\n    <div class=\"article-content\">\n      {{ article.content }}\n    </div>\n  </div>\n\n</div>\n\n{% endblock %}\n"
  },
  {
    "path": "website/theme/templates/base.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <title>{% block title %}{{ SITENAME }}{% endblock title %}</title>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\n  <link href=\"https://fonts.googleapis.com/css2?family=Lato:wght@300;400;500;600;700&display=swap\" rel=\"stylesheet\">\n  <link rel=\"stylesheet\" type=\"text/css\" href=\"{{ SITEURL }}/theme/style.css\"/>\n  <link rel=\"stylesheet\" type=\"text/css\" href=\"{{ SITEURL }}/theme/prism.css\"/>\n\n  {% if FEED_ATOM %}\n    <link href=\"/{{ FEED_ATOM }}\" type=\"application/atom+xml\" rel=\"alternate\" title=\"{{ SITENAME }} Atom Feed\" />\n  {% endif %}\n  {% if FEED_RSS %}\n    <link href=\"/{{ FEED_RSS }}\" type=\"application/rss+xml\" rel=\"alternate\" title=\"{{ SITENAME }} RSS Feed\" />\n  {% endif %}\n\n  {% block head %}\n  {% endblock head %}\n</head>\n\n<body class=\"page\">\n  <div class=\"page__container\">\n\n    <div class=\"header\">\n      <div class=\"header__container\">\n\n        <div class=\"header__brand\">\n          <div class=\"brand\">\n            <a href=\"{{ SITEURL }}/\" class=\"brand__link\">\n              <div class=\"brand__logo\">\n                <img src=\"{{ PROFILE_IMAGE_URL }}\" alt=\"{{ SITENAME }} Logo\" class=\"brand__image\">\n              </div>\n              <div class=\"brand__text\">\n                <div class=\"brand__title\">{{ SITENAME }}</div>\n                <div class=\"brand__subtitle\">{{ SITESUBTITLE }}</div>\n              </div>\n            </a>\n          </div>\n        </div>\n\n        <nav class=\"nav\">\n          <ul class=\"nav__list\">\n            {% for title, link in MENUITEMS %}\n              <li class=\"nav__item\">\n                <a href=\"{{ link }}\" class=\"nav__link\">{{ title }}</a>\n              </li>\n            {% endfor %}\n            {% if DISPLAY_PAGES_ON_MENU %}\n              {% for p in PAGES %}\n                <li class=\"nav__item{% if p == page %} nav__item--active{% endif %}\">\n                  <a href=\"{{ SITEURL }}/{{ p.url }}\" class=\"nav__link\">{{ p.title }}</a>\n                </li>\n              {% endfor %}\n            {% endif %}\n          </ul>\n        </nav>\n\n      </div>\n    </div>\n\n    <div class=\"main\">\n      <div class=\"main__container\">\n        {% block content %}\n        {% endblock %}\n      </div>\n    </div>\n\n    <div class=\"footer\">\n      <div class=\"footer__container\">\n        <div class=\"footer__content\">\n          <span class=\"footer__text\"></span>\n        </div>\n      </div>\n    </div>\n\n  </div>\n\n  <script>\n    // Make article cards clickable\n    document.addEventListener('DOMContentLoaded', function() {\n      const articleCards = document.querySelectorAll('.article-card[data-url]');\n\n      articleCards.forEach(function(card) {\n        card.style.cursor = 'pointer';\n\n        card.addEventListener('click', function(event) {\n          const url = this.getAttribute('data-url');\n          if (event.metaKey) {\n            window.open(url, '_blank');\n          } else {\n            window.location.href = url;\n          }\n        });\n      });\n    });\n  </script>\n\n  <script src=\"{{ SITEURL }}/theme/prism.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "website/theme/templates/category.html",
    "content": "{% extends \"base.html\" %}\n\n{% block content %}\n\n<div class=\"articles-page\">\n  <div class=\"articles-page__header\">\n    <div class=\"articles-page__title\">{{ category.name|capitalize }}</div>\n  </div>\n\n  <div class=\"articles-grid\">\n    {% for article in articles %}\n    {% include \"article-card.html\" %}\n    {% endfor %}\n  </div>\n</div>\n\n{% endblock content %}\n"
  },
  {
    "path": "website/theme/templates/index.html",
    "content": "{% extends \"base.html\" %}\n\n{% block content %}\n\n<div class=\"home-page\">\n\n  <div class=\"article-content\">\n    <div class=\"main-page__header\">\n      <div class=\"main-page__header-text\">\n        Hypothesis\n      </div>\n    </div>\n\n      <p>Hypothesis is the property-based testing library for Python. With Hypothesis, you write tests which should pass for all inputs in whatever range you describe, and let Hypothesis randomly choose which of those inputs to check - including edge cases you might not have thought about. For example:</p>\n\n    <div class=\"article__code\">\n      <pre><code class=\"language-python\">from hypothesis import given, strategies as st\n\n@given(st.lists(st.integers()))\ndef test_matches_builtin(ls):\n  assert sorted(ls) == my_sort(ls)</code></pre>\n    </div>\n\n      <p>This randomized testing can catch bugs and edge cases that you didn't think of and wouldn't have found. In addition, when Hypothesis does find a bug, it doesn't just report any failing example — it reports the simplest possible one. This makes property-based tests a powerful tool for debugging, as well as testing.</p>\n\n      <h2>Recent Articles</h2>\n      <div class=\"articles-grid\">\n        {% for article in articles[:3] %}\n        {% include \"article-card.html\" %}\n        {% endfor %}\n      </div>\n      <p style=\"margin: 3rem 0;\">\n        <a href=\"/articles/\">More articles from the Hypothesis blog →</a>\n      </p>\n\n      <div class=\"separator\" style=\"margin-top: 3rem; margin-bottom: 3rem;\"></div>\n\n      <div class=\"newsletter-box\">\n        <h2 style=\"margin-top: 0rem;\">Hypothesis Quarterly</h2>\n        <p>Every three months, we send out a roundup newsletter of what's new in Hypothesis and the Hypothesis ecosystem!</p>\n\n        <form action=\"https://works.us16.list-manage.com/subscribe/post?u=96a2ac0812802282504dd335f&id=76e6edcda3\" method=\"post\" id=\"mc-embedded-subscribe-form\" name=\"mc-embedded-subscribe-form\" target=\"_blank\" class=\"newsletter-form\">\n          <div id=\"mc_embed_signup_scroll\">\n            <div class=\"newsletter-form__content\">\n              <input type=\"email\" placeholder=\"me@example.com\" value=\"\" name=\"EMAIL\" id=\"mce-EMAIL\" required class=\"newsletter-form__input\"/>\n              <button type=\"submit\" name=\"subscribe\" id=\"mc-embedded-subscribe\" class=\"cta-button\" style=\"height: 3rem;\">Subscribe</button>\n            </div>\n            <div id=\"mce-responses\" class=\"clear\">\n              <div class=\"response\" id=\"mce-error-response\" style=\"display:none\"></div>\n              <div class=\"response\" id=\"mce-success-response\" style=\"display:none\"></div>\n            </div>\n          </div>\n        </form>\n      </div>\n    </div>\n  </div>\n</div>\n\n{% endblock content %}\n"
  },
  {
    "path": "website/theme/templates/page.html",
    "content": "{% extends \"base.html\" %}\n\n{% block content %}\n\n<div class=\"static-page\">\n  <div class=\"page-content\">\n    <div class=\"page-content__header\">\n      <div class=\"page-content__title\">{{ page.title }}</div>\n    </div>\n\n    <div class=\"page-content__body\">\n      <div class=\"page-body\">\n    {{ page.content }}\n      </div>\n    </div>\n  </div>\n</div>\n{% endblock %}\n"
  },
  {
    "path": "whole_repo_tests/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "whole_repo_tests/documentation/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "whole_repo_tests/documentation/test_documentation.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport importlib\nimport posixpath\nfrom pathlib import Path\n\nfrom sphinx.util.inventory import InventoryFile\n\nimport hypothesis.provisional\nfrom hypothesis.strategies import __all__ as STRATEGY_EXPORTS\nfrom hypothesistooling.__main__ import documentation\nfrom hypothesistooling.projects import hypothesispython as hp\n\n\ndef test_documentation():\n    documentation()\n\n\ndef get_all_exported_names():\n    # start with hypothesis.strategies\n    exports = {f\"hypothesis.strategies.{name}\" for name in STRATEGY_EXPORTS}\n    # add any strategy exported by hypothesis.provisional\n    exports |= {\n        f\"hypothesis.provisional.{name}\"\n        for name, value in vars(hypothesis.provisional).items()\n        if getattr(value, \"is_hypothesis_strategy_function\", False)\n        and not name.startswith(\"_\")\n    }\n\n    # add anything exported from an extra\n    for p in (hp.PYTHON_SRC / \"hypothesis\" / \"extra\").iterdir():\n        # ignore private files/dirs. Also skip django, which requires setting up\n        # a django app to import:\n        #   django.core.exceptions.ImproperlyConfigured: Requested setting\n        #   INSTALLED_APPS, but settings are not configured. You must either define\n        #   the environment variable DJANGO_SETTINGS_MODULE or call settings.configure()\n        #   before accessing settings.\n        if p.name.startswith(\"_\") or p.name == \"django\":\n            continue\n\n        module_name = f\"hypothesis.extra.{p.stem}\"\n        try:\n            module = importlib.import_module(module_name)\n        except ImportError:\n            continue\n\n        if hasattr(module, \"__all__\"):\n            exports |= {f\"{module_name}.{name}\" for name in module.__all__}\n\n    return exports\n\n\ndef test_documents_all_exported_strategies():\n    # concurrent docs builds to the same output directory does bad things to\n    # sphinx. Build to a test-specific directory, so we don't overlap builds with\n    # any other test that is also building docs.\n    out_dir = \"documents_all_exported_strategies\"\n    hp.build_docs(to=out_dir)\n    undocumented = get_all_exported_names() - {\n        \"hypothesis.extra.numpy.BroadcastableShapes\",\n    }\n\n    # `inventory` looks like:\n    #   {\n    #       \"py:class\": {\n    #           \"hypothesis.HealthCheck\": (\n    #               \"Hypothesis\",\n    #               \"6.129.4\",\n    #               \"reference/api.html#hypothesis.HealthCheck\",\n    #               \"-\",\n    #           ),\n    #           ...\n    #       },\n    #       ...\n    #   }\n    inventory_path = (\n        Path(hp.HYPOTHESIS_PYTHON) / \"docs\" / \"_build\" / out_dir / \"objects.inv\"\n    )\n    with open(inventory_path, \"rb\") as f:\n        inventory = InventoryFile.load(f, \"\", posixpath.join)\n\n    for items in inventory.values():\n        undocumented -= set(items.keys())\n    assert not undocumented, f\"undocumented strategies: {sorted(undocumented)}\"\n"
  },
  {
    "path": "whole_repo_tests/types/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "whole_repo_tests/types/revealed_types.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\nfrom typing import NamedTuple\n\nfrom hypothesistooling.__main__ import PYTHONS as pythons_map\n\nPYTHON_VERSIONS = [v for v in pythons_map if re.fullmatch(r\"3\\.\\d\\d?\", v)]\n\ntry:\n    from numpy import __version__ as np_version\nexcept ImportError:\n    NP1 = False\nelse:\n    NP1 = np_version.startswith(\"1.\")\n\nASSUME_REVEALED_TYPES = [\n    (\"assume(False)\", \"Never\"),\n    (\"assume(None)\", \"Never\"),\n    (\"assume(True)\", \"Literal[True]\"),\n    (\"assume(1)\", \"Literal[True]\"),\n]\n\nREVEALED_TYPES = [\n    (\"integers()\", \"int\"),\n    (\"text()\", \"str\"),\n    (\"integers().map(str)\", \"str\"),\n    (\"booleans().filter(bool)\", \"bool\"),\n    (\"tuples()\", \"tuple[()]\"),\n    (\"tuples(integers())\", \"tuple[int]\"),\n    (\"tuples(integers(), text())\", \"tuple[int, str]\"),\n    (\n        \"tuples(integers(), text(), integers(), text(), integers())\",\n        \"tuple[int, str, int, str, int]\",\n    ),\n    (\n        \"tuples(text(), text(), text(), text(), text(), text())\",\n        \"tuple[Any, ...]\",\n    ),\n    (\"lists(none())\", \"list[None]\"),\n    (\"integers().filter(lambda x: x > 0)\", \"int\"),\n    (\"booleans().filter(lambda x: x)\", \"bool\"),\n    (\"integers().map(bool).filter(lambda x: x)\", \"bool\"),\n    (\"integers().flatmap(lambda x: lists(floats()))\", \"list[float]\"),\n    (\"one_of([integers(), integers()])\", \"int\"),\n    (\"one_of([integers(), floats()])\", \"float\"),\n    (\"one_of([integers(), none()])\", \"int | None\"),\n    (\"one_of(integers(), none())\", \"int | None\"),\n    (\"one_of(integers(), text())\", \"int | str\"),\n    (\"recursive(integers(), lists)\", \"list[Any] | int\"),\n    # We have overloads for up to five types, then fall back to Any.\n    # (why five?  JSON atoms are None|bool|int|float|str and we do that a lot)\n    (\n        \"one_of(integers(), text(), none(), binary(), builds(list), builds(dict))\",\n        \"Any\",\n    ),\n]\n\n\nclass DifferingRevealedTypes(NamedTuple):\n    value: str\n    mypy: str\n    pyright: str\n\n\nDIFF_REVEALED_TYPES = [\n    DifferingRevealedTypes(\"none() | integers()\", \"None | int\", \"int | None\"),\n    DifferingRevealedTypes(\n        \"data()\", \"hypothesis.strategies._internal.core.DataObject\", \"DataObject\"\n    ),\n    # We have overloads for up to five types, then fall back to Any.\n    # (why five?  JSON atoms are None|bool|int|float|str and we do that a lot)\n    DifferingRevealedTypes(\n        \"one_of(integers(), text(), none(), binary(), builds(list))\",\n        \"int | str | None | bytes | list[Never]\",\n        \"int | str | bytes | list[Unknown] | None\",\n    ),\n    DifferingRevealedTypes(\n        \"dictionaries(integers(), datetimes())\",\n        \"dict[int, datetime.datetime]\",\n        \"dict[int, datetime]\",\n    ),\n]\n\n\nNUMPY_REVEALED_TYPES = [\n    (\n        'arrays(dtype=np.dtype(\"int32\"), shape=1)',\n        \"ndarray[tuple[Any, ...], dtype[signedinteger[_32Bit]]]\",\n    ),\n    # (\n    #     \"arrays(dtype=np.dtype(int), shape=1)\",\n    #     \"ndarray[tuple[int, ...], dtype[Union[signedinteger[Union[_32Bit, _64Bit]], bool[bool]]]]\",\n    #     # FIXME: `dtype[signedinteger[_32Bit | _64Bit] | bool[bool]]]]` on mypy now\n    # ),\n    (\n        \"boolean_dtypes()\",\n        \"dtype[bool[bool]]\",  # np.bool[builtins.bool]\n    ),\n    (\n        \"unsigned_integer_dtypes(sizes=8)\",\n        \"dtype[unsignedinteger[_8Bit]]\",\n    ),\n    (\n        \"unsigned_integer_dtypes(sizes=16)\",\n        \"dtype[unsignedinteger[_16Bit]]\",\n    ),\n    (\n        \"unsigned_integer_dtypes(sizes=32)\",\n        \"dtype[unsignedinteger[_32Bit]]\",\n    ),\n    (\n        \"unsigned_integer_dtypes(sizes=64)\",\n        \"dtype[unsignedinteger[_64Bit]]\",\n    ),\n    (\n        \"unsigned_integer_dtypes()\",\n        \"dtype[unsignedinteger[Any]]\",\n    ),\n    (\n        \"unsigned_integer_dtypes(sizes=(8, 16))\",\n        \"dtype[unsignedinteger[Any]]\",\n    ),\n    (\n        \"integer_dtypes(sizes=8)\",\n        \"dtype[signedinteger[_8Bit]]\",\n    ),\n    (\n        \"integer_dtypes(sizes=16)\",\n        \"dtype[signedinteger[_16Bit]]\",\n    ),\n    (\n        \"integer_dtypes(sizes=32)\",\n        \"dtype[signedinteger[_32Bit]]\",\n    ),\n    (\n        \"integer_dtypes(sizes=64)\",\n        \"dtype[signedinteger[_64Bit]]\",\n    ),\n    (\n        \"integer_dtypes()\",\n        \"dtype[signedinteger[Any]]\",\n    ),\n    (\n        \"integer_dtypes(sizes=(8, 16))\",\n        \"dtype[signedinteger[Any]]\",\n    ),\n    (\n        \"floating_dtypes(sizes=16)\",\n        \"dtype[floating[_16Bit]]\",\n    ),\n    (\n        \"floating_dtypes(sizes=32)\",\n        \"dtype[floating[_32Bit]]\",\n    ),\n    (\n        \"floating_dtypes(sizes=64)\",\n        \"dtype[float64]\",\n    ),\n    (\n        \"floating_dtypes(sizes=128)\",\n        \"dtype[floating[_128Bit]]\",\n    ),\n    (\n        \"floating_dtypes()\",\n        \"dtype[floating[Any]]\",\n    ),\n    (\n        \"floating_dtypes(sizes=(16, 32))\",\n        \"dtype[floating[Any]]\",\n    ),\n    (\n        \"complex_number_dtypes(sizes=64)\",\n        \"dtype[complexfloating[_32Bit, _32Bit]]\",\n    ),\n    (\n        \"complex_number_dtypes(sizes=128)\",\n        \"dtype[complex128]\",\n    ),\n    (\n        \"complex_number_dtypes(sizes=256)\",\n        \"dtype[complexfloating[_128Bit, _128Bit]]\",\n    ),\n    (\n        \"complex_number_dtypes()\",\n        \"dtype[complexfloating[Any, Any]]\",\n    ),\n    (\n        \"complex_number_dtypes(sizes=(64, 128))\",\n        \"dtype[complexfloating[Any, Any]]\",\n    ),\n    (\n        \"integer_array_indices(shape=(2, 3))\",\n        \"tuple[ndarray[tuple[Any, ...], dtype[signedinteger[Any]]], ...]\",\n    ),\n    (\n        'integer_array_indices(shape=(2, 3), dtype=np.dtype(\"int32\"))',\n        \"tuple[ndarray[tuple[Any, ...], dtype[signedinteger[_32Bit]]], ...]\",\n    ),\n    (\n        'integer_array_indices(shape=(2, 3), dtype=np.dtype(\"uint8\"))',\n        \"tuple[ndarray[tuple[Any, ...], dtype[unsignedinteger[_8Bit]]], ...]\",\n    ),\n    # basic_indices with allow_ellipsis=False (no EllipsisType differences)\n    (\n        \"basic_indices((3, 4), allow_ellipsis=False)\",\n        \"int | slice[Any, Any, Any] | tuple[int | slice[Any, Any, Any], ...]\",\n    ),\n]\n\n# basic_indices tests where mypy/pyright differ in EllipsisType representation\nNUMPY_DIFF_REVEALED_TYPES = [\n    # mypy uses types.EllipsisType, pyright uses EllipsisType\n    DifferingRevealedTypes(\n        \"basic_indices((3, 4))\",\n        \"int | slice[Any, Any, Any] | types.EllipsisType | tuple[int | slice[Any, Any, Any] | types.EllipsisType, ...]\",\n        \"int | slice[Any, Any, Any] | EllipsisType | tuple[int | slice[Any, Any, Any] | EllipsisType, ...]\",\n    ),\n    # pyright also reorders None to the end\n    DifferingRevealedTypes(\n        \"basic_indices((3, 4), allow_newaxis=True, allow_ellipsis=False)\",\n        \"int | slice[Any, Any, Any] | None | tuple[int | slice[Any, Any, Any] | None, ...]\",\n        \"int | slice[Any, Any, Any] | tuple[int | slice[Any, Any, Any] | None, ...] | None\",\n    ),\n    DifferingRevealedTypes(\n        \"basic_indices((3, 4), allow_newaxis=True)\",\n        \"int | slice[Any, Any, Any] | None | types.EllipsisType | tuple[int | slice[Any, Any, Any] | None | types.EllipsisType, ...]\",\n        \"int | slice[Any, Any, Any] | EllipsisType | tuple[int | slice[Any, Any, Any] | EllipsisType | None, ...] | None\",\n    ),\n]\n"
  },
  {
    "path": "whole_repo_tests/types/test_hypothesis.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesistooling.projects.hypothesispython import PYTHON_SRC\nfrom hypothesistooling.scripts import pip_tool\n\n\ndef test_mypy_passes_on_hypothesis():\n    pip_tool(\"mypy\", str(PYTHON_SRC))\n"
  },
  {
    "path": "whole_repo_tests/types/test_mypy.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport subprocess\nimport textwrap\n\nimport pytest\n\nfrom hypothesistooling.projects.hypothesispython import PYTHON_SRC\nfrom hypothesistooling.scripts import pip_tool, tool_path\n\nfrom .revealed_types import (\n    ASSUME_REVEALED_TYPES,\n    DIFF_REVEALED_TYPES,\n    NUMPY_DIFF_REVEALED_TYPES,\n    NUMPY_REVEALED_TYPES,\n    PYTHON_VERSIONS,\n    REVEALED_TYPES,\n)\n\n\n@pytest.mark.skip(\n    reason=\"Hypothesis type-annotates the public API as a convenience for users, \"\n    \"but strict checks for our internals would be a net drag on productivity.\"\n)\ndef test_mypy_passes_on_hypothesis_strict():\n    pip_tool(\"mypy\", \"--strict\", str(PYTHON_SRC))\n\n\ndef get_mypy_output(fname, *extra_args):\n    # Work around a mypy cache bug,\n    # https://github.com/HypothesisWorks/hypothesis/pull/4256\n    worker_id = os.getenv(\"PYTEST_XDIST_WORKER\", \"master\")\n\n    proc = subprocess.run(\n        [\n            tool_path(\"mypy\"),\n            \"--cache-dir\",\n            f\".mypy_caches/{worker_id}\",\n            *extra_args,\n            str(fname),\n        ],\n        encoding=\"utf-8\",\n        capture_output=True,\n        text=True,\n    )\n    if proc.stderr:\n        raise AssertionError(f\"{proc.returncode=}\\n\\n{proc.stdout}\\n\\n{proc.stderr}\")\n    return proc.stdout\n\n\ndef get_mypy_analysed_type(fname):\n    attempts = 0\n    while True:\n        out = (\n            get_mypy_output(fname)\n            .rstrip()\n            .removesuffix(\"Success: no issues found in 1 source file\")\n        )\n        # we've noticed some flakiness in getting an empty output here. Give it\n        # a couple tries.\n        if len(out.splitlines()) == 0:\n            attempts += 1\n            continue\n\n        assert len(out.splitlines()) == 1, out\n        assert attempts < 2, \"too many failed retries\"\n        break\n\n    # See https://mypy.readthedocs.io/en/latest/common_issues.html#reveal-type\n    # The shell output for `reveal_type([1, 2, 3])` looks like a literal:\n    # file.py:2: error: Revealed type is 'builtins.list[builtins.int*]'\n    return (\n        out.split(\"Revealed type is \")[1]\n        .strip()\n        .strip('\"' + \"'\")\n        .replace(\"builtins.\", \"\")\n        .replace(\"*\", \"\")\n        .replace(\n            \"hypothesis.strategies._internal.strategies.SearchStrategy\",\n            \"SearchStrategy\",\n        )\n        .replace(\"numpy._typing.\", \"\")\n        .replace(\"_nbit_base.\", \"\")\n        .replace(\"numpy.\", \"\")\n        # .replace(\"List[\", \"list[\")\n        # .replace(\"Dict[\", \"dict[\")\n    )\n\n\ndef assert_mypy_errors(fname, expected, python_version=None):\n    _args = [\"--no-error-summary\", \"--show-error-codes\"]\n\n    if python_version:\n        _args.append(f\"--python-version={python_version}\")\n\n    out = get_mypy_output(fname, *_args)\n    del _args\n    # Shell output looks like:\n    # file.py:2: error: Incompatible types in assignment ... [assignment]\n\n    print(f\"mypy output: {out}\")\n\n    def convert_lines():\n        for error_line in out.splitlines():\n            col, category = error_line.split(\":\")[-3:-1]\n            if category.strip() != \"error\":\n                # mypy outputs \"note\" messages for overload problems, even with\n                # --hide-error-context. Don't include these\n                continue\n\n            error_code = error_line.split(\"[\")[-1].rstrip(\"]\")\n            if error_code == \"empty-body\":\n                continue\n            yield (int(col), error_code)\n\n    assert sorted(convert_lines()) == sorted(expected)\n\n\n@pytest.mark.parametrize(\n    \"val,expect\",\n    [*REVEALED_TYPES, *((x.value, x.mypy) for x in DIFF_REVEALED_TYPES)],\n)\ndef test_revealed_types(tmp_path, val, expect):\n    \"\"\"Check that Mypy picks up the expected `X` in SearchStrategy[`X`].\"\"\"\n    f = tmp_path / \"check.py\"\n    f.write_text(\n        textwrap.dedent(f\"\"\"\n            from hypothesis.strategies import *\n            reveal_type({val})\n            \"\"\"),\n        encoding=\"utf-8\",\n    )\n    typ = get_mypy_analysed_type(f)\n    assert typ == f\"SearchStrategy[{expect}]\"\n\n\n@pytest.mark.parametrize(\"val,expect\", ASSUME_REVEALED_TYPES)\ndef test_assume_revealed_types(tmp_path, val, expect):\n    \"\"\"Check that Mypy infers the correct return type for assume().\"\"\"\n    f = tmp_path / \"check.py\"\n    f.write_text(\n        textwrap.dedent(f\"\"\"\n            from hypothesis import assume\n            reveal_type({val})\n            \"\"\"),\n        encoding=\"utf-8\",\n    )\n    typ = get_mypy_analysed_type(f)\n    assert typ == expect\n\n\n@pytest.mark.parametrize(\n    \"val,expect\",\n    [*NUMPY_REVEALED_TYPES, *((x.value, x.mypy) for x in NUMPY_DIFF_REVEALED_TYPES)],\n)\ndef test_numpy_revealed_types(tmp_path, val, expect):\n    f = tmp_path / \"check.py\"\n    f.write_text(\n        textwrap.dedent(f\"\"\"\n            import numpy as np\n            from hypothesis.extra.numpy import *\n            reveal_type({val})\n            \"\"\"),\n        encoding=\"utf-8\",\n    )\n    typ = get_mypy_analysed_type(f)\n    assert typ == f\"SearchStrategy[{expect}]\"\n\n\n@pytest.mark.parametrize(\n    \"val,expect\",\n    [\n        (\"elements=None, fill=None\", \"Any\"),\n        (\"elements=None, fill=floats()\", \"float\"),\n        (\"elements=floats(), fill=None\", \"float\"),\n        (\"elements=floats(), fill=text()\", \"object\"),\n        # Note: keep this in sync with the equivalent test for Mypy\n    ],\n)\ndef test_pandas_column(tmp_path, val, expect):\n    f = tmp_path / \"test.py\"\n    f.write_text(\n        textwrap.dedent(f\"\"\"\n            from hypothesis.extra.pandas import column\n            from hypothesis.strategies import floats, text\n\n            x = column(name=\"test\", unique=True, dtype=None, {val})\n            reveal_type(x)\n            \"\"\"),\n        encoding=\"utf-8\",\n    )\n    typ = get_mypy_analysed_type(f)\n    assert typ == f\"hypothesis.extra.pandas.impl.column[{expect}]\"\n\n\ndef test_data_object_type_tracing(tmp_path):\n    f = tmp_path / \"check_mypy_on_st_data.py\"\n    f.write_text(\n        \"from hypothesis.strategies import data, integers\\n\"\n        \"d = data().example()\\n\"\n        \"s = d.draw(integers())\\n\"\n        \"reveal_type(s)\\n\",\n        encoding=\"utf-8\",\n    )\n    got = get_mypy_analysed_type(f)\n    assert got == \"int\"\n\n\ndef test_drawfn_type_tracing(tmp_path):\n    f = tmp_path / \"check_mypy_on_st_drawfn.py\"\n    f.write_text(\n        \"from hypothesis.strategies import DrawFn, text\\n\"\n        \"def comp(draw: DrawFn) -> str:\\n\"\n        \"    s = draw(text(), 123)\\n\"\n        \"    reveal_type(s)\\n\"\n        \"    return s\\n\",\n        encoding=\"utf-8\",\n    )\n    got = get_mypy_analysed_type(f)\n    assert got == \"str\"\n\n\ndef test_composite_type_tracing(tmp_path):\n    f = tmp_path / \"check_mypy_on_st_composite.py\"\n    f.write_text(\n        \"from hypothesis.strategies import composite, DrawFn\\n\"\n        \"@composite\\n\"\n        \"def comp(draw: DrawFn, x: int) -> int:\\n\"\n        \"    return x\\n\"\n        \"reveal_type(comp)\\n\",\n        encoding=\"utf-8\",\n    )\n    got = get_mypy_analysed_type(f)\n    assert got == \"def (x: int) -> SearchStrategy[int]\"\n\n\n@pytest.mark.parametrize(\n    \"source, expected\",\n    [\n        (\"\", \"def ()\"),\n        (\"like=f\", \"def (x: int) -> int\"),\n        (\"returns=booleans()\", \"def () -> bool\"),\n        (\"like=f, returns=booleans()\", \"def (x: int) -> bool\"),\n    ],\n)\ndef test_functions_type_tracing(tmp_path, source, expected):\n    f = tmp_path / \"check_mypy_on_st_composite.py\"\n    f.write_text(\n        \"from hypothesis.strategies import booleans, functions\\n\"\n        \"def f(x: int) -> int: return x\\n\"\n        f\"g = functions({source}).example()\\n\"\n        \"reveal_type(g)\\n\",\n        encoding=\"utf-8\",\n    )\n    got = get_mypy_analysed_type(f)\n    assert got == expected, (got, expected)\n\n\ndef test_settings_preserves_type(tmp_path):\n    f = tmp_path / \"check_mypy_on_settings.py\"\n    f.write_text(\n        \"from hypothesis import settings\\n\"\n        \"@settings(max_examples=10)\\n\"\n        \"def f(x: int) -> int:\\n\"\n        \"    return x\\n\"\n        \"reveal_type(f)\\n\",\n        encoding=\"utf-8\",\n    )\n    got = get_mypy_analysed_type(f)\n    assert got == \"def (x: int) -> int\"\n\n\ndef test_stateful_bundle_generic_type(tmp_path):\n    f = tmp_path / \"check_mypy_on_stateful_bundle.py\"\n    f.write_text(\n        \"from hypothesis.stateful import Bundle\\n\"\n        \"b: Bundle[int] = Bundle('test')\\n\"\n        \"x = b.example()\\n\"\n        \"reveal_type(x)\\n\",\n        encoding=\"utf-8\",\n    )\n    got = get_mypy_analysed_type(f)\n    assert got == \"int\"\n\n\n@pytest.mark.parametrize(\"decorator\", [\"rule\", \"initialize\"])\n@pytest.mark.parametrize(\n    \"target_args\",\n    [\n        \"target=b1\",\n        \"targets=(b1,)\",\n        \"targets=(b1, b2)\",\n    ],\n)\n@pytest.mark.parametrize(\"returns\", [\"int\", \"MultipleResults[int]\"])\ndef test_stateful_rule_targets(tmp_path, decorator, target_args, returns):\n    f = tmp_path / \"check_mypy_on_stateful_rule.py\"\n    f.write_text(\n        \"from hypothesis.stateful import *\\n\"\n        \"b1: Bundle[int] = Bundle('b1')\\n\"\n        \"b2: Bundle[int] = Bundle('b2')\\n\"\n        f\"@{decorator}({target_args})\\n\"\n        f\"def my_rule() -> {returns}:\\n\"\n        \"    ...\\n\",\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, [])\n\n\n@pytest.mark.parametrize(\"decorator\", [\"rule\", \"initialize\"])\ndef test_stateful_rule_no_targets(tmp_path, decorator):\n    f = tmp_path / \"check_mypy_on_stateful_rule.py\"\n    f.write_text(\n        \"from hypothesis.stateful import *\\n\"\n        f\"@{decorator}()\\n\"\n        \"def my_rule() -> None:\\n\"\n        \"    ...\\n\",\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, [])\n\n\n@pytest.mark.parametrize(\"decorator\", [\"rule\", \"initialize\"])\ndef test_stateful_target_params_mutually_exclusive(tmp_path, decorator):\n    f = tmp_path / \"check_mypy_on_stateful_rule.py\"\n    f.write_text(\n        \"from hypothesis.stateful import *\\n\"\n        \"b1: Bundle[int] = Bundle('b1')\\n\"\n        f\"@{decorator}(target=b1, targets=(b1,))\\n\"\n        \"def my_rule() -> int:\\n\"\n        \"    ...\\n\",\n        encoding=\"utf-8\",\n    )\n    # Also outputs \"untyped-decorator\" error \"Untyped decorator makes function \"my_rule\"\n    # untyped, due to the inability to resolve to an appropriate overloaded\n    # variant\n    assert_mypy_errors(f, [(3, \"call-overload\"), (3, \"untyped-decorator\")])\n\n\n@pytest.mark.parametrize(\"decorator\", [\"rule\", \"initialize\"])\n@pytest.mark.parametrize(\n    \"target_args\", [\"\", \"target=b1\", \"targets=(b1,)\", \"targets=(b1, b2)\"]\n)\n@pytest.mark.parametrize(\"returns\", [\"int\", \"MultipleResults[int]\"])\ndef test_stateful_target_params_return_type(tmp_path, decorator, target_args, returns):\n    f = tmp_path / \"check_mypy_on_stateful_rule.py\"\n    f.write_text(\n        \"from hypothesis.stateful import *\\n\"\n        \"b1: Bundle[str] = Bundle('b1')\\n\"\n        \"b2: Bundle[str] = Bundle('b2')\\n\"\n        f\"@{decorator}({target_args})\\n\"\n        f\"def my_rule() -> {returns}:\\n\"\n        \"    ...\\n\",\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, [(4, \"arg-type\")])\n\n\n@pytest.mark.parametrize(\"decorator\", [\"rule\", \"initialize\"])\ndef test_stateful_no_target_params_return_type(tmp_path, decorator):\n    f = tmp_path / \"check_mypy_on_stateful_rule.py\"\n    f.write_text(\n        \"from hypothesis.stateful import *\\n\"\n        f\"@{decorator}()\\n\"\n        \"def my_rule() -> int:\\n\"\n        \"    ...\\n\",\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, [(2, \"arg-type\")])\n\n\n@pytest.mark.parametrize(\"decorator\", [\"rule\", \"initialize\"])\n@pytest.mark.parametrize(\"use_multi\", [True, False])\ndef test_stateful_bundle_variance(tmp_path, decorator, use_multi):\n    f = tmp_path / \"check_mypy_on_stateful_bundle.py\"\n    if use_multi:\n        return_type = \"MultipleResults[Dog]\"\n        return_expr = \"multiple(dog, dog)\"\n    else:\n        return_type = \"Dog\"\n        return_expr = \"dog\"\n\n    f.write_text(\n        \"from hypothesis.stateful import *\\n\"\n        \"class Animal: pass\\n\"\n        \"class Dog(Animal): pass\\n\"\n        \"a: Bundle[Animal] = Bundle('animal')\\n\"\n        \"d: Bundle[Dog] = Bundle('dog')\\n\"\n        f\"@{decorator}(target=a, dog=d)\\n\"\n        f\"def my_rule(dog: Dog) -> {return_type}:\\n\"\n        f\"    return {return_expr}\\n\",\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, [])\n\n\n@pytest.mark.parametrize(\"decorator\", [\"rule\", \"initialize\"])\ndef test_stateful_multiple_return(tmp_path, decorator):\n    f = tmp_path / \"check_mypy_on_stateful_multiple.py\"\n    f.write_text(\n        \"from hypothesis.stateful import *\\n\"\n        \"b: Bundle[int] = Bundle('b')\\n\"\n        f\"@{decorator}(target=b)\\n\"\n        \"def my_rule() -> MultipleResults[int]:\\n\"\n        \"    return multiple(1, 2, 3)\\n\",\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, [])\n\n\n@pytest.mark.parametrize(\"decorator\", [\"rule\", \"initialize\"])\ndef test_stateful_multiple_return_invalid(tmp_path, decorator):\n    f = tmp_path / \"check_mypy_on_stateful_multiple.py\"\n    f.write_text(\n        \"from hypothesis.stateful import *\\n\"\n        \"b: Bundle[str] = Bundle('b')\\n\"\n        f\"@{decorator}(target=b)\\n\"\n        \"def my_rule() -> MultipleResults[int]:\\n\"\n        \"    return multiple(1, 2, 3)\\n\",\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, [(3, \"arg-type\")])\n\n\n@pytest.mark.parametrize(\n    \"wrapper,expected\",\n    [\n        (\"{}\", \"int\"),\n        (\"st.lists({})\", \"list[int]\"),\n    ],\n)\ndef test_stateful_consumes_type_tracing(tmp_path, wrapper, expected):\n    f = tmp_path / \"check_mypy_on_stateful_rule.py\"\n    wrapped = wrapper.format(\"consumes(b)\")\n    f.write_text(\n        \"from hypothesis.stateful import *\\n\"\n        \"from hypothesis import strategies as st\\n\"\n        \"b: Bundle[int] = Bundle('b')\\n\"\n        f\"s = {wrapped}\\n\"\n        \"reveal_type(s.example())\\n\",\n        encoding=\"utf-8\",\n    )\n    got = get_mypy_analysed_type(f)\n    assert got == expected\n\n\ndef test_stateful_consumed_bundle_cannot_be_target(tmp_path):\n    f = tmp_path / \"check_mypy_on_stateful_rule.py\"\n    f.write_text(\n        \"from hypothesis.stateful import *\\n\"\n        \"b: Bundle[int] = Bundle('b')\\n\"\n        \"rule(target=consumes(b))\\n\",\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, [(3, \"call-overload\")])\n\n\n@pytest.mark.parametrize(\n    \"return_val,errors\",\n    [\n        (\"True\", []),\n        (\"0\", [(2, \"arg-type\"), (2, \"return-value\")]),\n    ],\n)\ndef test_stateful_precondition_requires_predicate(tmp_path, return_val, errors):\n    f = tmp_path / \"check_mypy_on_stateful_precondition.py\"\n    f.write_text(\n        \"from hypothesis.stateful import *\\n\"\n        f\"@precondition(lambda self: {return_val})\\n\"\n        \"def my_rule() -> None: ...\\n\",\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, errors)\n\n\ndef test_stateful_precondition_lambda(tmp_path):\n    f = tmp_path / \"check_mypy_on_stateful_precondition.py\"\n    f.write_text(\n        \"from hypothesis.stateful import *\\n\"\n        \"class MyMachine(RuleBasedStateMachine):\\n\"\n        \"  valid: bool\\n\"\n        \"  @precondition(lambda self: self.valid)\\n\"\n        \"  @rule()\\n\"\n        \"  def my_rule(self) -> None: ...\\n\",\n        encoding=\"utf-8\",\n    )\n    # Note that this doesn't fully check the code because of the `Any` parameter\n    # type. `lambda self: self.invalid` would unfortunately pass too\n    assert_mypy_errors(f, [])\n\n\ndef test_stateful_precondition_instance_method(tmp_path):\n    f = tmp_path / \"check_mypy_on_stateful_precondition.py\"\n    f.write_text(\n        \"from hypothesis.stateful import *\\n\"\n        \"class MyMachine(RuleBasedStateMachine):\\n\"\n        \"  valid: bool\\n\"\n        \"  def check(self) -> bool:\\n\"\n        \"    return self.valid\\n\"\n        \"  @precondition(check)\\n\"\n        \"  @rule()\\n\"\n        \"  def my_rule(self) -> None: ...\\n\",\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, [])\n\n\ndef test_stateful_precondition_precond_requires_one_arg(tmp_path):\n    f = tmp_path / \"check_mypy_on_stateful_precondition.py\"\n    f.write_text(\n        \"from hypothesis.stateful import *\\n\"\n        \"precondition(lambda: True)\\n\"\n        \"precondition(lambda a, b: True)\\n\",\n        encoding=\"utf-8\",\n    )\n    # Additional \"Cannot infer type of lambda\" errors\n    assert_mypy_errors(\n        f,\n        [(2, \"arg-type\"), (2, \"misc\"), (3, \"arg-type\"), (3, \"misc\")],\n    )\n\n\ndef test_pos_only_args(tmp_path):\n    f = tmp_path / \"check_mypy_on_pos_arg_only_strats.py\"\n    f.write_text(\n        textwrap.dedent(\"\"\"\n            import hypothesis.strategies as st\n\n            st.tuples(a1=st.integers())\n            st.tuples(a1=st.integers(), a2=st.integers())\n\n            st.one_of(a1=st.integers())\n            st.one_of(a1=st.integers(), a2=st.integers())\n            \"\"\"),\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(\n        f,\n        [\n            (4, \"call-overload\"),\n            (5, \"call-overload\"),\n            (7, \"call-overload\"),\n            (8, \"call-overload\"),\n        ],\n    )\n\n\n@pytest.mark.parametrize(\"python_version\", PYTHON_VERSIONS)\ndef test_mypy_passes_on_basic_test(tmp_path, python_version):\n    f = tmp_path / \"check_mypy_on_basic_tests.py\"\n    f.write_text(\n        textwrap.dedent(\"\"\"\n            import hypothesis\n            import hypothesis.strategies as st\n\n            @hypothesis.given(x=st.text())\n            def test_foo(x: str) -> None:\n                assert x == x\n\n            from hypothesis import given\n            from hypothesis.strategies import text\n\n            @given(x=text())\n            def test_bar(x: str) -> None:\n                assert x == x\n            \"\"\"),\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, [], python_version=python_version)\n\n\n@pytest.mark.parametrize(\"python_version\", PYTHON_VERSIONS)\ndef test_given_only_allows_strategies(tmp_path, python_version):\n    f = tmp_path / \"check_mypy_given_expects_strategies.py\"\n    f.write_text(\n        textwrap.dedent(\"\"\"\n            from hypothesis import given\n\n            @given(1)\n            def f():\n                pass\n            \"\"\"),\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, [(4, \"call-overload\")], python_version=python_version)\n\n\n@pytest.mark.parametrize(\"python_version\", PYTHON_VERSIONS)\ndef test_raises_for_mixed_pos_kwargs_in_given(tmp_path, python_version):\n    f = tmp_path / \"raises_for_mixed_pos_kwargs_in_given.py\"\n    f.write_text(\n        textwrap.dedent(\"\"\"\n            from hypothesis import given\n            from hypothesis.strategies import text\n\n            @given(text(), x=text())\n            def test_bar(x):\n                ...\n            \"\"\"),\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, [(5, \"call-overload\")], python_version=python_version)\n\n\ndef test_register_random_interface(tmp_path):\n    f = tmp_path / \"test_register_random_interface.py\"\n    f.write_text(\n        textwrap.dedent(\"\"\"\n            from random import Random\n            from hypothesis import register_random\n\n            class MyRandom:\n                def __init__(self) -> None:\n                    r = Random()\n                    self.seed = r.seed\n                    self.setstate = r.setstate\n                    self.getstate = r.getstate\n\n            register_random(MyRandom())\n            register_random(None)  # type: ignore[arg-type]\n            \"\"\"),\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, [])\n\n\ndef test_register_type_strategy_type_alias_type(tmp_path):\n    # see https://github.com/HypothesisWorks/hypothesis/issues/4410\n    f = tmp_path / \"test_register_type_strategy_type_alias_type.py\"\n    f.write_text(\n        textwrap.dedent(\"\"\"\n            from hypothesis import strategies as st\n            from typing import TypeAliasType\n\n            def ints() -> st.SearchStrategy[int]:\n                return st.from_type(int)\n\n            Ints = TypeAliasType(\"Ints\", int)  # or `type Ints = int`\n\n            # this previous failed type-checking\n            st.register_type_strategy(Ints, ints())\n            \"\"\"),\n        encoding=\"utf-8\",\n    )\n    assert_mypy_errors(f, [], python_version=\"3.12\")\n"
  },
  {
    "path": "whole_repo_tests/types/test_pyright.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom __future__ import annotations\n\nimport json\nimport re\nimport subprocess\nimport sys\nimport textwrap\nfrom pathlib import Path\nfrom typing import Any\n\nimport pytest\n\nfrom hypothesistooling.projects.hypothesispython import HYPOTHESIS_PYTHON, PYTHON_SRC\nfrom hypothesistooling.scripts import pip_tool, tool_path\n\nfrom .revealed_types import (\n    ASSUME_REVEALED_TYPES,\n    DIFF_REVEALED_TYPES,\n    NUMPY_DIFF_REVEALED_TYPES,\n    NUMPY_REVEALED_TYPES,\n    PYTHON_VERSIONS,\n    REVEALED_TYPES,\n)\n\n\n@pytest.mark.skip(\n    reason=\"Hypothesis type-annotates the public API as a convenience for users, \"\n    \"but strict checks for our internals would be a net drag on productivity.\"\n)\ndef test_pyright_passes_on_hypothesis():\n    pip_tool(\"pyright\", \"--project\", HYPOTHESIS_PYTHON)\n\n\n@pytest.mark.parametrize(\"python_version\", PYTHON_VERSIONS)\ndef test_pyright_passes_on_basic_test(tmp_path: Path, python_version: str):\n    file = tmp_path / \"test.py\"\n    file.write_text(\n        textwrap.dedent(\n            \"\"\"\n            import hypothesis\n            import hypothesis.strategies as st\n\n            @hypothesis.given(x=st.text())\n            def test_foo(x: str):\n                assert x == x\n\n            from hypothesis import given\n            from hypothesis.strategies import text\n\n            @given(x=text())\n            def test_bar(x: str):\n                assert x == x\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    _write_config(\n        tmp_path, {\"typeCheckingMode\": \"strict\", \"pythonVersion\": python_version}\n    )\n    assert _get_pyright_errors(file) == []\n\n\n@pytest.mark.parametrize(\n    \"python_version\",\n    [\n        # FIXME: temporary workaround, see hypothesis/pull/4136\n        pytest.param(v, marks=[pytest.mark.xfail(strict=False)] * (v == \"3.13\"))\n        for v in PYTHON_VERSIONS\n    ],\n)\ndef test_given_only_allows_strategies(tmp_path: Path, python_version: str):\n    file = tmp_path / \"test.py\"\n    file.write_text(\n        textwrap.dedent(\n            \"\"\"\n            from hypothesis import given\n\n            @given(1)\n            def f():\n                pass\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    _write_config(\n        tmp_path, {\"typeCheckingMode\": \"strict\", \"pythonVersion\": python_version}\n    )\n    errors = _get_pyright_errors(file)\n    msg = 'Argument of type \"Literal[1]\" cannot be assigned to parameter \"_given_arguments\"'\n    assert sum(e[\"message\"].startswith(msg) for e in errors) == 1, errors\n\n\ndef test_pyright_issue_3296(tmp_path: Path):\n    file = tmp_path / \"test.py\"\n    file.write_text(\n        textwrap.dedent(\n            \"\"\"\n            from hypothesis.strategies import lists, integers\n\n            lists(integers()).map(sorted)\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    _write_config(tmp_path, {\"typeCheckingMode\": \"strict\"})\n    assert _get_pyright_errors(file) == []\n\n\ndef test_pyright_raises_for_mixed_pos_kwargs_in_given(tmp_path: Path):\n    file = tmp_path / \"test.py\"\n    file.write_text(\n        textwrap.dedent(\n            \"\"\"\n            from hypothesis import given\n            from hypothesis.strategies import text\n\n            @given(text(), x=text())\n            def test_bar(x: str):\n                pass\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    _write_config(tmp_path, {\"typeCheckingMode\": \"strict\"})\n    assert (\n        sum(\n            e[\"message\"].startswith(\n                'No overloads for \"given\" match the provided arguments'\n            )\n            for e in _get_pyright_errors(file)\n        )\n        == 1\n    )\n\n\ndef test_pyright_issue_3348(tmp_path: Path):\n    file = tmp_path / \"test.py\"\n    file.write_text(\n        textwrap.dedent(\n            \"\"\"\n            import hypothesis.strategies as st\n\n            st.tuples(st.integers(), st.integers())\n            st.one_of(st.integers(), st.integers())\n            st.one_of([st.integers(), st.floats()])  # sequence of strats should be OK\n            st.sampled_from([1, 2])\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    _write_config(tmp_path, {\"typeCheckingMode\": \"strict\"})\n    assert _get_pyright_errors(file) == []\n\n\ndef test_numpy_arrays_strategy(tmp_path: Path):\n    file = tmp_path / \"test.py\"\n    file.write_text(\n        textwrap.dedent(\n            \"\"\"\n            import numpy as np\n            from hypothesis.extra.numpy import arrays\n\n            x = arrays(dtype=np.dtype(\"int32\"), shape=1)\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    _write_config(tmp_path, {\"typeCheckingMode\": \"strict\"})\n    errors = _get_pyright_errors(file)\n    print(errors)\n    assert errors == []\n\n\n@pytest.mark.parametrize(\n    \"val,expect\",\n    [*REVEALED_TYPES, *((x.value, x.pyright) for x in DIFF_REVEALED_TYPES)],\n)\ndef test_revealed_types(tmp_path, val, expect):\n    \"\"\"Check that Pyright picks up the expected `X` in SearchStrategy[`X`].\"\"\"\n    f = tmp_path / (expect + \".py\")\n    f.write_text(\n        textwrap.dedent(\n            f\"\"\"\n            from hypothesis.strategies import *\n            reveal_type({val})\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    _write_config(tmp_path, {\"reportWildcardImportFromLibrary \": \"none\"})\n    typ = get_pyright_analysed_type(f)\n    assert typ == f\"SearchStrategy[{expect}]\"\n\n\n@pytest.mark.parametrize(\"val,expect\", ASSUME_REVEALED_TYPES)\ndef test_assume_revealed_types(tmp_path, val, expect):\n    \"\"\"Check that Pyright infers the correct return type for assume().\"\"\"\n    f = tmp_path / \"check.py\"\n    f.write_text(\n        textwrap.dedent(\n            f\"\"\"\n            from hypothesis import assume\n            reveal_type({val})\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    _write_config(tmp_path)\n    typ = get_pyright_analysed_type(f)\n    # Pyright uses NoReturn, mypy uses Never\n    assert typ == (expect if expect != \"Never\" else \"NoReturn\")\n\n\n@pytest.mark.parametrize(\n    \"val,expect\",\n    [*NUMPY_REVEALED_TYPES, *((x.value, x.pyright) for x in NUMPY_DIFF_REVEALED_TYPES)],\n)\ndef test_numpy_revealed_types(tmp_path, val, expect):\n    f = tmp_path / \"check.py\"\n    f.write_text(\n        textwrap.dedent(\n            f\"\"\"\n            import numpy as np\n            from hypothesis.extra.numpy import *\n            reveal_type({val})\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    _write_config(tmp_path, {\"reportWildcardImportFromLibrary \": \"none\"})\n    typ = get_pyright_analysed_type(f)\n    assert typ == f\"SearchStrategy[{expect}]\"\n\n\n@pytest.mark.parametrize(\n    \"val,expect\",\n    [\n        (\"elements=None, fill=None\", \"Any\"),\n        (\"elements=None, fill=floats()\", \"float\"),\n        (\"elements=floats(), fill=None\", \"float\"),\n        (\"elements=floats(), fill=text()\", \"float | str\"),\n        # Note: keep this in sync with the equivalent test for Mypy\n    ],\n)\ndef test_pandas_column(tmp_path, val, expect):\n    f = tmp_path / \"test.py\"\n    f.write_text(\n        textwrap.dedent(\n            f\"\"\"\n            from hypothesis.extra.pandas import column\n            from hypothesis.strategies import *\n\n            x = column(name=\"test\", unique=True, dtype=None, {val})\n            reveal_type(x)\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    _write_config(\n        tmp_path,\n        {\"typeCheckingMode\": \"strict\", \"reportWildcardImportFromLibrary \": \"none\"},\n    )\n    typ = get_pyright_analysed_type(f)\n    assert typ == f\"column[{expect}]\"\n\n\ndef test_pyright_tuples_pos_args_only(tmp_path: Path):\n    file = tmp_path / \"test.py\"\n    file.write_text(\n        textwrap.dedent(\n            \"\"\"\n            import hypothesis.strategies as st\n\n            st.tuples(a1=st.integers())\n            st.tuples(a1=st.integers(), a2=st.integers())\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    _write_config(tmp_path, {\"typeCheckingMode\": \"strict\"})\n    assert (\n        sum(\n            e[\"message\"].startswith(\n                'No overloads for \"tuples\" match the provided arguments'\n            )\n            for e in _get_pyright_errors(file)\n        )\n        == 2\n    )\n\n\ndef test_pyright_one_of_pos_args_only(tmp_path: Path):\n    file = tmp_path / \"test.py\"\n    file.write_text(\n        textwrap.dedent(\n            \"\"\"\n            import hypothesis.strategies as st\n\n            st.one_of(a1=st.integers())\n            st.one_of(a1=st.integers(), a2=st.integers())\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    _write_config(tmp_path, {\"typeCheckingMode\": \"strict\"})\n    assert (\n        sum(\n            e[\"message\"].startswith(\n                'No overloads for \"one_of\" match the provided arguments'\n            )\n            for e in _get_pyright_errors(file)\n        )\n        == 2\n    )\n\n\ndef test_register_random_protocol(tmp_path: Path):\n    file = tmp_path / \"test.py\"\n    file.write_text(\n        textwrap.dedent(\n            \"\"\"\n            from random import Random\n            from hypothesis import register_random\n\n            class MyRandom:\n                def __init__(self) -> None:\n                    r = Random()\n                    self.seed = r.seed\n                    self.setstate = r.setstate\n                    self.getstate = r.getstate\n\n            register_random(MyRandom())\n            register_random(None)  # type: ignore\n            \"\"\"\n        ),\n        encoding=\"utf-8\",\n    )\n    _write_config(tmp_path, {\"reportUnnecessaryTypeIgnoreComment\": True})\n    assert _get_pyright_errors(file) == []\n\n\n# ---------- Helpers for running pyright ---------- #\n\n\ndef _get_pyright_output(file: Path) -> dict[str, Any]:\n    proc = subprocess.run(\n        [tool_path(\"pyright\"), \"--outputjson\", f\"--pythonpath={sys.executable}\"],\n        cwd=file.parent,\n        encoding=\"utf-8\",\n        text=True,\n        capture_output=True,\n    )\n    try:\n        return json.loads(proc.stdout)\n    except Exception:\n        print(proc.stdout)\n        raise\n\n\ndef _get_pyright_errors(file: Path) -> list[dict[str, Any]]:\n    return _get_pyright_output(file)[\"generalDiagnostics\"]\n\n\ndef get_pyright_analysed_type(fname):\n    out, *rest = _get_pyright_errors(fname)\n    print(out, rest)\n    assert not rest\n    assert out[\"severity\"] == \"information\"\n    return (\n        re.fullmatch(r'Type of \".+\" is \"(.+)\"', out[\"message\"])\n        .group(1)\n        .replace(\"builtins.\", \"\")\n        .replace(\"numpy.\", \"\")\n        .replace(\n            \"signedinteger[_32Bit | _64Bit] | bool[bool]\",\n            \"Union[signedinteger[Union[_32Bit, _64Bit]], bool[bool]]\",\n        )\n    )\n\n\ndef _write_config(config_dir: Path, data: dict[str, Any] | None = None):\n    config = {\"extraPaths\": [str(PYTHON_SRC)], **(data or {})}\n    (config_dir / \"pyrightconfig.json\").write_text(json.dumps(config), encoding=\"utf-8\")\n"
  },
  {
    "path": "whole_repo_tests/whole_repo/__init__.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "whole_repo_tests/whole_repo/test_ci_config.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport re\nfrom pathlib import Path\n\nimport pytest\n\nfrom hypothesistooling.__main__ import PYTHONS\n\nci_checks = \"    \".join(\n    line.strip()\n    for line in Path(\".github/workflows/main.yml\")\n    .read_text(encoding=\"utf-8\")\n    .splitlines()\n    if \"- check-py\" in line\n)\n\n\n@pytest.mark.parametrize(\"version\", sorted(PYTHONS))\ndef test_python_versions_are_tested_in_ci(version):\n    slug = version.replace(\"pypy\", \"py\").replace(\".\", \"\")\n    print(ci_checks)\n    assert f\"- check-py{slug}\" in ci_checks, f\"Add {version} to main.yml and tox.ini\"\n\n\ndef test_python_versions_are_in_trove_classifiers():\n    got_classifiers = {\n        line.strip(' \",\\n')\n        for line in Path(\"hypothesis-python/pyproject.toml\")\n        .read_text(encoding=\"utf-8\")\n        .splitlines()\n        if \"Programming Language :: Python :: 3.\" in line\n    }\n    expected_classifiers = {\n        f\"Programming Language :: Python :: 3.{v.split('.')[1]}\"\n        for v in PYTHONS.values()\n        if re.fullmatch(r\"3\\.\\d+\\.\\d+\", v)\n    }\n    assert got_classifiers == expected_classifiers\n"
  },
  {
    "path": "whole_repo_tests/whole_repo/test_deploy.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\n\nimport pytest\n\nimport hypothesistooling as tools\nfrom hypothesistooling import __main__ as main, releasemanagement as rm\n\n\n@pytest.mark.parametrize(\n    \"project\", [p for p in tools.all_projects() if p.has_release()]\n)\ndef test_release_file_exists_and_is_valid(project, monkeypatch):\n    if not tools.has_uncommitted_changes(project.BASE_DIR):\n        pytest.xfail(\"Cannot run release process with uncommitted changes\")\n\n    monkeypatch.setattr(tools, \"create_tag\", lambda *args, **kwargs: None)\n    monkeypatch.setattr(tools, \"push_tag\", lambda name: None)\n    monkeypatch.setattr(rm, \"commit_pending_release\", lambda p: None)\n    monkeypatch.setattr(project, \"upload_distribution\", lambda: None)\n    monkeypatch.setattr(project, \"IN_TEST\", True, raising=False)\n\n    try:\n        main.do_release(project)\n\n        with open(project.CHANGELOG_FILE, encoding=\"utf-8\") as i:\n            changelog = i.read()\n        assert project.current_version() in changelog\n        assert rm.release_date_string() in changelog\n\n    finally:\n        tools.git(\"checkout\", project.BASE_DIR)\n        os.chdir(tools.ROOT)\n"
  },
  {
    "path": "whole_repo_tests/whole_repo/test_release_files.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nimport hypothesistooling as tools\nfrom hypothesistooling import releasemanagement as rm\nfrom hypothesistooling.projects import hypothesispython as hp\n\n\n@pytest.mark.parametrize(\"project\", tools.all_projects())\ndef test_release_file_exists_and_is_valid(project):\n    if project.has_source_changes():\n        assert project.has_release(), (\n            \"There are source changes but no RELEASE.rst. Please create \"\n            \"one to describe your changes. An example can be found in \"\n            \"RELEASE-sample.rst.\"\n        )\n        assert project.has_release_sample(), (\n            \"The RELEASE-sample.rst file is missing. Please copy it \"\n            \"to RELEASE.rst, rather than moving it.\"\n        )\n        rm.parse_release_file(project.RELEASE_FILE)\n\n\n@pytest.mark.skipif(not hp.has_release(), reason=\"Checking that release\")\ndef test_release_file_has_no_merge_conflicts():\n    _, message = rm.parse_release_file(hp.RELEASE_FILE)\n    assert \"<<<\" not in message, \"Merge conflict in RELEASE.rst\"\n    if message in {hp.get_autoupdate_message(x).strip() for x in (True, False)}:\n        return\n    _, *recent_changes, _ = hp.CHANGELOG_ANCHOR.split(hp.changelog(), maxsplit=12)\n    for entry in recent_changes:\n        _, version, old_msg = (x.strip() for x in hp.CHANGELOG_BORDER.split(entry))\n        assert message not in old_msg, f\"Release notes already published for {version}\"\n        assert old_msg not in message, f\"Copied {version} release notes - merge error?\"\n"
  },
  {
    "path": "whole_repo_tests/whole_repo/test_release_management.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport pytest\n\nfrom hypothesistooling.releasemanagement import (\n    bump_version_info,\n    parse_release_file_contents,\n    release_date_string,\n    replace_assignment_in_string as replace,\n    update_markdown_changelog,\n)\n\n\ndef parse_release(contents):\n    return parse_release_file_contents(contents, \"<string>\")\n\n\ndef test_update_single_line():\n    assert replace(\"a = 1\", \"a\", \"2\") == \"a = 2\"\n\n\ndef test_update_without_spaces():\n    assert replace(\"a=1\", \"a\", \"2\") == \"a=2\"\n\n\ndef test_update_in_middle():\n    assert replace(\"a = 1\\nb=2\\nc = 3\", \"b\", \"4\") == \"a = 1\\nb=4\\nc = 3\"\n\n\ndef test_quotes_string_to_assign():\n    assert replace(\"a.c = 1\", \"a.c\", \"2\") == \"a.c = 2\"\n    with pytest.raises(ValueError):\n        replace(\"abc = 1\", \"a.c\", \"2\")\n\n\ndef test_duplicates_are_errors():\n    with pytest.raises(ValueError):\n        replace(\"a = 1\\na=1\", \"a\", \"2\")\n\n\ndef test_missing_is_error():\n    with pytest.raises(ValueError):\n        replace(\"\", \"a\", \"1\")\n\n\ndef test_bump_minor_version():\n    assert bump_version_info((1, 1, 1), \"minor\")[0] == \"1.2.0\"\n\n\ndef test_parse_release_file():\n    assert parse_release(\"RELEASE_TYPE: patch\\nhi\") == (\"patch\", \"hi\")\n    assert parse_release(\"RELEASE_TYPE: minor\\n\\n\\n\\nhi\") == (\"minor\", \"hi\")\n    assert parse_release(\"RELEASE_TYPE: major\\n \\n\\nhi\") == (\"major\", \"hi\")\n\n\ndef test_invalid_release():\n    with pytest.raises(ValueError):\n        parse_release(\"RELEASE_TYPE: wrong\\nstuff\")\n\n    with pytest.raises(ValueError):\n        parse_release(\"\")\n\n\nTEST_CHANGELOG = f\"\"\"\n# A test project 1.2.3 ({release_date_string()})\n\nsome stuff happened\n\n# some previous log entry\n\"\"\"\n\n\ndef test_update_changelog(tmp_path):\n    path = tmp_path / \"CHANGELOG.md\"\n    path.write_text(\"# some previous log entry\\n\", encoding=\"utf-8\")\n    update_markdown_changelog(\n        str(path), \"A test project\", \"1.2.3\", \"some stuff happened\"\n    )\n    assert path.read_text(encoding=\"utf-8\").strip() == TEST_CHANGELOG.strip()\n\n\ndef test_changelog_parsing_strips_trailing_whitespace():\n    header = \"RELEASE_TYPE: patch\\n\\n\"\n    contents = \"Adds a feature\\n    indented.\\n\"\n    _level, out = parse_release(header + contents.replace(\"feature\", \"feature    \"))\n    assert contents.strip() == out\n"
  },
  {
    "path": "whole_repo_tests/whole_repo/test_requirements.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nfrom hypothesistooling.__main__ import check_requirements\n\n\ndef test_requirements():\n    check_requirements()\n"
  },
  {
    "path": "whole_repo_tests/whole_repo/test_rst_is_valid.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport os\nimport re\nfrom pathlib import Path\n\nimport hypothesistooling as tools\nfrom hypothesistooling.projects import hypothesispython as hp\nfrom hypothesistooling.scripts import pip_tool\n\n\ndef is_sphinx(f):\n    f = os.path.abspath(f)\n    return f.startswith(os.path.join(hp.HYPOTHESIS_PYTHON, \"docs\"))\n\n\nALL_RST = [\n    p\n    for p in tools.all_files()\n    if p.name not in [\"RELEASE.rst\", \"RELEASE-sample.rst\"] and p.suffix == \".rst\"\n]\n\n\ndef test_passes_rst_lint():\n    pip_tool(\"rst-lint\", *(f for f in ALL_RST if not is_sphinx(f)))\n\n\ndef test_rst_code_blocks():\n    # has bitten us before https://github.com/HypothesisWorks/hypothesis/pull/4273\n    pattern = re.compile(r\"^\\.\\.\\s+code-block:\\s+\", re.MULTILINE)\n    for f in ALL_RST:\n        matches = pattern.search(Path(f).read_text())\n        assert not matches, (\n            f\"incorrect code block syntax in {f}. Use `.. code-block::` \"\n            \"instead of `.. code-block:`\"\n        )\n\n\ndef disabled_test_passes_flake8():\n    # TODO: get these whitespace checks without flake8?\n    pip_tool(\"flake8\", \"--select=W191,W291,W292,W293,W391\", *ALL_RST)\n"
  },
  {
    "path": "whole_repo_tests/whole_repo/test_shellcheck.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport subprocess\n\nimport hypothesistooling as tools\nfrom hypothesistooling import installers as install\n\nSCRIPTS = [p for p in tools.all_files() if p.suffix == \".sh\"]\n\n\ndef test_all_shell_scripts_are_valid():\n    subprocess.check_call(\n        [install.SHELLCHECK, \"--exclude=SC1073,SC1072\", *SCRIPTS], cwd=tools.ROOT\n    )\n"
  },
  {
    "path": "whole_repo_tests/whole_repo/test_validate_branch_check.py",
    "content": "# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis/\n#\n# Copyright the Hypothesis Authors.\n# Individual contributors are listed in AUTHORS.rst and the git log.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at https://mozilla.org/MPL/2.0/.\n\nimport json\nimport os\nimport subprocess\nimport sys\n\nfrom hypothesistooling.projects.hypothesispython import BASE_DIR\n\nBRANCH_CHECK = \"branch-check\"\nVALIDATE_BRANCH_CHECK = os.path.join(BASE_DIR, \"scripts\", \"validate_branch_check.py\")\n\n\ndef write_entries(tmp_path, entries):\n    with open(tmp_path / BRANCH_CHECK, \"w\", encoding=\"utf-8\") as f:\n        f.writelines([json.dumps(entry) + \"\\n\" for entry in entries])\n\n\ndef run_validate_branch_check(tmp_path, *, check, **kwargs):\n    return subprocess.run(\n        [sys.executable, VALIDATE_BRANCH_CHECK],\n        cwd=tmp_path,\n        text=True,\n        capture_output=True,\n        check=check,\n        **kwargs,\n    )\n\n\ndef test_validates_branches(tmp_path):\n    write_entries(\n        tmp_path,\n        [\n            {\"name\": name, \"value\": value}\n            for name in (\"first\", \"second\", \"third\")\n            for value in (False, True)\n        ],\n    )\n\n    output = run_validate_branch_check(tmp_path, check=True)\n    assert output.stdout == \"Successfully validated 3 branches.\\n\"\n\n\ndef test_validates_one_branch(tmp_path):\n    write_entries(\n        tmp_path, [{\"name\": \"sole\", \"value\": value} for value in (False, True)]\n    )\n\n    output = run_validate_branch_check(tmp_path, check=True)\n    assert output.stdout == \"Successfully validated 1 branch.\\n\"\n\n\ndef test_fails_on_zero_branches(tmp_path):\n    write_entries(tmp_path, [])\n\n    output = run_validate_branch_check(tmp_path, check=False)\n    assert output.returncode == 1\n    assert output.stdout == \"No branches found in the branch-check file?\\n\"\n\n\ndef test_reports_uncovered_branches(tmp_path):\n    write_entries(\n        tmp_path,\n        [\n            {\"name\": \"branch that is always taken\", \"value\": True},\n            {\"name\": \"some other branch that is never taken\", \"value\": False},\n            {\"name\": \"covered branch\", \"value\": True},\n            {\"name\": \"covered branch\", \"value\": False},\n        ],\n    )\n\n    output = run_validate_branch_check(tmp_path, check=False)\n    assert output.returncode == 1\n    expected = \"\"\"\\\nSome branches were not properly covered.\n\nThe following were always True:\n  * branch that is always taken\n\nThe following were always False:\n  * some other branch that is never taken\n\"\"\"\n    assert output.stdout == expected\n"
  }
]