Last active
January 26, 2022 01:26
-
-
Save mjhong0708/675e2829c36ea43824933ccaa030973f to your computer and use it in GitHub Desktop.
Simple INCAR parser class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import Iterable, Union | |
Numeric = Union[int, float] | |
IncarValue = Union[bool, str, Numeric, Iterable[Union[str, Numeric]]] | |
class Incar: | |
def __init__(self, **kwargs): | |
self.__dict__ = kwargs | |
def __repr__(self) -> str: | |
attrs = ", ".join([f"{key}={val}" for key, val in self.__dict__.items()]) | |
return f"Incar({attrs})" | |
def __str__(self) -> str: | |
return self.__repr__() | |
def __eq__(self, other) -> bool: | |
if not self.__dict__.keys() == other.__dict__.keys(): | |
return False | |
for key in self.__dict__: | |
if self.__dict__[key] != other.__dict__[key]: | |
return False | |
return True | |
def to_string(self) -> str: | |
incar_lines = [] | |
for tag, val in self.__dict__.items(): | |
if val is not None: | |
incar_tag = tag | |
incar_val = self.validate_data(val) | |
incar_line = " = ".join([incar_tag, incar_val]) | |
incar_lines.append(incar_line) | |
return "\n".join(incar_lines) | |
def write(self, filename: str) -> None: | |
with open(filename, "w") as f: | |
incar_str = self.to_string() | |
f.write(incar_str) | |
@classmethod | |
def read(cls, filename: str): | |
kwargs = dict() | |
with open(filename, "r") as f: | |
lines = f.readlines() | |
for line in lines: | |
# Remove whitespace and skip if the line is empty or comment | |
line_stripped = line.strip() | |
if not line_stripped or line_stripped.startswith("#"): | |
continue | |
# Get tag and value | |
line_splitted = line_stripped.split("#")[0].split("=") | |
tag = line_splitted[0].strip() | |
val = line_splitted[1].strip() | |
# If value is array, split into list | |
# while preserving its type | |
_val_split = val.split() | |
if len(_val_split) == 1: | |
val_final = str_to_num_if_possible(_val_split[0]) | |
else: | |
val_final = [str_to_num_if_possible(val) for val in _val_split] # type: ignore | |
kwargs[tag] = val_final | |
return cls(**kwargs) | |
@staticmethod | |
def validate_data(data: IncarValue) -> str: | |
# If boolean | |
if isinstance(data, bool): | |
if data: | |
return ".TRUE." | |
else: | |
return ".FALSE." | |
# If iterable and not string | |
elif not isinstance(data, str) and hasattr(data, "__iter__"): | |
return " ".join(map(str, data)) # type: ignore | |
# Otherwise, return as str | |
else: | |
return str(data) | |
def str_to_num_if_possible(s: str) -> Union[str, Numeric]: | |
try: | |
val = int(s) | |
except ValueError: | |
try: | |
val = float(s) # type: ignore | |
except ValueError: | |
val = s # type: ignore | |
return val |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How to use
Create manually with python
Read & manimulate tag