Skip to content

fix: AttributeError in single-output mode with XML/o5m output#77

Merged
agrenott merged 2 commits intoagrenott:masterfrom
psca:bugfix/single-output-bbox-cast
Mar 17, 2026
Merged

fix: AttributeError in single-output mode with XML/o5m output#77
agrenott merged 2 commits intoagrenott:masterfrom
psca:bugfix/single-output-bbox-cast

Conversation

@psca
Copy link
Copy Markdown
Contributor

@psca psca commented Mar 17, 2026

Summary

  • Bug: AttributeError: 'list' object has no attribute 'min_lat' crash when running in single-output mode (--maxNodesPerTile=0) with XML or o5m output.
  • Root cause: typing.cast() is a runtime no-op — it returns its second argument unchanged. The old code passed a plain list[float] where a BBox NamedTuple was expected, which fails when downstream code accesses named fields like .min_lat. The fix constructs an actual BBox, which also required moving the import out of TYPE_CHECKING.
  • Regression test: Added test_process_files_single_output_bbox_type — the existing test_process_files_single_output E2E test uses PBF output, which unpacks bbox as a tuple and silently accepts a plain list; this new test targets the XML/o5m path by asserting get_osm_output receives a proper BBox instance, catching the exact failure mode.

Traceback

File "pyhgtmap/hgt/processor.py", line 277, in process_files
    self.get_osm_output(...)
  File "pyhgtmap/output/factory.py", line 87, in get_osm_output
    output = osmUtil.Output(...)
  File "pyhgtmap/output/osmUtil.py", line 72, in __init__
    self.boundsTag = make_bounds_tag(bbox)
  File "pyhgtmap/output/osmUtil.py", line 29, in make_bounds_tag
    return f'<bounds minlat="{bbox.min_lat:.7f}" ...'
AttributeError: 'list' object has no attribute 'min_lat'

Test plan

  • hatch run fmt — formatting passes
  • hatch run test — 296 passed, 5 skipped
  • New regression test test_process_files_single_output_bbox_type covers the exact failure path
  • Verified fix end-to-end against a real tile set covering low-elevation SEA region

🤖 Generated with Claude Code

typing.cast() is a static-analysis no-op and does not construct a
BBox NamedTuple at runtime. The area string was being parsed into a
plain list and passed downstream, causing AttributeError when
make_bounds_tag() accessed bbox.min_lat (XML/o5m output paths).

Replace cast("BBox", [...]) with BBox(*[...]) to actually instantiate
the NamedTuple, and add a regression test verifying the correct type
is passed to get_osm_output in single-output mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@agrenott
Copy link
Copy Markdown
Owner

Thanks for the proposal.
At a first glance, I'm not convinced the proposed fix is fixing the root cause, but rather its consequences.
Could you please share the overall command/files used to reproduce the original issue?

@psca
Copy link
Copy Markdown
Contributor Author

psca commented Mar 17, 2026

Thanks for the review!

Also updated the PR summary, the original description incorrectly framed this as specific to areas with no elevation data. The crash happens in single-output mode with XML/o5m output regardless, as the repro below shows.

Reproduction:

pyhgtmap -a 6:43:7:44 --max-nodes-per-tile=0 tests/data/N43E006.hgt

Root cause: typing.cast() is a runtime no-op, it returns its second argument unchanged. The old code passed a plain list[float] where a BBox NamedTuple was expected, which fails when downstream code accesses named fields like .min_lat. The fix constructs an actual BBox, which also required moving the import out of TYPE_CHECKING.

Longer-term, storing options.area as a BBox on Configuration would avoid re-parsing. Happy to follow up separately.

@psca psca changed the title fix: AttributeError in single-output mode when area has no elevation data fix: AttributeError in single-output mode with XML/o5m output Mar 17, 2026
@agrenott agrenott merged commit 3e81688 into agrenott:master Mar 17, 2026
15 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants