{"id":19097251,"url":"https://github.com/lycantropos/hypothesis_geometry","last_synced_at":"2025-04-30T14:29:57.894Z","repository":{"id":55042173,"uuid":"234055195","full_name":"lycantropos/hypothesis_geometry","owner":"lycantropos","description":"`hypothesis` strategies for geometries","archived":false,"fork":false,"pushed_at":"2023-05-15T04:13:59.000Z","size":738,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-30T14:29:53.579Z","etag":null,"topics":["data-generator","geometry","hypothesis","quickcheck","testing"],"latest_commit_sha":null,"homepage":"https://hypothesis-geometry.rtfd.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lycantropos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-01-15T10:24:38.000Z","updated_at":"2024-11-27T10:49:21.000Z","dependencies_parsed_at":"2024-11-09T03:39:49.482Z","dependency_job_id":null,"html_url":"https://github.com/lycantropos/hypothesis_geometry","commit_stats":{"total_commits":663,"total_committers":1,"mean_commits":663.0,"dds":0.0,"last_synced_commit":"aac311840fba13f05ef48369e600284c2d3698f6"},"previous_names":[],"tags_count":50,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lycantropos%2Fhypothesis_geometry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lycantropos%2Fhypothesis_geometry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lycantropos%2Fhypothesis_geometry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lycantropos%2Fhypothesis_geometry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lycantropos","download_url":"https://codeload.github.com/lycantropos/hypothesis_geometry/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251721336,"owners_count":21632814,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-generator","geometry","hypothesis","quickcheck","testing"],"created_at":"2024-11-09T03:39:34.464Z","updated_at":"2025-04-30T14:29:57.854Z","avatar_url":"https://github.com/lycantropos.png","language":"Python","readme":"hypothesis_geometry\n===================\n\n[![](https://github.com/lycantropos/hypothesis_geometry/workflows/CI/badge.svg)](https://github.com/lycantropos/hypothesis_geometry/actions/workflows/ci.yml \"Github Actions\")\n[![](https://readthedocs.org/projects/hypothesis_geometry/badge/?version=latest)](https://hypothesis-geometry.readthedocs.io/en/latest \"Documentation\")\n[![](https://codecov.io/gh/lycantropos/hypothesis_geometry/branch/master/graph/badge.svg)](https://codecov.io/gh/lycantropos/hypothesis_geometry \"Codecov\")\n[![](https://img.shields.io/github/license/lycantropos/hypothesis_geometry.svg)](https://github.com/lycantropos/hypothesis_geometry/blob/master/LICENSE \"License\")\n[![](https://badge.fury.io/py/hypothesis-geometry.svg)](https://badge.fury.io/py/hypothesis-geometry \"PyPI\")\n\nIn what follows `python` is an alias for `python3.7` or `pypy3.7`\nor any later version (`python3.8`, `pypy3.8` and so on).\n\nInstallation\n------------\n\nInstall the latest `pip` \u0026 `setuptools` packages versions\n```bash\npython -m pip install --upgrade pip setuptools\n```\n\n### User\n\nDownload and install the latest stable version from `PyPI` repository\n```bash\npython -m pip install --upgrade hypothesis_geometry\n```\n\n### Developer\n\nDownload the latest version from `GitHub` repository\n```bash\ngit clone https://github.com/lycantropos/hypothesis_geometry.git\ncd hypothesis_geometry\n```\n\nInstall dependencies\n```bash\npython -m pip install -r requirements.txt\n```\n\nInstall\n```bash\npython setup.py install\n```\n\nUsage\n-----\n\nWith setup\n```python\n\u003e\u003e\u003e from ground.base import get_context\n\u003e\u003e\u003e from hypothesis import strategies\n\u003e\u003e\u003e from hypothesis_geometry import planar\n\u003e\u003e\u003e context = get_context()\n\u003e\u003e\u003e Contour = context.contour_cls\n\u003e\u003e\u003e Empty = context.empty_cls\n\u003e\u003e\u003e Mix = context.mix_cls\n\u003e\u003e\u003e Multipoint = context.multipoint_cls\n\u003e\u003e\u003e Multipolygon = context.multipolygon_cls\n\u003e\u003e\u003e Multisegment = context.multisegment_cls\n\u003e\u003e\u003e Point = context.point_cls\n\u003e\u003e\u003e Polygon = context.polygon_cls\n\u003e\u003e\u003e Segment = context.segment_cls\n\u003e\u003e\u003e min_coordinate, max_coordinate = -100, 100\n\u003e\u003e\u003e coordinates_type = int\n\u003e\u003e\u003e coordinates = strategies.integers(min_coordinate, max_coordinate)\n\u003e\u003e\u003e import warnings\n\u003e\u003e\u003e from hypothesis.errors import NonInteractiveExampleWarning\n\u003e\u003e\u003e # ignore hypothesis warnings caused by `example` method call\n... warnings.filterwarnings('ignore', category=NonInteractiveExampleWarning)\n\n```\nlet's take a look at what can be generated and how.\n\n### Empty geometries\n```python\n\u003e\u003e\u003e empty_geometries = planar.empty_geometries()\n\u003e\u003e\u003e empty = empty_geometries.example()\n\u003e\u003e\u003e isinstance(empty, Empty)\nTrue\n\n```\n\n### Points\n```python\n\u003e\u003e\u003e points = planar.points(coordinates)\n\u003e\u003e\u003e point = points.example()\n\u003e\u003e\u003e isinstance(point, Point)\nTrue\n\u003e\u003e\u003e (isinstance(point.x, coordinates_type)\n...  and isinstance(point.y, coordinates_type))\nTrue\n\u003e\u003e\u003e (min_coordinate \u003c= point.x \u003c= max_coordinate\n...  and min_coordinate \u003c= point.y \u003c= max_coordinate)\nTrue\n\n```\n\n### Multipoints\n```python\n\u003e\u003e\u003e min_size, max_size = 5, 10\n\u003e\u003e\u003e multipoints = planar.multipoints(coordinates,\n...                                  min_size=min_size,\n...                                  max_size=max_size)\n\u003e\u003e\u003e multipoint = multipoints.example()\n\u003e\u003e\u003e isinstance(multipoint, Multipoint)\nTrue\n\u003e\u003e\u003e min_size \u003c= len(multipoint.points) \u003c= max_size\nTrue\n\u003e\u003e\u003e all(isinstance(point.x, coordinates_type)\n...     and isinstance(point.y, coordinates_type)\n...     for point in multipoint.points)\nTrue\n\u003e\u003e\u003e all(min_coordinate \u003c= point.x \u003c= max_coordinate\n...     and min_coordinate \u003c= point.y \u003c= max_coordinate\n...     for point in multipoint.points)\nTrue\n\n```\n\n### Segments\n```python\n\u003e\u003e\u003e segments = planar.segments(coordinates)\n\u003e\u003e\u003e segment = segments.example()\n\u003e\u003e\u003e isinstance(segment, Segment)\nTrue\n\u003e\u003e\u003e (isinstance(segment.start.x, coordinates_type)\n...  and isinstance(segment.start.y, coordinates_type)\n...  and isinstance(segment.end.x, coordinates_type)\n...  and isinstance(segment.end.y, coordinates_type))\nTrue\n\u003e\u003e\u003e (min_coordinate \u003c= segment.start.x \u003c= max_coordinate \n...  and min_coordinate \u003c= segment.start.y \u003c= max_coordinate\n...  and min_coordinate \u003c= segment.end.x \u003c= max_coordinate \n...  and min_coordinate \u003c= segment.end.y \u003c= max_coordinate)\nTrue\n\n```\n\n### Multisegments\n```python\n\u003e\u003e\u003e min_size, max_size = 5, 10\n\u003e\u003e\u003e multisegments = planar.multisegments(coordinates, \n...                                      min_size=min_size,\n...                                      max_size=max_size)\n\u003e\u003e\u003e multisegment = multisegments.example()\n\u003e\u003e\u003e isinstance(multisegment, Multisegment)\nTrue\n\u003e\u003e\u003e min_size \u003c= len(multisegment.segments) \u003c= max_size\nTrue\n\u003e\u003e\u003e all(isinstance(segment.start.x, coordinates_type)\n...     and isinstance(segment.start.y, coordinates_type)\n...     and isinstance(segment.end.x, coordinates_type)\n...     and isinstance(segment.end.y, coordinates_type)\n...     for segment in multisegment.segments)\nTrue\n\u003e\u003e\u003e all(min_coordinate \u003c= segment.start.x \u003c= max_coordinate\n...     and min_coordinate \u003c= segment.start.y \u003c= max_coordinate\n...     and min_coordinate \u003c= segment.end.x \u003c= max_coordinate\n...     and min_coordinate \u003c= segment.end.y \u003c= max_coordinate\n...     for segment in multisegment.segments)\nTrue\n\n```\n\n### Contours\n```python\n\u003e\u003e\u003e min_size, max_size = 5, 10\n\u003e\u003e\u003e contours = planar.contours(coordinates, \n...                            min_size=min_size,\n...                            max_size=max_size)\n\u003e\u003e\u003e contour = contours.example()\n\u003e\u003e\u003e isinstance(contour, Contour)\nTrue\n\u003e\u003e\u003e min_size \u003c= len(contour.vertices) \u003c= max_size\nTrue\n\u003e\u003e\u003e all(isinstance(vertex.x, coordinates_type)\n...     and isinstance(vertex.y, coordinates_type)\n...     for vertex in contour.vertices)\nTrue\n\u003e\u003e\u003e all(min_coordinate \u003c= vertex.x \u003c= max_coordinate\n...     and min_coordinate \u003c= vertex.y \u003c= max_coordinate\n...     for vertex in contour.vertices)\nTrue\n\n```\nalso `planar.concave_contours` \u0026 `planar.convex_contours` options are available.\n\n### Multicontours\n```python\n\u003e\u003e\u003e min_size, max_size = 5, 10\n\u003e\u003e\u003e min_contour_size, max_contour_size = 4, 8\n\u003e\u003e\u003e multicontours = planar.multicontours(coordinates, \n...                                      min_size=min_size,\n...                                      max_size=max_size,\n...                                      min_contour_size=min_contour_size,\n...                                      max_contour_size=max_contour_size)\n\u003e\u003e\u003e multicontour = multicontours.example()\n\u003e\u003e\u003e isinstance(multicontour, list)\nTrue\n\u003e\u003e\u003e all(isinstance(contour, Contour) for contour in multicontour)\nTrue\n\u003e\u003e\u003e min_size \u003c= len(multicontour) \u003c= max_size\nTrue\n\u003e\u003e\u003e all(min_contour_size \u003c= len(contour.vertices) \u003c= max_contour_size\n...     for contour in multicontour)\nTrue\n\u003e\u003e\u003e all(isinstance(vertex.x, coordinates_type)\n...     and isinstance(vertex.y, coordinates_type)\n...     for contour in multicontour\n...     for vertex in contour.vertices)\nTrue\n\u003e\u003e\u003e all(min_coordinate \u003c= vertex.x \u003c= max_coordinate\n...     and min_coordinate \u003c= vertex.y \u003c= max_coordinate\n...     for contour in multicontour\n...     for vertex in contour.vertices)\nTrue\n\n```\n\n### Polygons\n```python\n\u003e\u003e\u003e min_size, max_size = 5, 10\n\u003e\u003e\u003e min_holes_size, max_holes_size = 1, 3\n\u003e\u003e\u003e min_hole_size, max_hole_size = 4, 8\n\u003e\u003e\u003e polygons = planar.polygons(coordinates, \n...                            min_size=min_size,\n...                            max_size=max_size,\n...                            min_holes_size=min_holes_size,\n...                            max_holes_size=max_holes_size,\n...                            min_hole_size=min_hole_size,\n...                            max_hole_size=max_hole_size)\n\u003e\u003e\u003e polygon = polygons.example()\n\u003e\u003e\u003e isinstance(polygon, Polygon)\nTrue\n\u003e\u003e\u003e min_size \u003c= len(polygon.border.vertices) \u003c= max_size\nTrue\n\u003e\u003e\u003e min_holes_size \u003c= len(polygon.holes) \u003c= max_holes_size\nTrue\n\u003e\u003e\u003e all(min_hole_size \u003c= len(hole.vertices) \u003c= max_hole_size for hole in polygon.holes)\nTrue\n\u003e\u003e\u003e polygon_contours = [polygon.border, *polygon.holes]\n\u003e\u003e\u003e all(isinstance(vertex.x, coordinates_type)\n...     and isinstance(vertex.y, coordinates_type)\n...     for contour in polygon_contours\n...     for vertex in contour.vertices)\nTrue\n\u003e\u003e\u003e all(min_coordinate \u003c= vertex.x \u003c= max_coordinate\n...     and min_coordinate \u003c= vertex.y \u003c= max_coordinate\n...     for contour in polygon_contours\n...     for vertex in contour.vertices)\nTrue\n\n```\n\n### Multipolygons\n```python\n\u003e\u003e\u003e min_size, max_size = 2, 5\n\u003e\u003e\u003e min_border_size, max_border_size = 5, 10\n\u003e\u003e\u003e min_holes_size, max_holes_size = 1, 3\n\u003e\u003e\u003e min_hole_size, max_hole_size = 4, 8\n\u003e\u003e\u003e multipolygons = planar.multipolygons(coordinates, \n...                                      min_size=min_size,\n...                                      max_size=max_size,\n...                                      min_border_size=min_border_size,\n...                                      max_border_size=max_border_size,\n...                                      min_holes_size=min_holes_size,\n...                                      max_holes_size=max_holes_size,\n...                                      min_hole_size=min_hole_size,\n...                                      max_hole_size=max_hole_size)\n\u003e\u003e\u003e multipolygon = multipolygons.example()\n\u003e\u003e\u003e isinstance(multipolygon, Multipolygon)\nTrue\n\u003e\u003e\u003e min_size \u003c= len(multipolygon.polygons) \u003c= max_size\nTrue\n\u003e\u003e\u003e all(min_border_size \u003c= len(polygon.border.vertices) \u003c= max_border_size\n...     and min_holes_size \u003c= len(polygon.holes) \u003c= max_holes_size\n...     and all(min_hole_size \u003c= len(hole.vertices) \u003c= max_hole_size\n...             for hole in polygon.holes)\n...     for polygon in multipolygon.polygons)\nTrue\n\u003e\u003e\u003e all(all(isinstance(vertex.x, coordinates_type)\n...         and isinstance(vertex.y, coordinates_type)\n...         for vertex in polygon.border.vertices)\n...     and all(isinstance(vertex.x, coordinates_type)\n...             and isinstance(vertex.y, coordinates_type)\n...             for hole in polygon.holes\n...             for vertex in hole.vertices)\n...     for polygon in multipolygon.polygons)\nTrue\n\u003e\u003e\u003e all(all(min_coordinate \u003c= vertex.x \u003c= max_coordinate\n...         and min_coordinate \u003c= vertex.y \u003c= max_coordinate\n...         for vertex in polygon.border.vertices)\n...     and all(min_coordinate \u003c= vertex.x \u003c= max_coordinate\n...             and min_coordinate \u003c= vertex.y \u003c= max_coordinate\n...             for hole in polygon.holes\n...             for vertex in hole.vertices)\n...     for polygon in multipolygon.polygons)\nTrue\n\n```\n\n### Mixes\n```python\n\u003e\u003e\u003e min_points_size, max_points_size = 2, 3\n\u003e\u003e\u003e min_segments_size, max_segments_size = 1, 4\n\u003e\u003e\u003e min_polygons_size, max_polygons_size = 0, 5\n\u003e\u003e\u003e min_polygon_border_size, max_polygon_border_size = 5, 10\n\u003e\u003e\u003e min_polygon_holes_size, max_polygon_holes_size = 1, 4\n\u003e\u003e\u003e min_polygon_hole_size, max_polygon_hole_size = 3, 5\n\u003e\u003e\u003e mixes = planar.mixes(coordinates,\n...                      min_points_size=min_points_size,\n...                      max_points_size=max_points_size,\n...                      min_segments_size=min_segments_size,\n...                      max_segments_size=max_segments_size,\n...                      min_polygons_size=min_polygons_size,\n...                      max_polygons_size=max_polygons_size,\n...                      min_polygon_border_size=min_polygon_border_size,\n...                      max_polygon_border_size=max_polygon_border_size,\n...                      min_polygon_holes_size=min_polygon_holes_size,\n...                      max_polygon_holes_size=max_polygon_holes_size,\n...                      min_polygon_hole_size=min_polygon_hole_size,\n...                      max_polygon_hole_size=max_polygon_hole_size)\n\u003e\u003e\u003e mix = mixes.example()\n\u003e\u003e\u003e isinstance(mix, Mix)\nTrue\n\u003e\u003e\u003e isinstance(mix.discrete, (Empty, Multipoint))\nTrue\n\u003e\u003e\u003e points = [] if isinstance(mix.discrete, Empty) else mix.discrete.points\n\u003e\u003e\u003e min_points_size \u003c= len(points) \u003c= max_points_size\nTrue\n\u003e\u003e\u003e all(isinstance(point.x, coordinates_type)\n...     and isinstance(point.y, coordinates_type)\n...     for point in points)\nTrue\n\u003e\u003e\u003e all(min_coordinate \u003c= point.x \u003c= max_coordinate\n...     and min_coordinate \u003c= point.y \u003c= max_coordinate\n...     for point in points)\nTrue\n\u003e\u003e\u003e isinstance(mix.linear, (Empty, Segment, Contour, Multisegment))\nTrue\n\u003e\u003e\u003e segments = ([]\n...             if isinstance(mix.linear, Empty)\n...             else ([mix.linear]\n...                   if isinstance(mix.linear, Segment)\n...                   else (mix.linear.segments\n...                         if isinstance(mix.linear, Multisegment)\n...                         else context.contour_edges(mix.linear))))\n\u003e\u003e\u003e min_segments_size \u003c= len(segments) \u003c= max_segments_size\nTrue\n\u003e\u003e\u003e all(isinstance(segment.start.x, coordinates_type)\n...     and isinstance(segment.start.y, coordinates_type)\n...     and isinstance(segment.end.x, coordinates_type)\n...     and isinstance(segment.end.y, coordinates_type)\n...     for segment in segments)\nTrue\n\u003e\u003e\u003e all(min_coordinate \u003c= segment.start.x \u003c= max_coordinate\n...     and min_coordinate \u003c= segment.start.y \u003c= max_coordinate\n...     and min_coordinate \u003c= segment.end.x \u003c= max_coordinate\n...     and min_coordinate \u003c= segment.end.y \u003c= max_coordinate\n...     for segment in segments)\nTrue\n\u003e\u003e\u003e isinstance(mix.shaped, (Empty, Polygon, Multipolygon))\nTrue\n\u003e\u003e\u003e polygons = ([]\n...             if isinstance(mix.shaped, Empty)\n...             else ([mix.shaped]\n...                   if isinstance(mix.shaped, Polygon)\n...                   else mix.shaped.polygons))\n\u003e\u003e\u003e min_polygons_size \u003c= len(polygons) \u003c= max_polygons_size\nTrue\n\u003e\u003e\u003e all(min_polygon_border_size\n...     \u003c= len(polygon.border.vertices)\n...     \u003c= max_polygon_border_size\n...     and (min_polygon_holes_size\n...          \u003c= len(polygon.holes)\n...          \u003c= max_polygon_holes_size)\n...     and all(min_polygon_hole_size\n...             \u003c= len(hole.vertices)\n...             \u003c= max_polygon_hole_size\n...             for hole in polygon.holes)\n...     for polygon in polygons)\nTrue\n\u003e\u003e\u003e all(all(isinstance(vertex.x, coordinates_type)\n...         and isinstance(vertex.y, coordinates_type)\n...         for vertex in polygon.border.vertices)\n...     and all(isinstance(vertex.x, coordinates_type)\n...             and isinstance(vertex.y, coordinates_type)\n...             for hole in polygon.holes\n...             for vertex in hole.vertices)\n...     for polygon in polygons)\nTrue\n\u003e\u003e\u003e all(all(min_coordinate \u003c= vertex.x \u003c= max_coordinate\n...         and min_coordinate \u003c= vertex.y \u003c= max_coordinate\n...         for vertex in polygon.border.vertices)\n...     and all(min_coordinate \u003c= vertex.x \u003c= max_coordinate\n...             and min_coordinate \u003c= vertex.y \u003c= max_coordinate\n...             for hole in polygon.holes\n...             for vertex in hole.vertices)\n...     for polygon in polygons)\nTrue\n\n```\n\n#### Caveats\n- Strategies may be slow depending on domain,\nso it may be necessary to add `HealthCheck.filter_too_much`, `HealthCheck.too_slow`\nin [`suppress_health_check`](https://hypothesis.readthedocs.io/en/latest/settings.html#hypothesis.settings.suppress_health_check) \nand set [`deadline`](https://hypothesis.readthedocs.io/en/latest/settings.html#hypothesis.settings.deadline) to `None`.\n\n- Unbounded floating point strategies for coordinates \n(like [`hypothesis.strategies.floats`](https://hypothesis.readthedocs.io/en/latest/data.html#hypothesis.strategies.floats)\nwith unset `min_value`/`max_value`) do not play well with bounded sizes \nand may cause a lot of searching iterations with no success,\nso it is recommended to use bounded floating point coordinates with bounded sizes\nor unbounded coordinates with unbounded sizes.\n\n- [`decimal.Decimal`](https://docs.python.org/library/decimal.html) coordinates are not supported, because \nthey seem to be too hard to work with correctly (e.g. sometimes self-intersecting contours arise), \nso it is suggested to use `float`  or [`fractions.Fraction`](https://docs.python.org/library/fractions.html) instead.\n\nDevelopment\n-----------\n\n### Bumping version\n\n#### Preparation\n\nInstall\n[bump2version](https://github.com/c4urself/bump2version#installation).\n\n#### Pre-release\n\nChoose which version number category to bump following [semver\nspecification](http://semver.org/).\n\nTest bumping version\n```bash\nbump2version --dry-run --verbose $CATEGORY\n```\n\nwhere `$CATEGORY` is the target version number category name, possible\nvalues are `patch`/`minor`/`major`.\n\nBump version\n```bash\nbump2version --verbose $CATEGORY\n```\n\nThis will set version to `major.minor.patch-alpha`. \n\n#### Release\n\nTest bumping version\n```bash\nbump2version --dry-run --verbose release\n```\n\nBump version\n```bash\nbump2version --verbose release\n```\n\nThis will set version to `major.minor.patch`.\n\n### Running tests\n\nInstall dependencies\n```bash\npython -m pip install -r requirements-tests.txt\n```\n\nPlain\n```bash\npytest\n```\n\nInside `Docker` container:\n- with `CPython`\n  ```bash\n  docker-compose --file docker-compose.cpython.yml up\n  ```\n- with `PyPy`\n  ```bash\n  docker-compose --file docker-compose.pypy.yml up\n  ```\n\n`Bash` script:\n- with `CPython`\n  ```bash\n  ./run-tests.sh\n  ```\n  or\n  ```bash\n  ./run-tests.sh cpython\n  ```\n\n- with `PyPy`\n  ```bash\n  ./run-tests.sh pypy\n  ```\n\n`PowerShell` script:\n- with `CPython`\n  ```powershell\n  .\\run-tests.ps1\n  ```\n  or\n  ```powershell\n  .\\run-tests.ps1 cpython\n  ```\n- with `PyPy`\n  ```powershell\n  .\\run-tests.ps1 pypy\n  ```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flycantropos%2Fhypothesis_geometry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flycantropos%2Fhypothesis_geometry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flycantropos%2Fhypothesis_geometry/lists"}