Skip to content

Commit

Permalink
Data 2025a (#266)
Browse files Browse the repository at this point in the history
* Update .pre-commit-config.yaml

* Update .pre-commit-config.yaml

* update file_converter.py for h3>4

* run pre commit hooks

* version 6.5.8

* end json files with newlines

* Update poetry.lock

* update data 2025a

* refactor file converter json io

* install build dependency group

* bugfix cbuildwheel missing poetry

* remove build dependency group
  • Loading branch information
jannikmi authored Jan 22, 2025
1 parent 056d91f commit 17ece10
Show file tree
Hide file tree
Showing 20 changed files with 639 additions and 575 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,6 @@ jobs:
- name: "Checkout repo"
uses: actions/checkout@v4

- name: Install poetry
run: pip install poetry

- name: "Build wheels"
uses: pypa/[email protected]
with:
Expand Down
14 changes: 7 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v5.0.0
hooks:
- id: check-ast # Is it valid Python?
- id: debug-statements # no debbuging statements used
Expand All @@ -19,15 +19,15 @@ repos:


- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.6
rev: v0.9.2
hooks:
# linter.
- id: ruff
args: [ --fix ]
- id: ruff-format

- repo: https://github.com/asottile/blacken-docs
rev: 1.18.0
rev: 1.19.1
hooks:
- id: blacken-docs

Expand All @@ -39,17 +39,17 @@ repos:
exclude: ^(docs/)

- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.19
rev: v0.23
hooks:
- id: validate-pyproject

- repo: https://github.com/asottile/pyupgrade
rev: v3.17.0
rev: v3.19.1
hooks:
- id: pyupgrade

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.11.2
rev: v1.14.1
hooks:
- id: mypy
exclude: ^((tests|scripts)/)
Expand All @@ -62,6 +62,6 @@ repos:
# additional_dependencies: [ numpy, poetry==1.1.11 ]

- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v18.1.8
rev: v19.1.7
hooks:
- id: clang-format
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
Changelog
=========


6.5.8 (2025-01-21)
------------------

* updated the data to `2025a <https://github.com/evansiroky/timezone-boundary-builder/releases/tag/2025a>`__
* internal: updated ``file_converter.py`` for ``h3>=4``


6.5.7 (2024-12-02)
------------------

Expand Down
732 changes: 393 additions & 339 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "timezonefinder"
version = "6.5.7"
version = "6.5.8"
description = "python package for finding the timezone of any point on earth (coordinates) offline"
authors = ["jannikmi <[email protected]>"]
license = "MIT"
Expand Down
57 changes: 30 additions & 27 deletions scripts/file_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@

import functools
import itertools
import json
from dataclasses import dataclass
from os.path import abspath, join
from pathlib import Path
from typing import Dict, List, NamedTuple, Optional, Set, Tuple, Union

Expand All @@ -90,6 +88,7 @@
write_boundary_data,
write_coordinate_data,
write_json,
load_json,
)
from timezonefinder.configs import (
DTYPE_FORMAT_H,
Expand Down Expand Up @@ -147,8 +146,8 @@ def parse_polygons_from_json(input_path: Path) -> int:
global polygons, polygon_lengths, poly_zone_ids, poly_boundaries

print(f"parsing input file: {input_path}\n...\n")
with open(input_path) as json_file:
tz_list = json.loads(json_file.read()).get("features")
input_json = load_json(input_path)
tz_list = input_json["features"]

poly_id = 0
zone_id = 0
Expand Down Expand Up @@ -184,7 +183,7 @@ def parse_polygons_from_json(input_path: Path) -> int:
for hole_nr, hole in enumerate(poly_with_hole):
nr_of_holes += 1 # keep track of how many holes there are
print(
f"\rpolygon {poly_id}, zone {tz_name}, hole number {nr_of_holes}, {hole_nr+1} in polygon",
f"\rpolygon {poly_id}, zone {tz_name}, hole number {nr_of_holes}, {hole_nr + 1} in polygon",
end="",
)
polynrs_of_holes.append(poly_id)
Expand All @@ -205,24 +204,24 @@ def parse_polygons_from_json(input_path: Path) -> int:
assert nr_of_polygons >= 0
assert nr_of_polygons >= nr_of_zones
assert zone_id == nr_of_zones - 1
assert (
poly_id == nr_of_polygons
), f"polygon counter {poly_id} and entry amount in all_length {nr_of_polygons} are different."
assert poly_id == nr_of_polygons, (
f"polygon counter {poly_id} and entry amount in all_length {nr_of_polygons} are different."
)

if 0 in polygon_lengths:
raise ValueError()

# binary file value range tests:
assert (
nr_of_polygons < THRES_DTYPE_H
), f"address overflow: #{nr_of_polygons} polygon ids cannot be encoded as {DTYPE_FORMAT_H}!"
assert (
nr_of_zones < THRES_DTYPE_H
), f"address overflow: #{nr_of_zones} zone ids cannot be encoded as {DTYPE_FORMAT_H}!"
assert nr_of_polygons < THRES_DTYPE_H, (
f"address overflow: #{nr_of_polygons} polygon ids cannot be encoded as {DTYPE_FORMAT_H}!"
)
assert nr_of_zones < THRES_DTYPE_H, (
f"address overflow: #{nr_of_zones} zone ids cannot be encoded as {DTYPE_FORMAT_H}!"
)
max_poly_length = max(polygon_lengths)
assert (
max_poly_length < THRES_DTYPE_I
), f"address overflow: the maximal amount of coords {max_poly_length} cannot be represented by {DTYPE_FORMAT_I}"
assert max_poly_length < THRES_DTYPE_I, (
f"address overflow: the maximal amount of coords {max_poly_length} cannot be represented by {DTYPE_FORMAT_I}"
)
max_hole_poly_length = max(all_hole_lengths)
assert max_hole_poly_length < THRES_DTYPE_H, (
f"address overflow: the maximal amount of coords in hole polygons "
Expand All @@ -242,7 +241,7 @@ def parse_polygons_from_json(input_path: Path) -> int:
return polygon_space


def update_zone_names(output_path):
def update_zone_names(output_path: Path):
# update all the zone names and set the right ids to be written in the poly_zone_ids.bin
global poly_zone_ids
global list_of_pointers
Expand All @@ -252,7 +251,7 @@ def update_zone_names(output_path):
global polynrs_of_holes
global nr_of_zones
global nr_of_polygons
file_path = abspath(join(output_path, TIMEZONE_NAMES_FILE))
file_path = output_path / TIMEZONE_NAMES_FILE
print(f"updating the zone names in {file_path} now.")
# pickle the zone names (python array)
write_json(all_tz_names, file_path)
Expand Down Expand Up @@ -483,18 +482,18 @@ def zones_in_cell(self) -> Set[int]:

@property
def children(self) -> Set[int]:
return set(h3.h3_to_children(self.id))
return set(h3.cell_to_children(self.id))

@property
def outer_children(self) -> Set[int]:
child_set = self.children
center_child = h3.h3_to_center_child(self.id)
center_child = h3.cell_to_center_child(self.id)
child_set.remove(center_child)
return child_set

@property
def neighbours(self) -> HexIdSet:
return set(h3.k_ring(self.id, k=1))
return set(h3.grid_ring(self.id, k=1))

@property
def true_parents(self) -> HexIdSet:
Expand All @@ -509,7 +508,7 @@ def true_parents(self) -> HexIdSet:
raise ValueError("not defined for resolution 0")
lower_res = self.res - 1
# NOTE: (lat,lng) pairs!
coord_pairs = h3.h3_to_geo_boundary(self.id)
coord_pairs = h3.cell_to_boundary(self.id)
return {h3.latlng_to_cell(pt[0], pt[1], lower_res) for pt in coord_pairs}


Expand Down Expand Up @@ -582,9 +581,9 @@ def report_progress():
def all_res_candidates(res: int) -> HexIdSet:
print(f"compiling hex candidates for resolution {res}.")
if res == 0:
return set(h3.get_res0_indexes())
return set(h3.get_res0_cells())
parent_res_candidates = all_res_candidates(res - 1)
child_iter = (h3.h3_to_children(h) for h in parent_res_candidates)
child_iter = (h3.cell_to_children(h) for h in parent_res_candidates)
return set(itertools.chain.from_iterable(child_iter))


Expand Down Expand Up @@ -734,8 +733,8 @@ def compile_addresses(
}
)

with open(join(output_path, HOLE_REGISTRY_FILE), "w") as json_file:
json.dump(hole_registry, json_file, indent=4)
path = output_path / HOLE_REGISTRY_FILE
write_json(hole_registry, path)

# '<H' Y times [H unsigned short: nr of values (coordinate PAIRS! x,y in int32 int32) in this hole]
assert len(all_hole_lengths) == nr_of_holes
Expand Down Expand Up @@ -775,6 +774,10 @@ def parse_data(
input_path: Union[Path, str] = DEFAULT_INPUT_PATH,
output_path: Union[Path, str] = DEFAULT_OUTPUT_PATH,
):
input_path = Path(input_path)
output_path = Path(output_path)
output_path.mkdir(parents=True, exist_ok=True)

polygon_space = parse_polygons_from_json(input_path)
update_zone_names(output_path)
hole_space = compile_polygon_binaries(output_path)
Expand Down
14 changes: 8 additions & 6 deletions scripts/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ def write_json(obj, path):
print("writing json to ", path)
with open(abspath(path), "w") as json_file:
json.dump(obj, json_file, indent=2)
# write a newline at the end of the file
json_file.write("\n")


def time_execution(func):
Expand Down Expand Up @@ -133,12 +135,12 @@ def export_mapping(file_name: str, obj: Dict, res: int):


def write_value(output_file, value, data_format, lower_value_limit, upper_value_limit):
assert (
value > lower_value_limit
), f"trying to write value {value} subceeding lower limit {lower_value_limit} (data type {data_format})"
assert (
value < upper_value_limit
), f"trying to write value {value} exceeding upper limit {upper_value_limit} (data type {data_format})"
assert value > lower_value_limit, (
f"trying to write value {value} subceeding lower limit {lower_value_limit} (data type {data_format})"
)
assert value < upper_value_limit, (
f"trying to write value {value} exceeding upper limit {upper_value_limit} (data type {data_format})"
)
output_file.write(struct.pack(data_format, value))


Expand Down
36 changes: 18 additions & 18 deletions tests/main_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,26 @@ def ocean2land(test_locations):

def check_geometry(geometry_obj: List):
coords = geometry_obj[0][0]
assert (
len(coords) == 2
), "the polygon does not consist of two latitude longitude lists"
assert len(coords) == 2, (
"the polygon does not consist of two latitude longitude lists"
)
x_coords, y_coords = coords
nr_x_coords = len(x_coords)
nr_y_coords = len(y_coords)
assert nr_x_coords > 2, "a polygon must consist of more than 2 coordinates"
assert (
nr_x_coords == nr_y_coords
), "the amount of x and y coordinates (lng, lat) must be equal"
assert nr_x_coords == nr_y_coords, (
"the amount of x and y coordinates (lng, lat) must be equal"
)


def check_pairwise_geometry(geometry_obj: List):
# list of all coord pairs of the first polygon
cord_pairs = geometry_obj[0][0]
assert len(cord_pairs) > 2, "a polygon must consist of more than 2 coordinates"
first_coord_pair = cord_pairs[0]
assert (
len(first_coord_pair) == 2
), "the polygon does not consist of coordinate pairs as expected."
assert len(first_coord_pair) == 2, (
"the polygon does not consist of coordinate pairs as expected."
)


def is_valid_lng_int(x: int) -> bool:
Expand Down Expand Up @@ -192,9 +192,9 @@ def test_timezone_name_attribute(self):
timezone_names_stored = self.test_instance.timezone_names
with open(join(abs_default_path, TIMEZONE_NAMES_FILE)) as json_file:
timezone_names_json = json.loads(json_file.read())
assert (
timezone_names_stored == timezone_names_json
), f"the content of the {TIMEZONE_NAMES_FILE} and the attribute {timezone_names_stored} are different."
assert timezone_names_stored == timezone_names_json, (
f"the content of the {TIMEZONE_NAMES_FILE} and the attribute {timezone_names_stored} are different."
)


class BaseClassTestMEM(BaseTimezoneFinderClassTest):
Expand Down Expand Up @@ -285,9 +285,9 @@ def test_get_geometry(self):
)
# not necessary:
# assert nested_list_equal(geometry_from_id, geometry_from_name), \
assert (
len(geometry_from_name) == len(geometry_from_id)
), "the results for querying the geometry for a zone with zone name or zone id are NOT equal."
assert len(geometry_from_name) == len(geometry_from_id), (
"the results for querying the geometry for a zone with zone name or zone id are NOT equal."
)
check_geometry(geometry_from_id)

geometry_from_name = self.test_instance.get_geometry(
Expand All @@ -296,9 +296,9 @@ def test_get_geometry(self):
geometry_from_id = self.test_instance.get_geometry(
tz_name=zone_name, tz_id=zone_id, use_id=False, coords_as_pairs=True
)
assert (
len(geometry_from_name) == len(geometry_from_id)
), "the results for querying the geometry for a zone with zone name or zone id are NOT equal."
assert len(geometry_from_name) == len(geometry_from_id), (
"the results for querying the geometry for a zone with zone name or zone id are NOT equal."
)

check_pairwise_geometry(geometry_from_id)
check_pairwise_geometry(geometry_from_name)
Expand Down
18 changes: 9 additions & 9 deletions tests/shortcut_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ def test_resolutions():
shortcut_hex_ids = shortcuts.keys()
resolutions = [h3.get_resolution(h) for h in shortcut_hex_ids]
res_matched = [res == configs.SHORTCUT_H3_RES for res in resolutions]
assert all(
res_matched
), f"not all shortcut resolutions match the expected resolution {configs.SHORTCUT_H3_RES}"
assert all(res_matched), (
f"not all shortcut resolutions match the expected resolution {configs.SHORTCUT_H3_RES}"
)


def test_empty_shortcut():
Expand All @@ -60,12 +60,12 @@ def test_unique_pole_cells():
if hex.surr_n_pole:
n_pole_ctr += 1

assert (
s_pole_ctr == 1
), f"{s_pole_ctr} cells are considered to surround the south pole"
assert (
n_pole_ctr == 1
), f"{n_pole_ctr} cells are considered to surround the north pole"
assert s_pole_ctr == 1, (
f"{s_pole_ctr} cells are considered to surround the south pole"
)
assert n_pole_ctr == 1, (
f"{n_pole_ctr} cells are considered to surround the north pole"
)


def has_coherent_sequences(lst: List[int]) -> bool:
Expand Down
Binary file modified timezonefinder/hole_adr2data.bin
Binary file not shown.
Binary file modified timezonefinder/hole_coord_amount.bin
Binary file not shown.
Binary file modified timezonefinder/hole_data.bin
Binary file not shown.
Loading

0 comments on commit 17ece10

Please sign in to comment.