diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7c27867 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,22 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/ios-shell.iml b/.idea/ios-shell.iml new file mode 100644 index 0000000..beb5060 --- /dev/null +++ b/.idea/ios-shell.iml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..751bf8e --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..cd7de99 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..d465484 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + { + "associatedIndex": 4 +} + + + + { + "keyToString": { + "Python.shell.executor": "Run", + "RunOnceActivity.ShowReadmeOnStart": "true", + "git-widget-placeholder": "Tyler__Branch", + "last_opened_file_path": "C:/Users/ZHANGD/Desktop/All Git Repo/ios-shell", + "settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable" + } +} + + + + + + + + + + + + + + + + + + + + + 1763164730975 + + + + \ No newline at end of file diff --git a/ios_shell/parsing.py b/ios_shell/parsing.py index d05faa2..34b7435 100644 --- a/ios_shell/parsing.py +++ b/ios_shell/parsing.py @@ -292,7 +292,7 @@ def get_history(contents: List[str]) -> Tuple[sections.History, List[str]]: """Parse the \\*HISTORY section""" history_dict, rest = get_section(contents, "history") programs = ( - [sections.Program(*elem) for elem in history_dict[PROGRAMS]] + [sections.Program(*elem.values()) for elem in history_dict[PROGRAMS]] if PROGRAMS in history_dict else [] ) @@ -413,6 +413,55 @@ def _postprocess_line(line: List[Any]) -> List[Any]: return [_process_item(item) for item in line] + +def handle_DMH_in_Data(lines: str, format: str): + fmt = format.strip("()") + fmt_list = [f.strip() for f in fmt.split(",")] + + # Use DMH position from the format list to remove character before and after each line + dmh_indices = [i for i, f in enumerate(fmt_list) if f == "DMH"] + first_dmh = dmh_indices[0] + last_dmh = dmh_indices[-1] + + width_before = sum(int(re.search(r"\d+", f).group()) if re.search(r"\d+", f) else 0 + for f in fmt_list[:first_dmh]) + width_after = sum(int(re.search(r"\d+", f).group()) if re.search(r"\d+", f) else 0 + for f in fmt_list[last_dmh + 1:]) + + new_lines = [] + for line in lines: + dmh_block = line[width_before: len(line) - width_after] + pattern = r"(\d+)\s+([\d.]+)\s*([NSEW])" + matches = re.findall(pattern, dmh_block) + + if len(matches) != 2: + new_lines.append(line) # keep line unchanged if DMH parsing fails + continue + + lat = lon = None + for deg, minute, hemi in matches: + value = float(deg) + float(minute) / 60.0 + if hemi in ("S", "W"): + value = -value + + if hemi in ("N", "S"): + lat = value + else: + lon = value + + new_line = ( + line[:width_before] + + f"{lat:11.4f}{lon:11.4f}" + + line[len(line) - width_after:]) + + new_lines.append(new_line) + + format = format.replace("DMH", "F11.4") + + return new_lines, format + + + def get_data(contents: str, format: str, records: int) -> Tuple[List[List[Any]], str]: """Process the data in the file""" lines = contents.splitlines() @@ -420,6 +469,10 @@ def get_data(contents: str, format: str, records: int) -> Tuple[List[List[Any]], lines.remove("") if len(lines) < records: raise ValueError(f"Insufficient data for requested number of records") + + if "DMH" in format: + lines, format = handle_DMH_in_Data(lines, format) + reader = ff.FortranRecordReader(format) data = [_postprocess_line(reader.read(line)) for line in lines[:records]] rest = "\n".join(lines[records:]) # pragma: no mutate diff --git a/ios_shell/sections.py b/ios_shell/sections.py index e7175f7..057ad10 100644 --- a/ios_shell/sections.py +++ b/ios_shell/sections.py @@ -42,8 +42,12 @@ def __init__( minimum = "0" if maximum.strip().upper() == "O": maximum = "0" - self.minimum = float(minimum) if minimum.strip() not in EMPTY else NAN - self.maximum = float(maximum) if maximum.strip() not in EMPTY else NAN + + #self.minimum = float(minimum) if minimum.strip() not in EMPTY else NAN + #self.maximum = float(maximum) if maximum.strip() not in EMPTY else NAN + + self.minimum = (NAN if minimum.strip() in EMPTY or "/" in minimum.strip() or ":" in minimum.strip() else float(minimum)) + self.maximum = (NAN if maximum.strip() in EMPTY or "/" in maximum.strip() or ":" in maximum.strip() else float(maximum)) class ChannelDetail: diff --git a/ios_shell/shell.py b/ios_shell/shell.py index 1770064..183364e 100644 --- a/ios_shell/shell.py +++ b/ios_shell/shell.py @@ -37,8 +37,15 @@ class ShellFile: @classmethod def fromfile(cls, filename, process_data=True): # pragma: no mutate """Construct a ShellFile object from the contents of a file.""" - with open(filename, "r", encoding="ASCII", errors="ignore") as f: - contents = f.read() + # with open(filename, "r", encoding="ASCII", errors="ignore") as f: + # contents = f.read() + try: + with open(filename, "r", encoding="utf-8") as f: + contents = f.read() + except UnicodeDecodeError: + with open(filename, "r", encoding="ANSI") as f: + contents = f.read() + try: return ShellFile.fromcontents(contents, process_data, filename=filename) except ValueError as e: diff --git a/ios_shell/utils.py b/ios_shell/utils.py index 685841f..1152e39 100644 --- a/ios_shell/utils.py +++ b/ios_shell/utils.py @@ -41,6 +41,7 @@ def format_string(format: str, kind: str, width: int, decimals: int) -> str: elif fortrantype in ["I"]: return f"I{width}" elif fortrantype.upper() in [ + "DD/MM/YYYY", "YYYY/MM/DD", "YYYY-MM-DD", "HH:MM", @@ -50,6 +51,11 @@ def format_string(format: str, kind: str, width: int, decimals: int) -> str: return f"A{len(fortrantype)+1}" elif fortrantype in ["' '", "NQ"]: return f"A{width}" + elif fortrantype in ["D"]: + if datatype in ["I"]: + return f"I{width}" + else: + return f"D{width}.{decimals}" else: return fortrantype diff --git a/pyproject.toml b/pyproject.toml index 7c07e02..c725abe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,9 @@ include = [ python = ">=3.8,<3.11" fortranformat = "^1.0.1" pandas = {version = "^1.4.2", optional = true} +numpy = "<2.0" + + [tool.poetry.dev-dependencies] pytest = "^6.2.5"