Skip to content
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

Deprecate get_string() methods in favor of get_str() #3231

Merged
merged 7 commits into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 35 additions & 14 deletions pymatgen/io/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@
import os
from collections.abc import MutableMapping
from pathlib import Path
from typing import Iterator
from zipfile import ZipFile

import numpy as np
from monty.io import zopen
from monty.json import MSONable

Expand All @@ -53,6 +55,11 @@ class InputFile(MSONable):
to __init__ as attributes.
"""

@abc.abstractmethod
def get_str(self) -> str:
"""Return a string representation of an entire input file."""

@np.deprecate(message="Use get_str instead")
@abc.abstractmethod
def get_string(self) -> str:
"""Return a string representation of an entire input file."""
Expand All @@ -65,12 +72,26 @@ def write_file(self, filename: str | Path) -> None:
filename: The filename to output to, including path.
"""
filename = filename if isinstance(filename, Path) else Path(filename)
with zopen(filename, "wt") as f:
f.write(self.get_string())
with zopen(filename, "wt") as file:
file.write(self.get_str())

@classmethod
@np.deprecate(message="Use from_str instead")
@abc.abstractmethod
def from_string(cls, contents: str) -> InputFile:
"""
Create an InputFile object from a string.

Args:
contents: The contents of the file as a single string

Returns:
InputFile
"""

@classmethod
@abc.abstractmethod
def from_str(cls, contents: str):
def from_str(cls, contents: str) -> InputFile:
"""
Create an InputFile object from a string.

Expand All @@ -96,8 +117,8 @@ def from_file(cls, path: str | Path):
with zopen(filename, "rt") as f:
return cls.from_str(f.read())

def __str__(self):
return self.get_string()
def __str__(self) -> str:
return self.get_str()


class InputSet(MSONable, MutableMapping):
Expand Down Expand Up @@ -132,11 +153,11 @@ def __init__(self, inputs: dict[str | Path, str | InputFile] | None = None, **kw
self._kwargs = kwargs
self.__dict__.update(**kwargs)

def __getattr__(self, k):
def __getattr__(self, key):
# allow accessing keys as attributes
if k in self._kwargs:
return self.get(k)
raise AttributeError(f"'{type(self).__name__}' object has no attribute {k!r}")
if key in self._kwargs:
return self.get(key)
raise AttributeError(f"'{type(self).__name__}' object has no attribute {key!r}")

def __copy__(self) -> InputSet:
cls = self.__class__
Expand All @@ -159,19 +180,19 @@ def __deepcopy__(self, memo: dict[int, InputSet]) -> InputSet:

return new_instance

def __len__(self):
def __len__(self) -> int:
return len(self.inputs)

def __iter__(self):
def __iter__(self) -> Iterator[str | Path]:
return iter(self.inputs)

def __getitem__(self, key):
def __getitem__(self, key) -> str | InputFile | slice:
return self.inputs[key]

def __setitem__(self, key, value):
def __setitem__(self, key: str | Path, value: str | InputFile) -> None:
self.inputs[key] = value

def __delitem__(self, key):
def __delitem__(self, key: str | Path) -> None:
del self.inputs[key]

def write_input(
Expand Down
127 changes: 82 additions & 45 deletions pymatgen/io/cp2k/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,11 @@ def as_dict(self):
dct["verbose"] = self.verbose
return dct

def get_string(self):
@np.deprecate(message="Use get_str instead")
def get_string(self, *args, **kwargs) -> str:
return self.get_str(*args, **kwargs)

def get_str(self) -> str:
"""String representation of Keyword."""
return str(self)

Expand Down Expand Up @@ -204,7 +208,7 @@ def __init__(self, keywords: Sequence[Keyword]):
self.keywords = list(keywords)

def __str__(self):
return self.get_string()
return self.get_str()

def __eq__(self, other: object) -> bool:
if not isinstance(other, type(self)):
Expand All @@ -228,7 +232,11 @@ def extend(self, lst: Sequence[Keyword]) -> None:
"""Extend the keyword list."""
self.keywords.extend(lst)

def get_string(self, indent=0):
@np.deprecate(message="Use get_str instead")
def get_string(self, *args, **kwargs) -> str:
return self.get_str(*args, **kwargs)

def get_str(self, indent: int = 0) -> str:
"""String representation of Keyword."""
return " \n".join("\t" * indent + str(k) for k in self.keywords)

Expand Down Expand Up @@ -306,7 +314,7 @@ def __init__(
self.keywords[k] = Keyword(k, v)

def __str__(self):
return self.get_string()
return self.get_str()

def __eq__(self, d):
d2 = copy.deepcopy(d)
Expand Down Expand Up @@ -552,12 +560,16 @@ def by_path(self, path: str):
s = s.get_section(p)
return s

def get_string(self):
@np.deprecate(message="Use get_str instead")
def get_string(self, *args, **kwargs) -> str:
return self.get_str(*args, **kwargs)

def get_str(self) -> str:
"""Get string representation of Section."""
return Section._get_string(self)
return Section._get_str(self)

@staticmethod
def _get_string(d, indent=0):
def _get_str(d, indent=0):
"""
Helper function to return a pretty string of the section. Includes indentation and
descriptions (if present).
Expand All @@ -576,11 +588,11 @@ def _get_string(d, indent=0):

for v in d.keywords.values():
if isinstance(v, KeywordList):
string += v.get_string(indent=indent + 1) + "\n"
string += f"{v.get_str(indent=indent + 1)}\n"
else:
string += "\t" * (indent + 1) + v.get_string() + "\n"
string += "\t" * (indent + 1) + v.get_str() + "\n"
for v in d.subsections.values():
string += v._get_string(v, indent + 1)
string += v._get_str(v, indent + 1)
string += "\t" * indent + "&END " + d.name + "\n"

return string
Expand Down Expand Up @@ -622,7 +634,7 @@ def __init__(self, sections: Sequence[Section]):
self.sections = list(sections)

def __str__(self):
return self.get_string()
return self.get_str()

def __eq__(self, other: object) -> bool:
if not isinstance(other, SectionList):
Expand All @@ -643,12 +655,16 @@ def __deepcopy__(self, memodict=None):
return SectionList(sections=[d.__deepcopy__() for d in self.sections])

@staticmethod
def _get_string(d, indent=0):
return " \n".join(s._get_string(s, indent) for s in d)
def _get_str(d, indent=0):
return " \n".join(s._get_str(s, indent) for s in d)

@np.deprecate(message="Use get_str instead")
def get_string(self, *args, **kwargs) -> str:
return self.get_str(*args, **kwargs)

def get_string(self):
def get_str(self) -> str:
"""Return string representation of section list."""
return SectionList._get_string(self.sections)
return SectionList._get_str(self.sections)

def get(self, d, index=-1):
"""
Expand All @@ -674,7 +690,7 @@ def verbosity(self, verbosity) -> None:
class Cp2kInput(Section):
"""
Special instance of 'Section' class that is meant to represent the overall cp2k input.
Distinguishes itself from Section by overriding get_string() to not print this section's
Distinguishes itself from Section by overriding get_str() to not print this section's
title and by implementing the file i/o.
"""

Expand All @@ -694,11 +710,11 @@ def __init__(self, name: str = "CP2K_INPUT", subsections: dict | None = None, **
**kwargs,
)

def get_string(self):
def get_str(self):
"""Get string representation of the Cp2kInput."""
s = ""
for v in self.subsections.values():
s += v.get_string()
s += v.get_str()
return s

@classmethod
Expand Down Expand Up @@ -808,7 +824,7 @@ def write_file(
os.mkdir(output_dir)
filepath = os.path.join(output_dir, input_filename)
with open(filepath, "w") as f:
f.write(self.get_string())
f.write(self.get_str())


class Global(Section):
Expand Down Expand Up @@ -2358,10 +2374,14 @@ def get_hash(self) -> str:
# usedforsecurity=False needed in FIPS mode (Federal Information Processing Standards)
# https://github.com/materialsproject/pymatgen/issues/2804
md5 = hashlib.new("md5", usedforsecurity=False) # hashlib.md5(usedforsecurity=False) is py39+
md5.update(self.get_string().lower().encode("utf-8"))
md5.update(self.get_str().lower().encode("utf-8"))
return md5.hexdigest()

def get_string(self):
@np.deprecate(message="Use get_str instead")
def get_string(self, *args, **kwargs) -> str:
return self.get_str(*args, **kwargs)

def get_str(self) -> str:
"""Get string representation."""
return str(self)

Expand Down Expand Up @@ -2426,11 +2446,21 @@ def nexp(self):
return [len(e) for e in self.exponents]

@typing.no_type_check
def get_string(self) -> str:
@np.deprecate(message="Use get_str instead")
def get_string(self, *args, **kwargs) -> str:
return self.get_str(*args, **kwargs)

def get_str(self) -> str:
"""Get standard cp2k GTO formatted string."""
if any(
getattr(self, x, None) is None
for x in ("info", "nset", "n", "lmax", "lmin", "nshell", "exponents", "coefficients")
if ( # written verbosely so mypy can perform type narrowing
self.info is None
or self.nset is None
or self.n is None
or self.lmax is None
or self.lmin is None
or self.nshell is None
or self.exponents is None
or self.coefficients is None
):
raise ValueError("Must have all attributes defined to get string representation")

Expand Down Expand Up @@ -2644,7 +2674,7 @@ def get_section(self) -> Section:
if self.name is None:
raise ValueError("Cannot get section without name attribute")

keywords = {"POTENTIAL": Keyword("", self.get_string())}
keywords = {"POTENTIAL": Keyword("", self.get_str())}
return Section(
name=self.name,
section_parameters=None,
Expand All @@ -2658,23 +2688,26 @@ def from_section(cls, section: Section) -> GthPotential:
"""Extract GTH-formatted string from a section and convert it to model."""
sec = copy.deepcopy(section)
sec.verbosity(False)
s = sec.get_string()
s = [_ for _ in s.split("\n") if not _.startswith("&")]
s = "\n".join(s)
return cls.from_str(s)
lst = sec.get_str().split("\n")
string = "\n".join(line for line in lst if not line.startswith("&"))
return cls.from_str(string)

def get_string(self):
@np.deprecate(message="Use get_str instead")
def get_string(self, *args, **kwargs) -> str:
return self.get_str(*args, **kwargs)

def get_str(self) -> str:
"""Convert model to a GTH-formatted string."""
if None in (
self.info,
self.n_elecs,
self.r_loc,
self.nexp_ppl,
self.c_exp_ppl,
self.radii,
self.nprj,
self.nprj_ppnl,
self.hprj_ppnl,
if ( # written verbosely so mypy can perform type narrowing
self.info is None
or self.n_elecs is None
or self.r_loc is None
or self.nexp_ppl is None
or self.c_exp_ppl is None
or self.radii is None
or self.nprj is None
or self.nprj_ppnl is None
or self.hprj_ppnl is None
):
raise ValueError("Must initialize all attributes in order to get string")

Expand Down Expand Up @@ -2799,14 +2832,18 @@ def from_str(cls):
def write_file(self, fn):
"""Write to a file."""
with open(fn, "w") as f:
f.write(self.get_string())
f.write(self.get_str())

@np.deprecate(message="Use get_str instead")
def get_string(self, *args, **kwargs) -> str:
return self.get_str(*args, **kwargs)

def get_string(self):
def get_str(self) -> str:
"""Get string representation."""
return "\n".join(b.get_string() for b in self.objects)
return "\n".join(b.get_str() for b in self.objects or [])

def __str__(self):
return self.get_string()
return self.get_str()


@dataclass
Expand Down
8 changes: 6 additions & 2 deletions pymatgen/io/feff/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,11 @@ def from_dict(d):
i[k] = v
return i

def get_string(self, sort_keys=False, pretty=False):
@np.deprecate(message="Use get_str instead")
def get_string(self, *args, **kwargs) -> str:
return self.get_str(*args, **kwargs)

def get_str(self, sort_keys: bool = False, pretty: bool = False) -> str:
"""
Returns a string representation of the Tags. The reason why this
method is different from the __str__ method is to provide options
Expand Down Expand Up @@ -666,7 +670,7 @@ def _stringify_val(val):
return str(val)

def __str__(self):
return self.get_string()
return self.get_str()

def write_file(self, filename="PARAMETERS"):
"""
Expand Down
Loading