From 0a647d1c6ade115df96d8ec121ad275a76498407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= <6774676+eumiro@users.noreply.github.com> Date: Sat, 15 Jul 2023 20:10:51 +0200 Subject: [PATCH 1/3] Use f-strings --- geojson/base.py | 10 +++++----- geojson/codec.py | 2 +- geojson/geometry.py | 2 +- geojson/utils.py | 4 ++-- tests/__init__.py | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/geojson/base.py b/geojson/base.py index 37a316e..380f4a2 100644 --- a/geojson/base.py +++ b/geojson/base.py @@ -107,15 +107,15 @@ def to_instance(cls, ob, default=None, strict=False): except UnicodeEncodeError: # If the type contains non-ascii characters, we can assume # it's not a valid GeoJSON type - raise AttributeError( - "{0} is not a GeoJSON type").format(type_) + raise AttributeError(f"{type_} is not a GeoJSON type") geojson_factory = getattr(geojson.factory, type_) instance = geojson_factory(**d) except (AttributeError, KeyError) as invalid: if strict: - msg = "Cannot coerce %r into a valid GeoJSON structure: %s" - msg %= (ob, invalid) - raise ValueError(msg) + raise ValueError( + f"Cannot coerce {ob!r} into " + f"a valid GeoJSON structure: {invalid}" + ) instance = ob return instance diff --git a/geojson/codec.py b/geojson/codec.py index 00ada79..20d8f8e 100644 --- a/geojson/codec.py +++ b/geojson/codec.py @@ -19,7 +19,7 @@ def default(self, obj): # Here the defaults are set to only permit valid JSON as per RFC 4267 def _enforce_strict_numbers(obj): - raise ValueError("Number %r is not JSON compliant" % obj) + raise ValueError(f"Number {obj!r} is not JSON compliant") def dump(obj, fp, cls=GeoJSONEncoder, allow_nan=False, **kwargs): diff --git a/geojson/geometry.py b/geojson/geometry.py index f22db60..19fc4a7 100755 --- a/geojson/geometry.py +++ b/geojson/geometry.py @@ -50,7 +50,7 @@ def clean_coordinates(cls, coords, precision): elif isinstance(coord, (Real, Decimal)): new_coords.append(round(coord, precision)) else: - raise ValueError("%r is not a JSON compliant number" % coord) + raise ValueError(f"{coord!r} is not a JSON compliant number") return new_coords diff --git a/geojson/utils.py b/geojson/utils.py index ae6debc..aa63c96 100644 --- a/geojson/utils.py +++ b/geojson/utils.py @@ -87,7 +87,7 @@ def map_tuples(func, obj): elif obj['type'] in ['Feature', 'FeatureCollection', 'GeometryCollection']: return map_geometries(lambda g: map_tuples(func, g), obj) else: - raise ValueError("Invalid geometry object %s" % repr(obj)) + raise ValueError(f"Invalid geometry object {obj!r}") return {'type': obj['type'], 'coordinates': coordinates} @@ -125,7 +125,7 @@ def map_geometries(func, obj): feats = [map_geometries(func, feat) for feat in obj['features']] return {'type': obj['type'], 'features': feats} else: - raise ValueError("Invalid GeoJSON object %s" % repr(obj)) + raise ValueError(f"Invalid GeoJSON object {obj!r}") def generate_random(featureType, numberVertices=3, diff --git a/tests/__init__.py b/tests/__init__.py index 4efcb7b..41e3f50 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -7,6 +7,6 @@ doctest.ELLIPSIS) _basedir = os.path.dirname(__file__) -paths = glob.glob("%s/*.txt" % _basedir) +paths = glob.glob(f"{_basedir}/*.txt") test_suite = doctest.DocFileSuite(*paths, **dict(module_relative=False, optionflags=optionflags)) From a1e36faa131cfe6e9af4e3c5e77b0cb780601aeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= <6774676+eumiro@users.noreply.github.com> Date: Sat, 15 Jul 2023 20:11:13 +0200 Subject: [PATCH 2/3] Use integers where appropriate --- geojson/utils.py | 2 +- tests/test_utils.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/geojson/utils.py b/geojson/utils.py index aa63c96..4d0dd5f 100644 --- a/geojson/utils.py +++ b/geojson/utils.py @@ -129,7 +129,7 @@ def map_geometries(func, obj): def generate_random(featureType, numberVertices=3, - boundingBox=[-180.0, -90.0, 180.0, 90.0]): + boundingBox=[-180, -90, 180, 90]): """ Generates random geojson features depending on the parameters passed through. diff --git a/tests/test_utils.py b/tests/test_utils.py index 5339cb8..58d9f04 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -10,12 +10,12 @@ def generate_bbox(): - min_lat = random.random() * 180.0 - 90.0 - max_lat = random.random() * 180.0 - 90.0 + min_lat = random.random() * 180 - 90 + max_lat = random.random() * 180 - 90 if min_lat > max_lat: min_lat, max_lat = max_lat, min_lat - min_lon = random.random() * 360.0 - 180.0 - max_lon = random.random() * 360.0 - 180.0 + min_lon = random.random() * 360 - 180 + max_lon = random.random() * 360 - 180 if min_lon > max_lon: min_lon, max_lon = max_lon, min_lon return [min_lon, min_lat, max_lon, max_lat] @@ -46,7 +46,7 @@ def check_point_bbox(point, bbox): class TestGenerateRandom(unittest.TestCase): def test_simple_polygon(self): for _ in range(5000): - bbox = [-180.0, -90.0, 180.0, 90.0] + bbox = [-180, -90, 180, 90] result = generate_random('Polygon') self.assertIsInstance(result, geojson.geometry.Polygon) self.assertTrue(geojson.geometry.check_polygon(result)) From c8a63c17982d582129458a9eaf0483982e562947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= <6774676+eumiro@users.noreply.github.com> Date: Sat, 15 Jul 2023 20:11:31 +0200 Subject: [PATCH 3/3] Refactor generate_random --- geojson/utils.py | 94 +++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 53 deletions(-) diff --git a/geojson/utils.py b/geojson/utils.py index 4d0dd5f..c80f893 100644 --- a/geojson/utils.py +++ b/geojson/utils.py @@ -152,79 +152,67 @@ def generate_random(featureType, numberVertices=3, import random import math - lonMin = boundingBox[0] - lonMax = boundingBox[2] + lon_min, lat_min, lon_max, lat_max = boundingBox - def randomLon(): - return random.uniform(lonMin, lonMax) + def random_lon(): + return random.uniform(lon_min, lon_max) - latMin = boundingBox[1] - latMax = boundingBox[3] + def random_lat(): + return random.uniform(lat_min, lat_max) - def randomLat(): - return random.uniform(latMin, latMax) + def create_point(): + return Point((random_lon(), random_lat())) - def createPoint(): - return Point((randomLon(), randomLat())) + def create_line(): + return LineString([create_point() for _ in range(numberVertices)]) - def createLine(): - return LineString([createPoint() for unused in range(numberVertices)]) + def create_poly(): + ave_radius = 60 + ctr_x = 0.1 + ctr_y = 0.2 + irregularity = clip(0.1, 0, 1) * math.tau / numberVertices + spikeyness = clip(0.5, 0, 1) * ave_radius - def createPoly(): - aveRadius = 60 - ctrX = 0.1 - ctrY = 0.2 - irregularity = clip(0.1, 0, 1) * 2 * math.pi / numberVertices - spikeyness = clip(0.5, 0, 1) * aveRadius + lower = (math.tau / numberVertices) - irregularity + upper = (math.tau / numberVertices) + irregularity + angle_steps = [] + for _ in range(numberVertices): + angle_steps.append(random.uniform(lower, upper)) + sum_angle = sum(angle_steps) - angleSteps = [] - lower = (2 * math.pi / numberVertices) - irregularity - upper = (2 * math.pi / numberVertices) + irregularity - sum = 0 - for i in range(numberVertices): - tmp = random.uniform(lower, upper) - angleSteps.append(tmp) - sum = sum + tmp - - k = sum / (2 * math.pi) - for i in range(numberVertices): - angleSteps[i] = angleSteps[i] / k + k = sum_angle / math.tau + angle_steps = [x / k for x in angle_steps] points = [] - angle = random.uniform(0, 2 * math.pi) - - for i in range(numberVertices): - r_i = clip(random.gauss(aveRadius, spikeyness), 0, 2 * aveRadius) - x = ctrX + r_i * math.cos(angle) - y = ctrY + r_i * math.sin(angle) - x = (x + 180.0) * (abs(lonMin-lonMax) / 360.0) + lonMin - y = (y + 90.0) * (abs(latMin-latMax) / 180.0) + latMin - x = clip(x, lonMin, lonMax) - y = clip(y, latMin, latMax) + angle = random.uniform(0, math.tau) + + for angle_step in angle_steps: + r_i = clip(random.gauss(ave_radius, spikeyness), 0, 2 * ave_radius) + x = ctr_x + r_i * math.cos(angle) + y = ctr_y + r_i * math.sin(angle) + x = (x + 180) * (abs(lon_min - lon_max) / 360) + lon_min + y = (y + 90) * (abs(lat_min - lat_max) / 180) + lat_min + x = clip(x, lon_min, lon_max) + y = clip(y, lat_min, lat_max) points.append((x, y)) - angle = angle + angleSteps[i] + angle += angle_step - firstVal = points[0] - points.append(firstVal) + points.append(points[0]) # append first point to the end return Polygon([points]) - def clip(x, min, max): - if min > max: + def clip(x, min_val, max_val): + if min_val > max_val: return x - elif x < min: - return min - elif x > max: - return max else: - return x + return min(max(min_val, x), max_val) if featureType == 'Point': - return createPoint() + return create_point() if featureType == 'LineString': - return createLine() + return create_line() if featureType == 'Polygon': - return createPoly() + return create_poly() raise ValueError(f"featureType: {featureType} is not supported.")