-
-
Notifications
You must be signed in to change notification settings - Fork 15
Add validate method for polar file #24 #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
c9cc9c2
c02a6b3
20f81ed
9d1c68b
0f1e060
591466b
5ef9365
a9e5694
9daa344
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,4 +5,5 @@ dist | |
| .tox | ||
| coverage.xml | ||
| .coverage* | ||
| *_cache | ||
| *_cache | ||
| venv/ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,10 +15,16 @@ | |
|
|
||
| # For detail about GNU see <http://www.gnu.org/licenses/>. | ||
| import math | ||
| import re | ||
| from io import TextIOWrapper | ||
| from typing import Dict, Optional, Tuple | ||
|
|
||
|
|
||
| class PolarError(Exception): | ||
| def __init__(self, message): | ||
|
||
| super().__init__(message) | ||
|
|
||
|
|
||
| class Polar: | ||
| def __init__(self, polar_path: str, f: Optional[TextIOWrapper] = None): | ||
| """ | ||
|
|
@@ -29,6 +35,7 @@ def __init__(self, polar_path: str, f: Optional[TextIOWrapper] = None): | |
| f : File | ||
| File object for passing an opened file | ||
| """ | ||
| self.validate_polar_file(polar_path) | ||
|
|
||
| self.tws = [] | ||
| self.twa = [] | ||
|
|
@@ -189,3 +196,98 @@ def get_twa_routage(self, tws: float, twa: float) -> float: | |
| if twa > twadown: | ||
| twa = twadown | ||
| return twa | ||
|
|
||
| # ---- Start validate function ---- | ||
| @staticmethod | ||
| def validate_polar_file(filepath): | ||
scyrock marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| """Validates the structure and content of a polar file. | ||
|
|
||
| Returns True if valid, raises PolarError with specific message if invalid. | ||
| """ | ||
| with open(filepath, "r") as f: | ||
| content = f.read() | ||
| lines = content.strip().split("\n") | ||
|
|
||
| # Check for empty file | ||
| if len(lines) == 1 and not lines[0] or not lines[0]: | ||
| raise PolarError("EMPTY_FILE") | ||
|
|
||
| # Process header (wind speeds) | ||
| Polar._validate_header(lines[0]) | ||
|
|
||
| # Check data rows | ||
| header_parts = re.split(r"\s+", lines[0].strip()) | ||
| expected_columns = len(header_parts) | ||
|
|
||
| for line in lines[1:]: | ||
| Polar._validate_data_row(line, expected_columns) | ||
|
|
||
| return True | ||
|
|
||
| @staticmethod | ||
| def _validate_header(header_line): | ||
| """Validates the header line containing wind speeds.""" | ||
| header_parts = re.split(r"\s+", header_line.strip()) | ||
|
|
||
| # Try to parse wind speeds (should be numeric) | ||
| try: | ||
scyrock marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| tws = [float(ws) for ws in header_parts[1:]] | ||
| except ValueError: | ||
| raise PolarError("WIND_SPEED_NOT_NUMERIC") | ||
|
|
||
| # Check for increasing wind speeds | ||
| if not all(tws[i] <= tws[i + 1] for i in range(len(tws) - 1)): | ||
| raise PolarError("WIND_SPEEDS_NOT_INCREASING") | ||
|
|
||
| return True | ||
|
|
||
| @staticmethod | ||
| def _validate_data_row(line, expected_columns): | ||
| """Validates a single data row in the polar file.""" | ||
| parts = re.split(r"\s+", line.strip()) | ||
|
|
||
| # Skip empty lines | ||
| if not parts or (len(parts) == 1 and not parts[0]): | ||
| raise PolarError("EMPTY_LINE") | ||
|
|
||
| # Check number of columns | ||
| if len(parts) != expected_columns: | ||
| raise PolarError("COLUMN_COUNT_MISMATCH") | ||
|
|
||
| # Validate TWA | ||
| Polar._validate_twa(parts[0]) | ||
|
|
||
| # Validate boat speeds | ||
| for speed in parts[1:]: | ||
| Polar._validate_boat_speed(speed) | ||
|
|
||
| return True | ||
|
|
||
| @staticmethod | ||
| def _validate_twa(twa_str): | ||
| """Validates a TWA (True Wind Angle) value.""" | ||
| try: | ||
| twa = float(twa_str) | ||
| if twa < 0 or twa > 180: | ||
| raise PolarError("TWA_OUT_OF_RANGE") | ||
| except ValueError: | ||
| raise PolarError("TWA_NOT_NUMERIC") | ||
|
|
||
| return True | ||
|
|
||
| @staticmethod | ||
| def _validate_boat_speed(speed_str): | ||
| """Validates a boat speed value.""" | ||
| if speed_str in ["", "-", "NaN", "NULL"]: | ||
| raise PolarError("EMPTY_VALUE") | ||
|
|
||
| try: | ||
| boat_speed = float(speed_str) | ||
| if boat_speed < 0: | ||
| raise PolarError("NEGATIVE_SPEED") | ||
| except ValueError: | ||
| raise PolarError("SPEED_NOT_NUMERIC") | ||
|
|
||
| return True | ||
|
|
||
| # ---- End validate function ---- | ||
Uh oh!
There was an error while loading. Please reload this page.