Skip to content

Commit

Permalink
Modernize code (#218)
Browse files Browse the repository at this point in the history
* Use f-strings

* Use integers where appropriate

* Refactor generate_random
  • Loading branch information
eumiro authored Oct 4, 2024
1 parent a3a4437 commit fe284f1
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 69 deletions.
10 changes: 5 additions & 5 deletions geojson/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion geojson/codec.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
2 changes: 1 addition & 1 deletion geojson/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
100 changes: 44 additions & 56 deletions geojson/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}


Expand Down Expand Up @@ -125,11 +125,11 @@ 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,
boundingBox=[-180.0, -90.0, 180.0, 90.0]):
boundingBox=[-180, -90, 180, 90]):
"""
Generates random geojson features depending on the parameters
passed through.
Expand All @@ -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.")
2 changes: 1 addition & 1 deletion tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
10 changes: 5 additions & 5 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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))
Expand Down

0 comments on commit fe284f1

Please sign in to comment.