Skip to content

Commit 596d827

Browse files
committed
linting
1 parent 6f6f51a commit 596d827

11 files changed

Lines changed: 79 additions & 48 deletions

docs/ARCHITECTURE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ Launches Blender headlessly and runs `blender_scripts/render_frames.py`, which p
9494

9595
When `render/n_segments > 1`, the render is split into N sequential Blender passes. Each pass loads only the terrain tiles whose world-space bounding boxes intersect the camera's AABB for that frame range, expanded by `render/frustum_margin_km`. This keeps per-pass VRAM proportional to the visible terrain fraction. Each Blender process exits completely between segments, fully releasing GPU memory before the next segment starts.
9696

97-
Output PNGs are stored in a temporary directory that is registered on `Pipeline._temp_dirs` for post-job cleanup.
97+
Output PNGs are stored in a temporary directory that is registered on `Pipeline.temp_dirs` for post-job cleanup.
9898

9999
### 8. Photo Overlay Compositor (`core/photo_compositor.py`)
100100
Groups consecutive pause keyframes into blocks and renders them as a photo carousel:
@@ -103,7 +103,7 @@ Groups consecutive pause keyframes into blocks and renders them as a photo carou
103103
- Letterboxing: blurred photo fill or black bars, preserving aspect ratio
104104
- Transition: fade (cross-dissolve) or cut (hard edit)
105105

106-
Supports all resolution presets (landscape 16:9, portrait 9:16, square 1:1). Output is stored in a temporary directory registered on `Pipeline._temp_dirs` for post-job cleanup.
106+
Supports all resolution presets (landscape 16:9, portrait 9:16, square 1:1). Output is stored in a temporary directory registered on `Pipeline.temp_dirs` for post-job cleanup.
107107

108108
### 9. Video Assembler (`core/video_assembler.py`)
109109
Encodes the final frame sequence into a video file using FFmpeg. Configurable container (MKV/MP4), codec (H.264/H.265/AV1), and encoder with automatic detection of available hardware accelerators (NVIDIA NVENC, AMD AMF, Intel QSV, Apple VideoToolbox) and software fallbacks. For MKV output, the source GPX and render settings JSON are attached as named attachments.

src/georeel/core/camera_path.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,37 @@ def _height_at_batch(
493493
return grid.elevation_at_batch(lats, lons)
494494

495495

496+
def _smooth_elevation(
497+
grid: ElevationGrid,
498+
lat: float,
499+
lon: float,
500+
) -> float:
501+
dlat = (grid.max_lat - grid.min_lat) / (grid.rows - 1) * 1.5
502+
dlon = (grid.max_lon - grid.min_lon) / (grid.cols - 1) * 1.5
503+
samples = [
504+
grid.elevation_at(lat + r * dlat, lon + c * dlon)
505+
for r in (-1, 0, 1)
506+
for c in (-1, 0, 1)
507+
]
508+
return float(np.mean(samples))
509+
510+
511+
def _height_at(
512+
x: float,
513+
y: float,
514+
grid: ElevationGrid,
515+
bbox: BoundingBox,
516+
lat_m: float,
517+
lon_m: float,
518+
height_mode: str,
519+
height_offset: float = 0.0,
520+
) -> float:
521+
result = float(_height_at_batch(
522+
np.array([x]), np.array([y]), grid, bbox, lat_m, lon_m, height_mode
523+
)[0])
524+
return result + height_offset
525+
526+
496527
# ------------------------------------------------------------------
497528
# Orientation helpers
498529
# ------------------------------------------------------------------

src/georeel/core/pipeline_memory.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def log_pipeline_memory(pipeline: object, label: str = "") -> None:
7272
f" satellite : {w}×{h} px {bands}-band {_fmt(sat_mb)}"
7373
)
7474
else:
75-
src_zip = getattr(sat, "_source_zip", None)
75+
src_zip = getattr(sat, "source_zip", None)
7676
td = getattr(sat, "_tiles_dir", None)
7777
if src_zip is not None:
7878
lines.append(

src/georeel/core/project.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def save_project(state: ProjectState, path: str) -> None:
173173
2. Renames the temporary file to *path*.
174174
175175
This matters especially for the lazy-loaded satellite texture: when a
176-
project is loaded, ``state.satellite_texture._source_zip`` points at
176+
project is loaded, ``state.satellite_texture.source_zip`` points at
177177
*path* itself. If we opened *path* for writing directly we would truncate
178178
the source while still trying to stream from it, producing a 0-byte
179179
``satellite/texture.png`` in the saved ZIP. Writing to a distinct temp
@@ -228,7 +228,7 @@ def save_project(state: ProjectState, path: str) -> None:
228228
}
229229

230230
# Write to a sibling temp file so the original (which may be the satellite
231-
# texture's _source_zip) stays intact during the entire write.
231+
# texture's source_zip) stays intact during the entire write.
232232
tmp_path = path + ".tmp"
233233
try:
234234
with zipfile.ZipFile(tmp_path, "w", compression=zipfile.ZIP_DEFLATED) as zf:

src/georeel/core/satellite/texture.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class SatelliteTexture:
5050
# Cached pixel dimensions — populated from image.size, tile manifest,
5151
# tile cache geometry, or the PNG IHDR header.
5252
dim_width: int | None = field(default=None, repr=False)
53-
_dim_height: int | None = field(default=None, repr=False)
53+
dim_height: int | None = field(default=None, repr=False)
5454

5555
@property
5656
def width(self) -> int:
@@ -66,8 +66,8 @@ def width(self) -> int:
6666
def height(self) -> int:
6767
if self.image is not None:
6868
return self.image.height
69-
if self._dim_height is not None:
70-
return self._dim_height
69+
if self.dim_height is not None:
70+
return self.dim_height
7171
raise RuntimeError(
7272
"SatelliteTexture dimensions not available (image not loaded and no cached size)."
7373
)
@@ -100,10 +100,10 @@ def free_image(
100100
if tiles_manifest is not None:
101101
self._tiles_manifest = tiles_manifest
102102
self.dim_width = tiles_manifest.get("image_width")
103-
self._dim_height = tiles_manifest.get("image_height")
103+
self.dim_height = tiles_manifest.get("image_height")
104104
if self.image is not None:
105105
self.dim_width = self.image.width
106-
self._dim_height = self.image.height
106+
self.dim_height = self.image.height
107107
mb = self.memory_bytes() / 1024 ** 2
108108
self.image = None
109109
# Blender tiles are now on disk; the XYZ tile cache is no longer needed.
@@ -119,8 +119,8 @@ def write_png(self, dest: IO[bytes]) -> None:
119119
120120
Priority order:
121121
1. Image in RAM — save directly.
122-
2. Lazy ZIP source (_source_zip) — copy raw bytes, zero decode.
123-
3. Tile cache (_tile_cache) — composite full bbox on demand.
122+
2. Lazy ZIP source (source_zip) — copy raw bytes, zero decode.
123+
3. Tile cache (tile_cache) — composite full bbox on demand.
124124
4. Blender tile manifest (_tiles_manifest) — reassemble from tile PNGs.
125125
"""
126126
if self.image is not None:
@@ -281,7 +281,7 @@ def from_zip_lazy(
281281
obj.source_zip = zip_path
282282
obj._source_entry = entry
283283
obj.dim_width = dim_w
284-
obj._dim_height = dim_h
284+
obj.dim_height = dim_h
285285
return obj
286286

287287
def load_image(self) -> Image.Image:
@@ -302,7 +302,7 @@ def load_image(self) -> Image.Image:
302302
image = image.convert("RGB")
303303
self.image = image
304304
self.dim_width = image.width
305-
self._dim_height = image.height
305+
self.dim_height = image.height
306306
return image
307307
raise RuntimeError(
308308
"SatelliteTexture has no image and no source ZIP to load from."

src/georeel/core/satellite/xyz_source.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def fetch(
118118
quality=self._quality,
119119
tile_cache=cache,
120120
dim_width=W,
121-
_dim_height=H,
121+
dim_height=H,
122122
)
123123

124124

tests/test_pipeline.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,24 @@ def test_cleanup_deletes_temp_dirs(self, tmp_path):
2626
d2 = tmp_path / "dir2"
2727
d1.mkdir()
2828
d2.mkdir()
29-
p._temp_dirs.append(d1)
30-
p._temp_dirs.append(d2)
29+
p.temp_dirs.append(d1)
30+
p.temp_dirs.append(d2)
3131
p.cleanup()
3232
assert not d1.exists()
3333
assert not d2.exists()
3434

3535
def test_cleanup_tolerates_missing_dirs(self, tmp_path):
3636
p = Pipeline()
37-
p._temp_dirs.append(tmp_path / "nonexistent")
37+
p.temp_dirs.append(tmp_path / "nonexistent")
3838
p.cleanup() # should not raise
3939

4040
def test_cleanup_clears_temp_dirs_list(self, tmp_path):
4141
p = Pipeline()
4242
d = tmp_path / "d"
4343
d.mkdir()
44-
p._temp_dirs.append(d)
44+
p.temp_dirs.append(d)
4545
p.cleanup()
46-
assert p._temp_dirs == []
46+
assert p.temp_dirs == []
4747

4848
def test_fields_assignable(self):
4949
p = Pipeline()

tests/test_pipeline_memory.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def _pipeline_with_lazy_sat(source_zip_name="test.georeel"):
109109
from pathlib import Path
110110
sat = SimpleNamespace(
111111
image=None,
112-
_source_zip=Path(source_zip_name),
112+
source_zip=Path(source_zip_name),
113113
_tiles_dir=None,
114114
)
115115
p.satellite_texture = sat
@@ -121,7 +121,7 @@ def _pipeline_with_freed_sat(tiles_dir="/tmp/tiles"):
121121
from pathlib import Path
122122
sat = SimpleNamespace(
123123
image=None,
124-
_source_zip=None,
124+
source_zip=None,
125125
_tiles_dir=Path(tiles_dir),
126126
)
127127
p.satellite_texture = sat

tests/test_project.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ def test_lazy_texture_saved_correctly_when_source_is_target(self, tmp_path):
463463

464464
loaded = load_project(path)
465465
assert loaded.satellite_texture is not None
466-
assert loaded.satellite_texture._source_zip == Path(path)
466+
assert loaded.satellite_texture.source_zip == Path(path)
467467

468468
# Simulate "output file name changed, then Save":
469469
save_project(

tests/test_satellite_texture_extended.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ def test_width_from_dim_width_when_image_none(self):
8787
max_lat=1,
8888
min_lon=0,
8989
max_lon=1,
90-
_dim_width=300,
91-
_dim_height=200,
90+
dim_width=300,
91+
dim_height=200,
9292
)
9393
assert t.width == 300
9494
assert t.height == 200
@@ -118,14 +118,14 @@ def test_image_is_none_after_free(self):
118118
def test_dims_cached_from_image_before_free(self):
119119
t = _make_texture(200, 150)
120120
t.free_image()
121-
assert t._dim_width == 200
122-
assert t._dim_height == 150
121+
assert t.dim_width == 200
122+
assert t.dim_height == 150
123123

124124
def test_tile_cache_cleared_on_free(self):
125125
t = _make_texture()
126-
t._tile_cache = MagicMock()
126+
t.tile_cache = MagicMock()
127127
t.free_image()
128-
assert t._tile_cache is None
128+
assert t.tile_cache is None
129129

130130
def test_tiles_dir_set_on_free(self):
131131
t = _make_texture()
@@ -141,8 +141,8 @@ def test_manifest_dims_set_before_image_dims_override(self):
141141
manifest = {"image_width": 400, "image_height": 300, "tiles": []}
142142
t.free_image(tiles_manifest=manifest)
143143
# Image dims (100×80) override the manifest values (400×300).
144-
assert t._dim_width == 100
145-
assert t._dim_height == 80
144+
assert t.dim_width == 100
145+
assert t.dim_height == 80
146146
assert t._tiles_manifest is manifest
147147

148148

@@ -222,7 +222,7 @@ def test_delegates_to_tile_cache_composite(self):
222222
fake_img = Image.new("RGB", (128, 96), (50, 100, 150))
223223
mock_cache = MagicMock()
224224
mock_cache.composite.return_value = fake_img
225-
t._tile_cache = mock_cache
225+
t.tile_cache = mock_cache
226226

227227
buf = io.BytesIO()
228228
t.write_png(buf)
@@ -243,7 +243,7 @@ def test_tile_cache_composite_rgba_converted(self):
243243
fake_img = Image.new("RGBA", (10, 10), (255, 0, 0, 200))
244244
mock_cache = MagicMock()
245245
mock_cache.composite.return_value = fake_img
246-
t._tile_cache = mock_cache
246+
t.tile_cache = mock_cache
247247

248248
buf = io.BytesIO()
249249
t.write_png(buf)
@@ -278,8 +278,8 @@ def test_reassembles_from_tiles(self, tmp_path):
278278
t = SatelliteTexture(image=None, min_lat=0, max_lat=1, min_lon=0, max_lon=1)
279279
t._tiles_dir = tmp_path
280280
t._tiles_manifest = manifest
281-
t._dim_width = 64
282-
t._dim_height = 32
281+
t.dim_width = 64
282+
t.dim_height = 32
283283

284284
buf = io.BytesIO()
285285
t.write_png(buf)
@@ -330,7 +330,7 @@ def test_source_zip_and_entry_set(self):
330330
t = SatelliteTexture.from_zip_lazy(
331331
zip_path, entry, min_lat=0, max_lat=1, min_lon=0, max_lon=1
332332
)
333-
assert t._source_zip == zip_path
333+
assert t.source_zip == zip_path
334334
assert t._source_entry == entry
335335
finally:
336336
zip_path.unlink(missing_ok=True)
@@ -362,8 +362,8 @@ def test_corrupt_zip_dims_unavailable(self, tmp_path):
362362
t = SatelliteTexture.from_zip_lazy(
363363
bad_zip, "satellite.png", min_lat=0, max_lat=1, min_lon=0, max_lon=1
364364
)
365-
assert t._dim_width is None
366-
assert t._dim_height is None
365+
assert t.dim_width is None
366+
assert t.dim_height is None
367367

368368

369369
# ---------------------------------------------------------------------------
@@ -399,8 +399,8 @@ def test_load_image_caches_dims(self):
399399
zip_path, entry, min_lat=0, max_lat=1, min_lon=0, max_lon=1
400400
)
401401
t.load_image()
402-
assert t._dim_width == 64
403-
assert t._dim_height == 48
402+
assert t.dim_width == 64
403+
assert t.dim_height == 48
404404
finally:
405405
zip_path.unlink(missing_ok=True)
406406

0 commit comments

Comments
 (0)