Skip to content

Commit

Permalink
update docstrings, str and repr functions
Browse files Browse the repository at this point in the history
  • Loading branch information
“Dafydd committed Sep 13, 2024
1 parent 6b21a2c commit 425e6a1
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 31 deletions.
41 changes: 30 additions & 11 deletions cstar/base/additional_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@

class AdditionalCode:
"""
Additional code contributing to a unique instance of a base model, e.g. namelists, source modifications, etc.
Additional code contributing to a unique instance of a base model
Additional code is assumed to be kept in a single directory or repository (described by the `source` attribute)
Additional code is assumed to be kept in a single directory or
subdirectory of a repository (described by the `source` attribute)
with this structure:
<additional_code_dir>
Expand All @@ -30,12 +31,18 @@ class AdditionalCode:
The base model with which this additional code is associated
source: DataSource
Describes the location and type of source data (e.g. repository,directory)
subdir: str
Subdirectory of source.location in which the additional code is kept
(used if, e.g., source.location is a remote repository)
checkout_target: Optional, str
Used if source.source_type is 'repository'. A tag, git hash, or other target to check out.
Used if source.source_type is 'repository'.
A tag, git hash, or other target to check out.
source_mods: Optional, list of strs
Path(s) relative to the top level of `source.location` to any code that is needed to compile a unique instance of the base model
Path(s) relative to the subdirectory `subdir` of `source.location`
to any code that is needed to compile a unique instance of the base model
namelists: str or list of strs
Path(s) relative to the top level of `source.location` to any code that is needed at runtime for the base model
Path(s) relative to the subdirectory `subdir` of `source.location`
to any code that is needed at runtime for the base model
working_path: Path, default None
The local path to the additional code. Set when `get()` method is called.
Expand All @@ -45,7 +52,7 @@ class AdditionalCode:
Fetch the directory containing this additional code and copy it to `local_dir`.
If source.source_type is 'repository', and source.location_type is 'url',
clone repository to a temporary directory, checkout `checkout_target`,
and move files associated with this AdditionalCode instance to `local_dir`.
and move files in `subdir` associated with this AdditionalCode instance to `local_dir`.
check_exists_locally(local_dir):
Verify whether the files associated with this AdditionalCode instance can be found at `local_dir`
"""
Expand All @@ -69,13 +76,16 @@ def __init__(
location: str
url or path pointing to the additional code directory or repository, used to set `source` attribute
subdir: str
Subdirectory of "location" in which to look for files (e.g. if location points to a remote repository)
Subdirectory of `location` in which to look for files
(e.g. if `location` points to a remote repository)
checkout_target: Optional, str
Used if source.source_type is 'repository'. A tag, git hash, or other target to check out.
source_mods: Optional, str or list of strs
Path(s) relative to the top level of `source.location` to any code that is needed to compile a unique instance of the base model
Path(s) relative to the subdirectory `subdir` of `source.location`
to any code that is needed to compile a unique instance of the base model
namelists: Optional, str or list of strs
Path(s) relative to the top level of `source.location` to any code that is needed at runtime for the base model
Path(s) relative to the subdirectory `subdir` of `source.location`
to any code that is needed at runtime for the base model
Returns:
--------
Expand All @@ -102,7 +112,11 @@ def __str__(self) -> str:
base_str += "-" * (len(base_str) - 1)
base_str += f"\nBase model: {self.base_model.name}"
base_str += f"\nLocation: {self.source.location}"
base_str += f"\n Working path: {self.working_path}"
base_str += f"\nsubdirectory: {self.subdir}"
base_str += f"\nWorking path: {self.working_path}"
base_str += f"\nExists locally: {self.exists_locally}"
if not self.exists_locally:
base_str += " (get with AdditionalCode.get())"
if self.source_mods is not None:
base_str += (
"\nSource code modification files (paths relative to above location)):"
Expand All @@ -122,6 +136,7 @@ def __repr__(self) -> str:
repr_str = f"{self.__class__.__name__}("
repr_str += f"\nbase_model = <{self.base_model.__class__.__name__} instance>,"
repr_str += f"\nlocation = {self.source.location!r},"
repr_str += f"\nsubdir = {self.subdir!r}"
if hasattr(self, "checkout_target"):
repr_str += f"\ncheckout_target = {self.checkout_target!r},"
if hasattr(self, "source_mods") and self.source_mods is not None:
Expand All @@ -132,13 +147,17 @@ def __repr__(self) -> str:
# Additional info:
info_str = ""
if self.working_path is not None:
info_str += f"working_path: {self.working_path},"
info_str += f"working_path = {self.working_path},"
info_str += f"exists_locally = {self.exists_locally}"
if len(info_str) > 0:
repr_str += f"\nState: <{info_str}>"
return repr_str

@property
def exists_locally(self):
"""
Determine whether a local working copy of the AdditionalCode exists at self.working_path (bool)
"""
if self.working_path is None:
return False

Expand Down
17 changes: 10 additions & 7 deletions cstar/base/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from cstar.base.base_model import BaseModel
from cstar.base.input_dataset import InputDataset

from cstar.base.utils import _list_to_concise_str

if TYPE_CHECKING:
from cstar.base.additional_code import AdditionalCode
Expand All @@ -18,7 +18,7 @@ class Component(ABC):
base_model: BaseModel
An object pointing to the unmodified source code of a model handling an individual
aspect of the simulation such as biogeochemistry or ocean circulation
additional_code: AdditionalCode or list of AdditionalCodes
additional_code: AdditionalCode
Additional code contributing to a unique instance of a base model,
e.g. namelists, source modifications, etc.
input_datasets: list of InputDatasets
Expand Down Expand Up @@ -105,12 +105,15 @@ def __str__(self) -> str:
def __repr__(self) -> str:
repr_str = f"{self.__class__.__name__}("
repr_str += f"\nbase_model = <{self.base_model.__class__.__name__} instance>, "
repr_str += f"\nadditional_code = <{self.additional_code.__class__.__name__} instance>, "
repr_str += "\ninput_datasets = ["
if self.additional_code is not None:
repr_str += f"\nadditional_code = <{self.additional_code.__class__.__name__} instance>, "
else:
repr_str += "\n additional_code = None"
ID_list = []
for i, inp in enumerate(self.input_datasets):
repr_str += f"\n <{inp.__class__.__name__} from {inp.source.basename}>, "
repr_str = repr_str.strip(", ")
repr_str += "],"
ID_list.append(f"<{inp.__class__.__name__} from {inp.source.basename}>")

repr_str += f"\ninput_datasets = {_list_to_concise_str(ID_list,pad=18,items_are_strs=False)}"
repr_str += f"\ndiscretization = {self.discretization.__repr__()}"
repr_str += "\n)"

Expand Down
18 changes: 13 additions & 5 deletions cstar/base/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,9 @@ def _replace_text_in_file(file_path: str | Path, old_text: str, new_text: str) -
temp_file_path.rename(file_path)


def _list_to_concise_str(input_list, item_threshold=4, pad=16, show_item_count=True):
def _list_to_concise_str(
input_list, item_threshold=4, pad=16, items_are_strs=True, show_item_count=True
):
"""
Take a list and return a concise string representation of it
Expand All @@ -201,6 +203,8 @@ def _list_to_concise_str(input_list, item_threshold=4, pad=16, show_item_count=T
The number of items beyond which to truncate the str to item0,...itemN
pad (int, default = 16):
The number of whitespace characters to prepend newlines with
items_are_strs (bool, default = True):
Will use repr formatting ([item1,item2]->['item1','item2']) for lists of strings
show_item_count (bool, default = True):
Will add <N items> to the end of a truncated representation
Expand All @@ -226,13 +230,17 @@ def _list_to_concise_str(input_list, item_threshold=4, pad=16, show_item_count=T
else:
count_str = ""
if len(input_list) > item_threshold:
list_str += f"[{input_list[0]!r},"
list_str += f"\n{pad_str}{input_list[1]!r},"
list_str += f"[{repr(input_list[0]) if items_are_strs else input_list[0]},"
list_str += (
f"\n{pad_str}{repr(input_list[1]) if items_are_strs else input_list[1]},"
)
list_str += f"\n{pad_str} ..."
list_str += f"\n{pad_str}{input_list[-1]!r}] {count_str}"
list_str += f"\n{pad_str}{repr(input_list[-1]) if items_are_strs else input_list[-1]}] {count_str}"
else:
list_str += "["
list_str += f",\n{pad_str}".join(repr(listitem) for listitem in input_list)
list_str += f",\n{pad_str}".join(
(repr(listitem) if items_are_strs else listitem) for listitem in input_list
)
list_str += "]"
return list_str

Expand Down
17 changes: 9 additions & 8 deletions cstar/roms/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class ROMSComponent(Component):
input_datasets: list of InputDatasets
Any spatiotemporal data needed to run this instance of ROMS
e.g. initial conditions, surface forcing, etc.
additional_code: AdditionalCode or list of AdditionalCodes
additional_code: AdditionalCode
Additional code contributing to a unique instance of this ROMS run
e.g. namelists, source modifications, etc.
discretization: ROMSDiscretization
Expand Down Expand Up @@ -131,13 +131,12 @@ def pre_run(self) -> None:
This method:
1. goes through any netcdf files associated with InputDataset objects belonging
to this ROMSComponent instance and runs `partit`, a ROMS program used to
partition netcdf files such that there is one file per processor.
to this ROMSComponent instance and partitions them such that there is one file per processor.
The partitioned files are stored in a subdirectory `PARTITIONED` of
InputDataset.working_path
2. Replaces the template strings INPUT_DIR and MARBL_NAMELIST_DIR (if present)
in the roms namelist file (typically `roms.in`) used to run the model with
2. Replaces placeholder strings (if present) representing, e.g. input file paths
in a template roms namelist file (typically `roms.in_TEMPLATE`) used to run the model with
the respective paths to input datasets and any MARBL namelists (if this ROMS
component belongs to a case for which MARBL is also a component).
The namelist file is sought in
Expand Down Expand Up @@ -242,12 +241,15 @@ def run(
This method creates a temporary file to be submitted to the job scheduler (if any)
on the calling machine, then submits it. By default the job requests the maximum
walltime. It calculates the number of nodes and cores-per-node to request based on
the number of cores required by the job, `ROMSComponent.n_procs_tot`.
the number of cores required by the job, `ROMSComponent.discretization.n_procs_tot`.
Parameters:
-----------
account_key: str, default None
The users account key on the system
output_dir: str or Path:
The path to the directory in which model output will be saved. This is by default
the directory from which the ROMS executable will be called.
walltime: str, default _CSTAR_SYSTEM_MAX_WALLTIME
The requested length of the job, HH:MM:SS
job_name: str, default 'my_roms_run'
Expand Down Expand Up @@ -415,8 +417,7 @@ def post_run(self, output_dir=None) -> None:
Performs post-processing steps associated with this ROMSComponent object.
This method goes through any netcdf files produced by the model in
`output_dir` and runs `ncjoin`,
a ROMS program used to join netcdf files that are produced separately by each processor.
`output_dir` and joins netcdf files that are produced separately by each processor.
Parameters:
-----------
Expand Down

0 comments on commit 425e6a1

Please sign in to comment.