Skip to content

Add tqdm progress bar for tile downloads#9

Open
swhitt wants to merge 3 commits into
JustDr00py:mainfrom
swhitt:add-progress-bar
Open

Add tqdm progress bar for tile downloads#9
swhitt wants to merge 3 commits into
JustDr00py:mainfrom
swhitt:add-progress-bar

Conversation

@swhitt
Copy link
Copy Markdown

@swhitt swhitt commented Dec 28, 2025

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Dec 28, 2025

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Unhandled future errors: The new progress-loop calls future.result() without handling exceptions from worker
threads, which can crash the run and prevent a graceful completion summary.

Referred Code
with tqdm(total=total_tiles, desc="Downloading", unit="tile") as pbar:
    for future in as_completed(futures):
        tile_path, status = future.result()
        if status == "downloaded":
            new_tiles += 1
            pbar.update(1)
        elif status == "cached":
            cached_tiles += 1
            pbar.total -= 1
            pbar.refresh()

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Raw exception printing: The new/retained error path prints the raw exception ({e}) directly to stdout, which may
leak internal details depending on runtime context.

Referred Code
except Exception as e:
    print(f"Error downloading tile {x},{y},{zoom}: {e}")
    return None, "failed"

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Unstructured console output: The added runtime status output uses unstructured print() statements (including filesystem
paths) rather than structured logging, which may be unsuitable for secure/auditable log
pipelines.

Referred Code
print(f"Generating tiles for bounds: N:{north}, S:{south}, E:{east}, W:{west}")
print(f"Zoom levels: {min_zoom} to {max_zoom}")
print(f"Source: {source}")
print(f"Output: {self.output_dir}")
print(f"Workers: {max_workers}, Delay: {self.delay}s")

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Dec 28, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Track and handle failed tiles
Suggestion Impact:The commit adds a failed_tiles counter, handles the "failed" status from futures, increments failed_tiles on exceptions, and reports failed counts in the completion message. It also changes progress bar updating logic so the loop always advances, avoiding stalling when failures occur.

code diff:

@@ -196,6 +196,7 @@
         total_tiles = 0
         new_tiles = 0
         cached_tiles = 0
+        failed_tiles = 0
         
         # Calculate total tiles for progress tracking
         for zoom in range(min_zoom, max_zoom + 1):
@@ -243,23 +244,26 @@
                         futures.append(future)
             
             # Process completed downloads
-            with tqdm(total=total_tiles, desc="Downloading", unit="tile") as pbar:
+            with tqdm(total=total_tiles, desc="Processing", unit="tile") as pbar:
                 for future in as_completed(futures):
                     try:
                         tile_path, status = future.result()
                         if status == "downloaded":
                             new_tiles += 1
-                            pbar.update(1)
                         elif status == "cached":
                             cached_tiles += 1
-                            pbar.total -= 1
-                            pbar.refresh()
+                        elif status == "failed":
+                            failed_tiles += 1
                     except Exception:
-                        pbar.total -= 1
-                        pbar.refresh()
+                        failed_tiles += 1
+                    pbar.update(1)
+                    pbar.set_postfix_str(f"new: {new_tiles}, cached: {cached_tiles}")
         
         elapsed = time.time() - start_time
-        print(f"Completed! {new_tiles} downloaded, {cached_tiles} cached in {elapsed:.1f}s")
+        if failed_tiles:
+            print(f"Completed! {new_tiles} downloaded, {cached_tiles} cached, {failed_tiles} failed in {elapsed:.1f}s")
+        else:
+            print(f"Completed! {new_tiles} downloaded, {cached_tiles} cached in {elapsed:.1f}s")

Handle the "failed" tile download status in the progress bar loop to prevent it
from stalling on errors. Track and report the number of failed downloads.

meshtastic_tiles.py [246-255]

+failed_tiles = 0
 with tqdm(total=total_tiles, desc="Downloading", unit="tile") as pbar:
     for future in as_completed(futures):
         tile_path, status = future.result()
         if status == "downloaded":
             new_tiles += 1
             pbar.update(1)
         elif status == "cached":
             cached_tiles += 1
             pbar.total -= 1
             pbar.refresh()
+        elif status == "failed":
+            failed_tiles += 1
+            pbar.total -= 1
+            pbar.refresh()

[Suggestion processed]

Suggestion importance[1-10]: 8

__

Why: This suggestion correctly identifies a bug where the progress bar would stall if a tile download fails, as the "failed" status is not handled. Adding a case for "failed" tiles fixes this bug and improves the robustness of the error handling.

Medium
General
Improve progress bar implementation for safety
Suggestion Impact:The commit removed the unsafe pattern of decrementing `pbar.total`/refreshing for cached/exception cases, changed the tqdm description to "Processing", updated the progress bar once per completed future, and added a postfix string showing live counts (new vs cached). It also extended the logic to track failed tiles.

code diff:

-            with tqdm(total=total_tiles, desc="Downloading", unit="tile") as pbar:
+            with tqdm(total=total_tiles, desc="Processing", unit="tile") as pbar:
                 for future in as_completed(futures):
                     try:
                         tile_path, status = future.result()
                         if status == "downloaded":
                             new_tiles += 1
-                            pbar.update(1)
                         elif status == "cached":
                             cached_tiles += 1
-                            pbar.total -= 1
-                            pbar.refresh()
+                        elif status == "failed":
+                            failed_tiles += 1
                     except Exception:
-                        pbar.total -= 1
-                        pbar.refresh()
+                        failed_tiles += 1
+                    pbar.update(1)
+                    pbar.set_postfix_str(f"new: {new_tiles}, cached: {cached_tiles}")
         

Improve the tqdm progress bar by tracking all processed tiles and displaying a
live breakdown of downloaded vs. cached tiles using a postfix, instead of
modifying the bar's total during iteration.

meshtastic_tiles.py [246-255]

-with tqdm(total=total_tiles, desc="Downloading", unit="tile") as pbar:
+with tqdm(total=total_tiles, desc="Processing", unit="tile") as pbar:
     for future in as_completed(futures):
         tile_path, status = future.result()
         if status == "downloaded":
             new_tiles += 1
-            pbar.update(1)
         elif status == "cached":
             cached_tiles += 1
-            pbar.total -= 1
-            pbar.refresh()
+        
+        pbar.update(1)
+        pbar.set_postfix_str(f"Downloaded: {new_tiles}, Cached: {cached_tiles}")

[Suggestion processed]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that modifying pbar.total is poor practice and can lead to a confusing UI. The proposed change to track all tiles and use a postfix is a significant improvement in code quality, user experience, and adherence to tqdm best practices.

Medium
  • Update

@swhitt swhitt changed the title Add tqdm progress bar for tile downloads Add tqdm progress bar for tile downloads Dec 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Given a coords box, not every tile inside the box is downloaded Metadata overwrites instead of appending.

1 participant