hypothesis strategies for geometric objects (points, polygons, etc.).
Project description
hypothesis_geometry
In what follows python
is an alias for python3.5
or pypy3.5
or any later version (python3.6
, pypy3.6
and so on).
Installation
Install the latest pip
& setuptools
packages versions
python -m pip install --upgrade pip setuptools
User
Download and install the latest stable version from PyPI
repository:
python -m pip install --upgrade hypothesis_geometry
Developer
Download the latest version from GitHub
repository
git clone https://github.com/lycantropos/hypothesis_geometry.git
cd hypothesis_geometry
Install dependencies
python -m pip install --force-reinstall -r requirements.txt
Install
python setup.py install
Usage
With setup
>>> from hypothesis import strategies
>>> from hypothesis_geometry import planar
>>> min_coordinate, max_coordinate = -100, 100
>>> coordinates_type = int
>>> coordinates = strategies.integers(min_coordinate, max_coordinate)
>>> import warnings
>>> from hypothesis.errors import NonInteractiveExampleWarning
>>> # ignore hypothesis warnings caused by `example` method call
... warnings.filterwarnings('ignore', category=NonInteractiveExampleWarning)
let's take a look at what can be generated and how.
Points
>>> points = planar.points(coordinates)
>>> point = points.example()
>>> isinstance(point, tuple)
True
>>> len(point) == 2
True
>>> all(isinstance(coordinate, coordinates_type) for coordinate in point)
True
>>> all(min_coordinate <= coordinate <= max_coordinate for coordinate in point)
True
Segments
>>> segments = planar.segments(coordinates)
>>> segment = segments.example()
>>> isinstance(segment, tuple)
True
>>> len(segment) == 2
True
>>> all(isinstance(endpoint, tuple) for endpoint in segment)
True
>>> all(len(endpoint) == 2 for endpoint in segment)
True
>>> all(isinstance(coordinate, coordinates_type)
... for endpoint in segment
... for coordinate in endpoint)
True
>>> all(min_coordinate <= coordinate <= max_coordinate
... for endpoint in segment
... for coordinate in endpoint)
True
Multisegments
>>> min_size, max_size = 5, 10
>>> multisegments = planar.multisegments(coordinates,
... min_size=min_size,
... max_size=max_size)
>>> multisegment = multisegments.example()
>>> isinstance(multisegment, list)
True
>>> min_size <= len(multisegment) <= max_size
True
>>> all(isinstance(segment, tuple)
... for segment in multisegment)
True
>>> all(isinstance(endpoint, tuple)
... for segment in multisegment
... for endpoint in segment)
True
>>> all(len(segment) == 2 for segment in multisegment)
True
>>> all(len(endpoint) == 2
... for segment in multisegment
... for endpoint in segment)
True
>>> all(isinstance(coordinate, coordinates_type)
... for segment in multisegment
... for endpoint in segment
... for coordinate in endpoint)
True
>>> all(min_coordinate <= coordinate <= max_coordinate
... for segment in multisegment
... for endpoint in segment
... for coordinate in endpoint)
True
Polylines
>>> min_size, max_size = 5, 10
>>> polylines = planar.polylines(coordinates,
... min_size=min_size,
... max_size=max_size)
>>> polyline = polylines.example()
>>> isinstance(polyline, list)
True
>>> min_size <= len(polyline) <= max_size
True
>>> all(isinstance(vertex, tuple) for vertex in polyline)
True
>>> all(len(vertex) == 2 for vertex in polyline)
True
>>> all(isinstance(coordinate, coordinates_type)
... for vertex in polyline
... for coordinate in vertex)
True
>>> all(min_coordinate <= coordinate <= max_coordinate
... for vertex in polyline
... for coordinate in vertex)
True
Contours
>>> min_size, max_size = 5, 10
>>> contours = planar.contours(coordinates,
... min_size=min_size,
... max_size=max_size)
>>> contour = contours.example()
>>> isinstance(contour, list)
True
>>> min_size <= len(contour) <= max_size
True
>>> all(isinstance(vertex, tuple) for vertex in contour)
True
>>> all(len(vertex) == 2 for vertex in contour)
True
>>> all(isinstance(coordinate, coordinates_type)
... for vertex in contour
... for coordinate in vertex)
True
>>> all(min_coordinate <= coordinate <= max_coordinate
... for vertex in contour
... for coordinate in vertex)
True
also planar.concave_contours
& planar.convex_contours
options are available.
Multicontours
>>> min_size, max_size = 5, 10
>>> min_contour_size, max_contour_size = 4, 8
>>> multicontours = planar.multicontours(coordinates,
... min_size=min_size,
... max_size=max_size,
... min_contour_size=min_contour_size,
... max_contour_size=max_contour_size)
>>> multicontour = multicontours.example()
>>> isinstance(multicontour, list)
True
>>> all(isinstance(contour, list) for contour in multicontour)
True
>>> min_size <= len(multicontour) <= max_size
True
>>> all(min_contour_size <= len(contour) <= max_contour_size
... for contour in multicontour)
True
>>> all(isinstance(vertex, tuple)
... for contour in multicontour
... for vertex in contour)
True
>>> all(len(vertex) == 2
... for contour in multicontour
... for vertex in contour)
True
>>> all(isinstance(coordinate, coordinates_type)
... for contour in multicontour
... for vertex in contour
... for coordinate in vertex)
True
>>> all(min_coordinate <= coordinate <= max_coordinate
... for contour in multicontour
... for vertex in contour
... for coordinate in vertex)
True
Polygons
>>> min_size, max_size = 5, 10
>>> min_holes_size, max_holes_size = 1, 3
>>> min_hole_size, max_hole_size = 4, 8
>>> polygons = planar.polygons(coordinates,
... min_size=min_size,
... max_size=max_size,
... min_holes_size=min_holes_size,
... max_holes_size=max_holes_size,
... min_hole_size=min_hole_size,
... max_hole_size=max_hole_size)
>>> polygon = polygons.example()
>>> isinstance(polygon, tuple)
True
>>> len(polygon) == 2
True
>>> border, holes = polygon
>>> isinstance(border, list)
True
>>> all(isinstance(hole, list) for hole in holes)
True
>>> min_size <= len(border) <= max_size
True
>>> min_holes_size <= len(holes) <= max_holes_size
True
>>> all(min_hole_size <= len(hole) <= max_hole_size for hole in holes)
True
>>> contours = [border, *holes]
>>> all(isinstance(vertex, tuple)
... for contour in contours
... for vertex in contour)
True
>>> all(len(vertex) == 2
... for contour in contours
... for vertex in contour)
True
>>> all(isinstance(coordinate, coordinates_type)
... for contour in contours
... for vertex in contour
... for coordinate in vertex)
True
>>> all(min_coordinate <= coordinate <= max_coordinate
... for contour in contours
... for vertex in contour
... for coordinate in vertex)
True
Multipolygons
>>> min_size, max_size = 0, 5
>>> min_border_size, max_border_size = 5, 10
>>> min_holes_size, max_holes_size = 1, 3
>>> min_hole_size, max_hole_size = 4, 8
>>> multipolygons = planar.multipolygons(coordinates,
... min_size=min_size,
... max_size=max_size,
... min_border_size=min_border_size,
... max_border_size=max_border_size,
... min_holes_size=min_holes_size,
... max_holes_size=max_holes_size,
... min_hole_size=min_hole_size,
... max_hole_size=max_hole_size)
>>> multipolygon = multipolygons.example()
>>> isinstance(multipolygon, list)
True
>>> min_size <= len(multipolygon) <= max_size
True
>>> all(isinstance(polygon, tuple) for polygon in multipolygon)
True
>>> all(len(polygon) == 2 for polygon in multipolygon)
True
>>> all(isinstance(border, list)
... and isinstance(holes, list)
... and all(isinstance(hole, list) for hole in holes)
... for border, holes in multipolygon)
True
>>> all(min_border_size <= len(border) <= max_border_size
... and min_holes_size <= len(holes) <= max_holes_size
... and all(min_hole_size <= len(hole) <= max_hole_size
... for hole in holes)
... for border, holes in multipolygon)
True
>>> all(all(isinstance(vertex, tuple) for vertex in border)
... and all(isinstance(vertex, tuple)
... for hole in holes
... for vertex in hole)
... for border, holes in multipolygon)
True
>>> all(all(len(vertex) == 2 for vertex in border)
... and all(len(vertex) == 2 for hole in holes for vertex in hole)
... for border, holes in multipolygon)
True
>>> all(all(isinstance(coordinate, coordinates_type)
... for vertex in border
... for coordinate in vertex)
... and all(isinstance(coordinate, coordinates_type)
... for hole in holes
... for vertex in hole
... for coordinate in vertex)
... for border, holes in multipolygon)
True
>>> all(all(all(min_coordinate <= coordinate <= max_coordinate
... for coordinate in vertex)
... for vertex in border)
... and all(min_coordinate <= coordinate <= max_coordinate
... for hole in holes
... for vertex in hole
... for coordinate in vertex)
... for border, holes in multipolygon)
True
Mixes
>>> min_multipoint_size, max_multipoint_size = 2, 3
>>> min_multisegment_size, max_multisegment_size = 1, 4
>>> min_multipolygon_size, max_multipolygon_size = 0, 5
>>> min_multipolygon_border_size, max_multipolygon_border_size = 5, 10
>>> min_multipolygon_holes_size, max_multipolygon_holes_size = 1, 4
>>> min_multipolygon_hole_size, max_multipolygon_hole_size = 3, 5
>>> mixes = planar.mixes(coordinates,
... min_multipoint_size=min_multipoint_size,
... max_multipoint_size=max_multipoint_size,
... min_multisegment_size=min_multisegment_size,
... max_multisegment_size=max_multisegment_size,
... min_multipolygon_size=min_multipolygon_size,
... max_multipolygon_size=max_multipolygon_size,
... min_multipolygon_border_size=min_multipolygon_border_size,
... max_multipolygon_border_size=max_multipolygon_border_size,
... min_multipolygon_holes_size=min_multipolygon_holes_size,
... max_multipolygon_holes_size=max_multipolygon_holes_size,
... min_multipolygon_hole_size=min_multipolygon_hole_size,
... max_multipolygon_hole_size=max_multipolygon_hole_size)
>>> mix = mixes.example()
>>> isinstance(mix, tuple)
True
>>> len(mix) == 3
True
>>> multipoint, multisegment, multipolygon = mix
>>> isinstance(multipoint, list)
True
>>> min_multipoint_size <= len(multipoint) <= max_multipoint_size
True
>>> all(isinstance(point, tuple) for point in multipoint)
True
>>> all(len(point) == 2 for point in multipoint)
True
>>> all(isinstance(coordinate, coordinates_type)
... for point in multipoint
... for coordinate in point)
True
>>> all(min_coordinate <= coordinate <= max_coordinate
... for point in multipoint
... for coordinate in point)
True
>>> isinstance(multisegment, list)
True
>>> min_multisegment_size <= len(multisegment) <= max_multisegment_size
True
>>> all(isinstance(segment, tuple) for segment in multisegment)
True
>>> all(isinstance(endpoint, tuple)
... for segment in multisegment
... for endpoint in segment)
True
>>> all(len(segment) == 2 for segment in multisegment)
True
>>> all(len(endpoint) == 2
... for segment in multisegment
... for endpoint in segment)
True
>>> all(isinstance(coordinate, coordinates_type)
... for segment in multisegment
... for endpoint in segment
... for coordinate in endpoint)
True
>>> all(min_coordinate <= coordinate <= max_coordinate
... for segment in multisegment
... for endpoint in segment
... for coordinate in endpoint)
True
>>> isinstance(multipolygon, list)
True
>>> min_multipolygon_size <= len(multipolygon) <= max_multipolygon_size
True
>>> all(isinstance(polygon, tuple) for polygon in multipolygon)
True
>>> all(len(polygon) == 2 for polygon in multipolygon)
True
>>> all(isinstance(border, list)
... and isinstance(holes, list)
... and all(isinstance(hole, list) for hole in holes)
... for border, holes in multipolygon)
True
>>> all(min_multipolygon_border_size
... <= len(border)
... <= max_multipolygon_border_size
... and (min_multipolygon_holes_size
... <= len(holes)
... <= max_multipolygon_holes_size)
... and all(min_multipolygon_hole_size
... <= len(hole)
... <= max_multipolygon_hole_size
... for hole in holes)
... for border, holes in multipolygon)
True
>>> all(all(isinstance(vertex, tuple) for vertex in border)
... and all(isinstance(vertex, tuple)
... for hole in holes
... for vertex in hole)
... for border, holes in multipolygon)
True
>>> all(all(len(vertex) == 2 for vertex in border)
... and all(len(vertex) == 2 for hole in holes for vertex in hole)
... for border, holes in multipolygon)
True
>>> all(all(isinstance(coordinate, coordinates_type)
... for vertex in border
... for coordinate in vertex)
... and all(isinstance(coordinate, coordinates_type)
... for hole in holes
... for vertex in hole
... for coordinate in vertex)
... for border, holes in multipolygon)
True
>>> all(all(all(min_coordinate <= coordinate <= max_coordinate
... for coordinate in vertex)
... for vertex in border)
... and all(min_coordinate <= coordinate <= max_coordinate
... for hole in holes
... for vertex in hole
... for coordinate in vertex)
... for border, holes in multipolygon)
True
Caveats
-
Strategies may be slow depending on domain, so it may be necessary to add
HealthCheck.filter_too_much
,HealthCheck.too_slow
insuppress_health_check
and setdeadline
toNone
. -
Unbounded floating point strategies for coordinates (like
hypothesis.strategies.floats
with unsetmin_value
/max_value
) do not play well with bounded sizes and may cause a lot of searching iterations with no success, so it is recommended to use bounded floating point coordinates with bounded sizes or unbounded coordinates with unbounded sizes. -
decimal.Decimal
coordinates are not supported, because they seem to be too hard to work with correctly (e.g. sometimes self-intersecting contours arise), so it is suggested to usefloat
orfractions.Fraction
instead.
Development
Bumping version
Preparation
Install bump2version.
Pre-release
Choose which version number category to bump following semver specification.
Test bumping version
bump2version --dry-run --verbose $CATEGORY
where $CATEGORY
is the target version number category name, possible
values are patch
/minor
/major
.
Bump version
bump2version --verbose $CATEGORY
This will set version to major.minor.patch-alpha
.
Release
Test bumping version
bump2version --dry-run --verbose release
Bump version
bump2version --verbose release
This will set version to major.minor.patch
.
Running tests
Install dependencies
python -m pip install --force-reinstall -r requirements-tests.txt
Plain
pytest
Inside Docker
container:
- with
CPython
docker-compose --file docker-compose.cpython.yml up
- with
PyPy
docker-compose --file docker-compose.pypy.yml up
Bash
script (e.g. can be used in Git
hooks):
-
with
CPython
./run-tests.sh
or
./run-tests.sh cpython
-
with
PyPy
./run-tests.sh pypy
PowerShell
script (e.g. can be used in Git
hooks):
- with
CPython
.\run-tests.ps1
or.\run-tests.ps1 cpython
- with
PyPy
.\run-tests.ps1 pypy
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for hypothesis_geometry-0.17.2.tar.gz
Algorithm | Hash digest | |
---|---|---|
SHA256 | dced87bf533d45dff5f281e82bb276664320a76cc7f74a5b26f782732b255771 |
|
MD5 | ba78681c9efa053bd852a18c7b766385 |
|
BLAKE2b-256 | f927cee62f0e34e8709835486c639092a25bac5df89303b36e3131dec06b4b0e |
Hashes for hypothesis_geometry-0.17.2-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | c5711bb54181b3950af4b4cafe31acc8ba120a4c433a3c6f4f7c330c19d9664b |
|
MD5 | 2dcd7d93751f983a17f01642da438cb4 |
|
BLAKE2b-256 | 9623d8dffc2284b0231f0650c95132c7441716afccbae2621dc24deb637682f7 |