Skip to content

Commit 4acaf63

Browse files
authored
Merge branch 'main' into estimate_memory_usage
2 parents d5c14e0 + 86460fa commit 4acaf63

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+699
-195
lines changed

.github/workflows/python-package.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ jobs:
3737
sudo apt-get -y update
3838
sudo apt-get install -y gdal-bin python-tk libgdal-dev libproj-dev libgeos-dev
3939
python -m pip install --upgrade pip wheel
40-
pip install -r test/requirements.txt -r requirements.txt
4140
pip install -e .[complete]
41+
pip install -r test/requirements.txt
4242
pip freeze
4343
4444
- name: Lint with flake8

.pre-commit-config.yaml

+7-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,10 @@ repos:
1616
- repo: https://github.com/PyCQA/autoflake
1717
rev: v2.1.1
1818
hooks:
19-
- id: autoflake
19+
- id: autoflake
20+
- repo: https://github.com/pycqa/isort
21+
rev: 5.12.0
22+
hooks:
23+
- id: isort
24+
name: isort (python)
25+
args: ["--profile", "black"]

CHANGELOG.rst

+60
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,66 @@ Changelog
33
#########
44

55

6+
---------------------
7+
2023.9.0 - 2023-09-05
8+
---------------------
9+
10+
* packaging
11+
12+
* limit dependent versions to `"aiobotocore>=1.1.2,<=2.5.4"` and `"s3fs<2023.9.0"`
13+
14+
* core
15+
16+
* make sure opened/written files are removed upon exception (#576)
17+
* CLI: apply tiled-assets hack also to create-item CLI (#577)
18+
* provide path schema to configure how tile paths are created (#581)
19+
* `IndexedFeatures`: allow reprojection of object bounds to a target CRS (#585)
20+
21+
22+
---------------------
23+
2023.8.1 - 2023-08-09
24+
---------------------
25+
26+
* packaging
27+
28+
* require `Shapely>=2.0.0` (#572)
29+
* remmove `cached_property` package requirement (#573)
30+
* add `isort` to pre-commit (#573)
31+
32+
* core
33+
34+
* fix `ReferencedRaster.to_file()` on 2D arrays (#574)
35+
36+
37+
---------------------
38+
2023.8.0 - 2023-08-09
39+
---------------------
40+
41+
* packaging
42+
43+
* add `pydantic<2.0.0` as dependency
44+
45+
46+
* CI
47+
48+
* also test on Python 3.11 (#562)
49+
50+
* core
51+
52+
* enable adding default read parameters to TileDirectory input (#565)
53+
* configuration schema (#564)
54+
55+
* add `pydantic<2.0.0` as dependency
56+
* `mapchete.config.ProcessConfig` now defines the mapchete process configuration schema
57+
* process function parameters should now go into the `process_parameters` section of the configuration
58+
* add `mapchete.config.ProcessFunc` abstraction class to load and handle user process functions
59+
60+
* CLI: fix passing on storage options; add storage options to convert command (#568)
61+
* update STACTA file schema to STAC 1.0.0 (#569)
62+
* added `ReferencedRaster.to_file()` (#570)
63+
* added `read_raster(tile=...)` kwarg to resample incoming raster (#570)
64+
65+
666
---------------------
767
2023.7.1 - 2023-07-18
868
---------------------

doc/source/process_output.rst

+12
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ inserting the values or pointing to environment variables for increased security
5151
AWS_SECRET_ACCESS_KEY: ${SOME_KEY_SECRET}
5252
5353
54+
Also, the tile path schema can be edited if desired:
55+
56+
.. code-block:: yaml
57+
58+
output:
59+
type: geodetic
60+
format: GTiff
61+
metatiling: 4 # optional
62+
pixelbuffer: 10 # optional
63+
tile_path_schema: "{zoom}/{col}/{row}.{extension}"
64+
65+
5466
----------------------
5567
Default output formats
5668
----------------------

mapchete/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"SkippedFuture",
2020
"Job",
2121
]
22-
__version__ = "2023.7.1"
22+
__version__ = "2023.9.0"
2323

2424
logger = logging.getLogger(__name__)
2525
logger.addHandler(logging.NullHandler())

mapchete/_core.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from mapchete.errors import MapcheteNodataTile, ReprojectionFailed
2525
from mapchete.formats import read_output_metadata
2626
from mapchete.io import MPath, fs_from_path, tiles_exist
27-
from mapchete.stac import update_tile_directory_stac_item
27+
from mapchete.stac import tile_direcotry_item_to_dict, update_tile_directory_stac_item
2828
from mapchete.tile import count_tiles
2929
from mapchete.validate import validate_tile, validate_zooms
3030

@@ -705,11 +705,12 @@ def write_stac(self, indent=4):
705705
item_metadata=self.config.output.stac_item_metadata,
706706
tile_pyramid=self.config.output_pyramid,
707707
bands_type=self.config.output.stac_asset_type,
708+
band_asset_template=self.config.output.tile_path_schema,
708709
)
709710
logger.debug("write STAC item JSON to %s", self.config.output.stac_path)
710711
self.config.output.stac_path.parent.makedirs()
711712
with self.config.output.stac_path.open("w") as dst:
712-
dst.write(json.dumps(item.to_dict(), indent=indent))
713+
dst.write(json.dumps(tile_direcotry_item_to_dict(item), indent=indent))
713714
except ReprojectionFailed:
714715
logger.warning(
715716
"cannot create STAC item because footprint cannot be reprojected into EPSG:4326"

mapchete/_executor.py

+2-6
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
import sys
88
import warnings
99
from concurrent.futures._base import CancelledError
10-
from functools import partial
11-
12-
from cached_property import cached_property
10+
from functools import cached_property, partial
1311

1412
from mapchete._timer import Timer
1513
from mapchete.errors import JobCancelledError, MapcheteTaskFailed
@@ -55,8 +53,6 @@ class _ExecutorBase:
5553
cancelled = False
5654
running_futures = None
5755
finished_futures = None
58-
_as_completed = None
59-
_executor = None
6056
_executor_cls = None
6157
_executor_args = ()
6258
_executor_kwargs = {}
@@ -687,8 +683,8 @@ def future_raise_exception(future, raise_errors=True):
687683
# Let's directly re-raise these to be more transparent.
688684
try:
689685
# when using dask, also directly raise specific dask errors
690-
from distributed import CancelledError
691686
from dask.distributed import TimeoutError
687+
from distributed import CancelledError
692688
from distributed.comm.core import CommClosedError
693689

694690
keep_exceptions = (CancelledError, TimeoutError, CommClosedError)

mapchete/_processing.py

+19-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from mapchete._tasks import TaskBatch, TileTask, TileTaskBatch, to_dask_collection
2020
from mapchete._timer import Timer
2121
from mapchete.errors import MapcheteNodataTile
22+
from mapchete.path import batch_sort_property
2223
from mapchete.types import Bounds, ZoomLevels
2324

2425
FUTURE_TIMEOUT = float(os.environ.get("MP_FUTURE_TIMEOUT", 10))
@@ -179,7 +180,12 @@ def task_batches(
179180

180181
for tile, skip, _ in _filter_skipable(
181182
process=process,
182-
tiles_batches=process.get_process_tiles(zoom, batch_by="row"),
183+
tiles_batches=process.get_process_tiles(
184+
zoom,
185+
batch_by=batch_sort_property(
186+
process.config.output_reader.tile_path_schema
187+
),
188+
),
183189
target_set=(
184190
overview_parents if process.config.baselevels and i else None
185191
),
@@ -726,7 +732,12 @@ def _run_multi_overviews(
726732
)
727733
for tile, skip, process_msg in _filter_skipable(
728734
process=process,
729-
tiles_batches=process.get_process_tiles(zoom, batch_by="row"),
735+
tiles_batches=process.get_process_tiles(
736+
zoom,
737+
batch_by=batch_sort_property(
738+
process.config.output_reader.tile_path_schema
739+
),
740+
),
730741
target_set=(
731742
overview_parents if process.config.baselevels and i else None
732743
),
@@ -810,7 +821,12 @@ def _run_multi_no_overviews(
810821
tiles_batches=(
811822
batch
812823
for zoom in zoom_levels.descending()
813-
for batch in process.get_process_tiles(zoom, batch_by="row")
824+
for batch in process.get_process_tiles(
825+
zoom,
826+
batch_by=batch_sort_property(
827+
process.config.output_reader.tile_path_schema
828+
),
829+
)
814830
),
815831
target_set=None,
816832
skip_output_check=skip_output_check,

mapchete/cli/default/convert.py

+2
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ def _validate_bidx(ctx, param, bidx):
102102
@options.opt_logfile
103103
@options.opt_vrt
104104
@options.opt_idx_out_dir
105+
@options.opt_src_fs_opts
106+
@options.opt_dst_fs_opts
105107
def convert(
106108
tiledir,
107109
output,

mapchete/cli/default/create.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
from string import Template
66

77
import click
8+
import tilematrix
89
from importlib_resources import files
910
from oyaml import dump
10-
import tilematrix
1111

1212
from mapchete.cli import options
1313
from mapchete.formats import available_output_formats

mapchete/cli/default/index.py

-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
"""Create index for process output."""
22

33
import logging
4-
import os
5-
import sys
64

75
import click
86
import click_spinner

mapchete/cli/default/serve.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ def _tile_response(mp, web_tile, debug):
168168

169169

170170
def _valid_tile_response(mp, data):
171-
from flask import make_response, jsonify
171+
from flask import jsonify, make_response
172172
from flask_rangerequest import RangeRequest
173173

174174
out_data, mime_type = mp.config.output.for_web(data)

mapchete/cli/default/stac.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@
1010
from mapchete.config import raw_conf, raw_conf_output_pyramid
1111
from mapchete.formats import read_output_metadata
1212
from mapchete.io import MPath
13-
from mapchete.stac import create_prototype_files, tile_directory_stac_item
13+
from mapchete.stac import (
14+
create_prototype_files,
15+
tile_direcotry_item_to_dict,
16+
tile_directory_stac_item,
17+
)
1418
from mapchete.validate import validate_zooms
1519

1620
logger = logging.getLogger(__name__)
@@ -66,6 +70,7 @@ def create_item(
6670
default_bounds_crs,
6771
default_zoom,
6872
default_item_metadata,
73+
band_asset_template,
6974
) = output_info(input_)
7075

7176
if default_zoom:
@@ -94,11 +99,12 @@ def create_item(
9499
item_path=item_path,
95100
asset_basepath=asset_basepath,
96101
relative_paths=relative_paths,
102+
band_asset_template=band_asset_template,
97103
bands_type=None,
98104
crs_unit_to_meter=1,
99105
)
100106
logger.debug("item_path: %s", item_path)
101-
item_json = json.dumps(item.to_dict(), indent=indent)
107+
item_json = json.dumps(tile_direcotry_item_to_dict(item), indent=indent)
102108
click.echo(item_json)
103109
if force or click.confirm(f"Write output to {item_path}?", abort=True):
104110
with fsspec.open(item_path, "w") as dst:
@@ -118,16 +124,19 @@ def output_info(inp):
118124
conf.get("bounds_crs"),
119125
conf.get("zoom_levels"),
120126
conf["output"].get("stac"),
127+
conf["output"].get("tile_path_schema", "{zoom}/{row}/{col}.{extension}"),
121128
)
122129

130+
output_metadata = read_output_metadata(path / "metadata.json")
123131
return (
124-
read_output_metadata(path / "metadata.json")["pyramid"],
132+
output_metadata["pyramid"],
125133
path,
126134
path.name,
127135
None,
128136
None,
129137
None,
130138
None,
139+
output_metadata.get("tile_path_schema", "{zoom}/{row}/{col}.{extension}"),
131140
)
132141

133142

mapchete/commands/_convert.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ def convert(
6565
cog: bool = False,
6666
msg_callback: Callable = None,
6767
as_iterator: bool = False,
68+
src_fs_opts: Union[dict, None] = None,
69+
dst_fs_opts: Union[dict, None] = None,
6870
) -> mapchete.Job:
6971
"""
7072
Convert mapchete outputs or other geodata.
@@ -176,8 +178,8 @@ def _empty_callback(*args, **kwargs):
176178
workers = workers or multi or cpu_count()
177179
creation_options = creation_options or {}
178180
bidx = [bidx] if isinstance(bidx, int) else bidx
179-
tiledir = MPath.from_inp(tiledir) if isinstance(tiledir, str) else tiledir
180-
output = MPath.from_inp(output)
181+
tiledir = MPath.from_inp(tiledir, storage_options=src_fs_opts)
182+
output = MPath.from_inp(output, storage_options=dst_fs_opts)
181183
try:
182184
input_info = _get_input_info(tiledir)
183185
logger.debug("input params: %s", input_info)

mapchete/commands/_cp.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ def cp(
2727
point: Tuple[float, float] = None,
2828
point_crs: Tuple[float, float] = None,
2929
overwrite: bool = False,
30-
workers: int = None,
31-
multi: int = None,
32-
concurrency: str = None,
33-
dask_scheduler: str = None,
30+
workers: Union[int, None] = None,
31+
multi: Union[int, None] = None,
32+
concurrency: Union[str, None] = None,
33+
dask_scheduler: Union[str, None] = None,
3434
dask_client=None,
35-
src_fs_opts: dict = None,
36-
dst_fs_opts: dict = None,
37-
msg_callback: Callable = None,
35+
src_fs_opts: Union[dict, None] = None,
36+
dst_fs_opts: Union[dict, None] = None,
37+
msg_callback: Union[Callable, None] = None,
3838
as_iterator: bool = False,
3939
) -> mapchete.Job:
4040
"""
@@ -112,8 +112,8 @@ def _empty_callback(*_):
112112
if zoom is None: # pragma: no cover
113113
raise ValueError("zoom level(s) required")
114114

115-
src_tiledir = MPath.from_inp(src_tiledir, **src_fs_opts)
116-
dst_tiledir = MPath.from_inp(dst_tiledir, **dst_fs_opts)
115+
src_tiledir = MPath.from_inp(src_tiledir, storage_options=src_fs_opts)
116+
dst_tiledir = MPath.from_inp(dst_tiledir, storage_options=dst_fs_opts)
117117
src_fs = src_tiledir.fs
118118
dst_fs = dst_tiledir.fs
119119

mapchete/commands/_index.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import mapchete
1010
from mapchete.index import zoom_index_gen
11+
from mapchete.path import MPath
1112

1213
logger = logging.getLogger(__name__)
1314

@@ -115,7 +116,6 @@ def _empty_callback(*_):
115116
pass
116117

117118
msg_callback = msg_callback or _empty_callback
118-
fs_opts = fs_opts or {}
119119

120120
msg_callback(f"create index(es) for {tiledir}")
121121
# process single tile

0 commit comments

Comments
 (0)