Translate the whole project to English and fix outdated comments and help
Comments, docstrings, logs, CLI help, map UI, legends, PDF sheet, scripts, compose files and AGENTS.md are now English. Data keys stay unchanged (relief_oriente, densite_sol, visualisations/, API JSON keys, link params). Wrong comments and help defaults found along the way are corrected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
"""Tests de l'export PDF (planche d'impression terrain)."""
|
||||
"""Tests for the PDF export (printable field sheet)."""
|
||||
|
||||
import pytest
|
||||
|
||||
@ -8,7 +8,7 @@ def test_layout_landscape_a4_dimensions():
|
||||
lay = layout("A4", "paysage", 2000)
|
||||
assert (lay.page_w, lay.page_h) == (297.0, 210.0) and lay.dpi == 300
|
||||
assert lay.map_w > 150 and lay.map_h > 150
|
||||
assert lay.panel_x >= lay.map_x + lay.map_w # bandeau à droite
|
||||
assert lay.panel_x >= lay.map_x + lay.map_w # panel on the right
|
||||
assert lay.map_x + lay.map_w <= lay.page_w and lay.map_y + lay.map_h <= lay.page_h
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ def test_layout_portrait_a3_panel_below():
|
||||
from lidar_pipeline.export_pdf import layout
|
||||
lay = layout("A3", "portrait", 5000)
|
||||
assert (lay.page_w, lay.page_h) == (297.0, 420.0) and lay.dpi == 250
|
||||
assert lay.panel_y + lay.panel_h <= lay.map_y # bandeau en bas
|
||||
assert lay.panel_y + lay.panel_h <= lay.map_y # panel at the bottom
|
||||
|
||||
|
||||
@pytest.mark.parametrize("args", [("A5", "paysage", 2000), ("A4", "biais", 2000),
|
||||
@ -38,7 +38,7 @@ def test_map_bbox_matches_paper_times_scale():
|
||||
|
||||
def test_pixel_size_and_grid_step():
|
||||
from lidar_pipeline.export_pdf import grid_step, layout, pixel_size
|
||||
assert pixel_size(layout("A4", "paysage", 1000)) == 0.2 # plafonné au natif
|
||||
assert pixel_size(layout("A4", "paysage", 1000)) == 0.2 # capped at the native resolution
|
||||
assert abs(pixel_size(layout("A3", "paysage", 10000)) - 10000 * 0.0254 / 250) < 1e-9
|
||||
assert [grid_step(s) for s in (1000, 2000, 5000, 10000)] == [100, 100, 500, 1000]
|
||||
|
||||
@ -57,7 +57,7 @@ def test_frame_roundtrip():
|
||||
assert abs(f["cx"] - cx) < 1e-6 and abs(f["cy"] - cy) < 1e-6
|
||||
assert len(f["corners"]) == 4
|
||||
nw, ne, se, sw = f["corners"]
|
||||
assert nw[0] > sw[0] and ne[1] > nw[1] # [lat, lon] : nord en haut, est à droite
|
||||
assert nw[0] > sw[0] and ne[1] > nw[1] # [lat, lon]: north at the top, east on the right
|
||||
assert f["width_m"] > f["height_m"] > 0
|
||||
|
||||
|
||||
@ -99,11 +99,11 @@ def test_compose_l93_half_outside_is_white_hatched(tmp_path, monkeypatch):
|
||||
from lidar_pipeline.export_pdf import compose_l93
|
||||
monkeypatch.setattr(index, "PANEL_VIZ", None)
|
||||
_dalle(tmp_path, 1054, 6882)
|
||||
# moitié ouest dans la dalle, moitié est hors données
|
||||
# western half inside the tile, eastern half outside the data
|
||||
img, mask, cells = compose_l93(tmp_path, (1054900.0, 6881400.0, 1055100.0, 6881500.0), 1.0)
|
||||
assert mask.getpixel((50, 50)) == 255 and mask.getpixel((150, 50)) == 0
|
||||
east = img.crop((110, 0, 200, 100)).convert("L").getextrema()
|
||||
assert east[1] == 255 and east[0] < 255 # blanc + hachures
|
||||
assert east[1] == 255 and east[0] < 255 # white + hatching
|
||||
|
||||
|
||||
def test_compose_l93_nodata_pixels_masked(tmp_path, monkeypatch):
|
||||
@ -145,12 +145,13 @@ def test_density_color_classes():
|
||||
|
||||
def test_pdf_text_replaces_unencodable():
|
||||
from lidar_pipeline.export_pdf import _pdf_text
|
||||
assert _pdf_text("Relief orienté — 1:2 000 ≥ 🚀") == "Relief orienté — 1:2 000 ? ?"
|
||||
# é and — exist in cp1252; ≥ and the emoji do not
|
||||
assert _pdf_text("Café — 1:2,000 ≥ 🚀") == "Café — 1:2,000 ? ?"
|
||||
|
||||
|
||||
def test_pdf_legend_uses_reading_text(monkeypatch):
|
||||
"""La légende de la planche PDF affiche le texte « Comment lire » de
|
||||
VIZ_LEGENDS, habillé à la largeur de la boîte, plutôt que « legend »."""
|
||||
"""The PDF sheet legend shows the "How to read" text of VIZ_LEGENDS,
|
||||
wrapped to the box width, rather than "legend"."""
|
||||
from lidar_pipeline import export_pdf
|
||||
from lidar_pipeline.index import VIZ_LEGENDS
|
||||
drawn = []
|
||||
@ -177,13 +178,13 @@ def test_zone_quality_aggregates_two_cells():
|
||||
from lidar_pipeline.export_pdf import zone_quality
|
||||
table = {"LHD_FXX_1054_6882_PTS_LAMB93_IGN69": _q(4.0, "2023-03-15", "2023-03-15"),
|
||||
"LHD_FXX_1055_6882_PTS_LAMB93_IGN69": _q(8.0, "2023-04-02", "2023-04-03", 0.3)}
|
||||
bbox = (1054500.0, 6881500.0, 1055500.0, 6881600.0) # moitié de chaque dalle
|
||||
bbox = (1054500.0, 6881500.0, 1055500.0, 6881600.0) # half of each tile
|
||||
z = zone_quality(bbox, table, [(1054, 6882), (1055, 6882)])
|
||||
assert abs(z["density_mean"] - 6.0) < 1e-6 and z["density_min"] == 4.0
|
||||
assert abs(z["empty_fraction"] - 0.2) < 1e-6
|
||||
assert (z["acq_start"], z["acq_end"]) == ("2023-03-15", "2023-04-03")
|
||||
assert z["missing_relief"] == [] and z["missing_quality"] == []
|
||||
assert len(z["grid_cells"]) == 2 * 10 * 2 # 10 mailles en x × 2 en y par dalle
|
||||
assert len(z["grid_cells"]) == 2 * 10 * 2 # 10 cells in x × 2 in y per tile
|
||||
|
||||
|
||||
def test_zone_quality_missing_cells():
|
||||
@ -216,12 +217,13 @@ def test_build_pdf_a4_landscape(tmp_path, monkeypatch):
|
||||
write_quality(tmp_path, "LHD_FXX_1054_6882_PTS_LAMB93_IGN69", _q(6.5))
|
||||
lat, lon = _cell_center_wgs84(1054, 6882)
|
||||
pdf, name = build_pdf(tmp_path, lat, lon, "A4", "paysage", 2000,
|
||||
title="Prospection 🚀 bois", compress=False)
|
||||
title="Survey 🚀 woods", compress=False)
|
||||
assert pdf.startswith(b"%PDF")
|
||||
w, h = _mediabox(pdf)
|
||||
assert abs(w - 841.89) < 0.5 and abs(h - 595.28) < 0.5
|
||||
assert name.startswith("relief_1054.") and name.endswith("_1-2000.pdf")
|
||||
for s in (b"Prospection ? bois", b"1:2 000", b"Densit", b"2023-03-15", b"LiDAR HD", b"6,5 pts"):
|
||||
for s in (b"Survey ? woods", b"1:2,000", b"ground density", b"2023-03-15", b"LiDAR HD",
|
||||
b"6.5 pts", b"landscape"):
|
||||
assert s in pdf, s
|
||||
|
||||
|
||||
@ -237,7 +239,7 @@ def test_build_pdf_a3_portrait_size(tmp_path, monkeypatch):
|
||||
|
||||
|
||||
def test_build_pdf_partial_zone_hatched(tmp_path, monkeypatch):
|
||||
"""Zone à cheval sur le bord des données : planche produite, dalle absente listée."""
|
||||
"""Area straddling the data edge: sheet produced, missing tile listed."""
|
||||
from lidar_pipeline import index
|
||||
from lidar_pipeline.export_pdf import build_pdf
|
||||
from lidar_pipeline.tiles import _transformer
|
||||
@ -246,7 +248,7 @@ def test_build_pdf_partial_zone_hatched(tmp_path, monkeypatch):
|
||||
lon, lat = _transformer("EPSG:2154", "EPSG:4326").transform(1055000.0, 6881500.0)
|
||||
pdf, _ = build_pdf(tmp_path, lat, lon, "A4", "paysage", 2000, compress=False)
|
||||
assert pdf.startswith(b"%PDF") and b"1055_6882" in pdf
|
||||
assert b"Donn" in pdf and b"manquante" in pdf
|
||||
assert b"Missing data" in pdf and b"no relief" in pdf # "(" is escaped in PDF strings
|
||||
|
||||
|
||||
def test_build_pdf_no_data_raises(tmp_path):
|
||||
@ -258,13 +260,13 @@ def test_build_pdf_no_data_raises(tmp_path):
|
||||
|
||||
def test_fmt_int():
|
||||
from lidar_pipeline.export_pdf import _fmt_int
|
||||
assert _fmt_int(2000) == "2 000" and _fmt_int(500) == "500"
|
||||
assert _fmt_int(2000) == "2,000" and _fmt_int(500) == "500"
|
||||
|
||||
|
||||
def test_north_arrow_angle_matches_pyproj_reference():
|
||||
"""L'angle de rotation reportlab doit amener la flèche (dessinée vers le
|
||||
nord du quadrillage) sur le nord géographique, dans le bon sens, à l'est
|
||||
et à l'ouest du méridien central (3°E)."""
|
||||
"""The reportlab rotation angle must bring the arrow (drawn towards grid
|
||||
north) onto true north, in the right direction, east and west of the
|
||||
central meridian (3°E)."""
|
||||
import math
|
||||
from lidar_pipeline.export_pdf import _north_arrow_angle, _to_wgs84
|
||||
from lidar_pipeline.tiles import _transformer, wgs84_to_l93
|
||||
@ -275,12 +277,12 @@ def test_north_arrow_angle_matches_pyproj_reference():
|
||||
lat0, lon0 = _to_wgs84(cx, cy)
|
||||
x0, y0 = to_l93.transform(lon0, lat0)
|
||||
x1, y1 = to_l93.transform(lon0, lat0 + 0.001)
|
||||
# azimut (sens horaire depuis le nord du quadrillage) du nord géographique
|
||||
# azimuth of true north (clockwise from grid north)
|
||||
psi = math.degrees(math.atan2(x1 - x0, y1 - y0))
|
||||
return -psi # rotation reportlab (antihoraire) amenant "haut" sur ce nord
|
||||
return -psi # reportlab rotation (counter-clockwise) bringing "up" onto that north
|
||||
|
||||
east = wgs84_to_l93(6.0, 46.0) # à l'est du méridien central
|
||||
west = wgs84_to_l93(0.0, 46.0) # à l'ouest du méridien central
|
||||
east = wgs84_to_l93(6.0, 46.0) # east of the central meridian
|
||||
west = wgs84_to_l93(0.0, 46.0) # west of the central meridian
|
||||
for cx, cy in (east, west):
|
||||
assert abs(_north_arrow_angle(cx, cy) - _reference_angle(cx, cy)) < 0.05
|
||||
assert _north_arrow_angle(*east) > 0
|
||||
@ -293,7 +295,7 @@ def test_wrap_text_lines_fit_width():
|
||||
from io import BytesIO
|
||||
from lidar_pipeline.export_pdf import _wrap_text
|
||||
c = rl_canvas.Canvas(BytesIO())
|
||||
text = "Donnée manquante (sans relief) : " + ", ".join(
|
||||
text = "Missing data (no relief): " + ", ".join(
|
||||
f"{1050 + i}_6882" for i in range(12))
|
||||
max_width = 60 * mm
|
||||
lines = _wrap_text(c, text, "Helvetica", 5.8, max_width, sep=", ")
|
||||
@ -308,22 +310,22 @@ def test_fit_title_shrinks_then_elides():
|
||||
from io import BytesIO
|
||||
from lidar_pipeline.export_pdf import _fit_title
|
||||
c = rl_canvas.Canvas(BytesIO())
|
||||
long_title = "Relief orienté - " + ", ".join(f"{1050 + i:04d}_6882" for i in range(6))
|
||||
long_title = "Oriented relief - " + ", ".join(f"{1050 + i:04d}_6882" for i in range(6))
|
||||
text, size = _fit_title(c, long_title, "Helvetica-Bold", 10, 60 * mm, min_size=7.0)
|
||||
assert size >= 7.0
|
||||
assert c.stringWidth(text, "Helvetica-Bold", size) <= 60 * mm + 1e-6
|
||||
|
||||
|
||||
def test_cartouche_title_avoids_north_arrow_column():
|
||||
"""Le titre (et le sous-titre) de la cartouche ne doit jamais empiéter sur
|
||||
la colonne réservée à la flèche du nord, en paysage comme en portrait."""
|
||||
"""The title block's title (and subtitle) must never encroach on the
|
||||
column reserved for the north arrow, in landscape as in portrait."""
|
||||
from reportlab.pdfgen import canvas as rl_canvas
|
||||
from reportlab.lib.units import mm
|
||||
from io import BytesIO
|
||||
from lidar_pipeline.export_pdf import (
|
||||
_cartouche_text_max_width, _fit_title, _panel_boxes, layout)
|
||||
c = rl_canvas.Canvas(BytesIO())
|
||||
long_title = "Relief orienté - " + ", ".join(f"{1050 + i:04d}_6882" for i in range(6))
|
||||
long_title = "Oriented relief - " + ", ".join(f"{1050 + i:04d}_6882" for i in range(6))
|
||||
for paper, orient, scale in (("A4", "paysage", 2000), ("A4", "portrait", 10000),
|
||||
("A3", "portrait", 2000)):
|
||||
lay = layout(paper, orient, scale)
|
||||
@ -332,5 +334,5 @@ def test_cartouche_title_avoids_north_arrow_column():
|
||||
max_w = _cartouche_text_max_width(w, mm)
|
||||
txt, size = _fit_title(c, long_title, "Helvetica-Bold", 10, max_w)
|
||||
title_right_mm = x + c.stringWidth(txt, "Helvetica-Bold", size) / mm
|
||||
arrow_left_mm = (x + w - 8) - 1.8 # bord gauche du triangle de la flèche
|
||||
arrow_left_mm = (x + w - 8) - 1.8 # left edge of the arrow triangle
|
||||
assert title_right_mm <= arrow_left_mm, (paper, orient, scale)
|
||||
|
||||
Reference in New Issue
Block a user