Skip to content

Commit d77b68a

Browse files
authored
make Component.load a classmethod (#283)
prep for wiring up the loader. Component.load() needs to be a classmethod not an instance method. add tests for the plumbing
1 parent 937b6e2 commit d77b68a

File tree

5 files changed

+522
-20
lines changed

5 files changed

+522
-20
lines changed

flopy4/mf6/__init__.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,20 @@ class WriteError(Exception):
2525
pass
2626

2727

28-
def _load_mf6(path: Path) -> Component:
28+
def _load_mf6(cls, path: Path) -> Component:
29+
"""Load MF6 format file into a component instance."""
2930
with open(path, "r") as fp:
3031
return structure(load_mf6(fp), path)
3132

3233

33-
def _load_json(path: Path) -> Component:
34+
def _load_json(cls, path: Path) -> Component:
35+
"""Load JSON format file into a component instance."""
3436
with open(path, "r") as fp:
3537
return structure(load_json(fp), path)
3638

3739

38-
def _load_toml(path: Path) -> Component:
40+
def _load_toml(cls, path: Path) -> Component:
41+
"""Load TOML format file into a component instance."""
3942
with open(path, "rb") as fp:
4043
return structure(load_toml(fp), path)
4144

flopy4/mf6/component.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from abc import ABC
22
from collections.abc import MutableMapping
3+
from os import PathLike
34
from pathlib import Path
45
from typing import Any, ClassVar, Optional
56

@@ -132,16 +133,12 @@ def get_dfn(cls) -> Dfn:
132133
blocks=blocks,
133134
)
134135

135-
def load(self, format: str = MF6) -> None:
136+
@classmethod
137+
def load(cls, path: str | PathLike, format: str = MF6) -> None:
136138
"""Load the component and any children."""
137-
# TODO: setting filename is a temp hack to get the parent's
138-
# name as this component's filename stem, if it has one. an
139-
# actual solution is to auto-set the filename when children
140-
# are attached to parents.
141-
self.filename = self.filename or self.default_filename()
142-
self._load(format=format)
139+
self = cls._load(path, format=format) # Get the instance
143140
for child in self.children.values(): # type: ignore
144-
child.load(format=format)
141+
child.__class__.load(child.path, format=format)
145142

146143
def write(self, format: str = MF6, context: Optional[WriteContext] = None) -> None:
147144
"""

flopy4/mf6/context.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,21 @@ def path(self) -> Path:
4848
self.filename = self.filename or self.default_filename()
4949
return self.workspace / self.filename
5050

51-
def load(self, format=MF6):
52-
with cd(self.workspace):
53-
super().load(format=format)
51+
@classmethod
52+
def load(cls, path, format=MF6):
53+
"""
54+
Load the context component and children.
55+
56+
Children are loaded relative to the parent's workspace directory,
57+
so their paths are resolved within that workspace.
58+
"""
59+
# Load the instance first
60+
instance = cls._load(path, format=format)
61+
62+
# Load children within the workspace context
63+
with cd(instance.workspace):
64+
for child in instance.children.values(): # type: ignore
65+
child.__class__.load(child.path, format=format)
5466

5567
def write(self, format=MF6, context=None):
5668
with cd(self.workspace):

flopy4/uio.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ def register_writer(self, cls, format, function):
5555
raise ValueError(f"Writer for format {format} already registered.")
5656
self._writers[cls, format] = function
5757

58-
def load(self, cls, instance, *args, format=None, **kwargs):
58+
def load(self, cls, *args, format=None, **kwargs):
5959
_load = self.get_loader(cls, format)
60-
return _load(instance, *args, **kwargs)
60+
return _load(cls, *args, **kwargs)
6161

6262
def write(self, cls, instance, *args, format=None, **kwargs):
6363
_write = self.get_writer(cls, format)
@@ -76,16 +76,16 @@ class IO(property):
7676
See the `astropy` source for more details/motivation.
7777
"""
7878

79-
def __get__(self, instance, owner_cls):
80-
return self.fget(instance, owner_cls)
79+
def __get__(self, instance, cls):
80+
return self.fget(instance, cls)
8181

8282

8383
class IODescriptor:
8484
"""Base class for file IO operation descriptors."""
8585

8686
def __init__(self, instance, cls, op: Op, registry: Registry | None = None):
8787
self._registry = registry or DEFAULT_REGISTRY
88-
self._instance = instance
88+
self._instance = instance # None for loaders
8989
self._cls = cls
9090
self._op: Op = op
9191

@@ -111,7 +111,7 @@ def __init__(self, instance, cls):
111111
super().__init__(instance, cls, "load", registry=DEFAULT_REGISTRY)
112112

113113
def __call__(self, *args, **kwargs):
114-
return self.registry.load(self._cls, self._instance, *args, **kwargs)
114+
return self.registry.load(self._cls, *args, **kwargs)
115115

116116

117117
class Writer(IODescriptor):

0 commit comments

Comments
 (0)