You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The user config follows the same format as the bundled bootstrap file. Sources defined in the user config will override or extend those in the bundled config, allowing users to:
134
+
- Add custom DFN repositories
135
+
- Point to forks of existing repositories (useful for testing experimental schema versions)
136
+
- Override default refs for existing sources
137
+
138
+
**Implementation note**: The user config path logic (`get_user_config_path("dfn")`) is shared across all three APIs (Models, Programs, DFNs) via `modflow_devtools.config`, but each API implements its own `merge_bootstrap()` function using API-specific bootstrap schemas.
139
+
127
140
#### Sample bootstrap file
128
141
129
142
```toml
@@ -190,13 +203,13 @@ Or for v1/v1.1, no spec file needed - everything inferred.
190
203
191
204
#### Registry file format
192
205
193
-
A `dfns.toml` registry file for **discovery and distribution**:
206
+
A **`dfns.toml`** registry file for **discovery and distribution** (the specific naming distinguishes it from `models.toml` and `programs.toml`):
194
207
195
208
```toml
196
-
# Registry metadata (optional)
209
+
# Registry metadata (top-level, optional)
210
+
schema_version = "1.0"
197
211
generated_at = "2025-01-02T10:30:00Z"
198
212
devtools_version = "1.9.0"
199
-
registry_schema_version = "1.0"
200
213
201
214
[metadata]
202
215
ref = "6.6.0" # Optional, known from discovery context
@@ -533,50 +546,23 @@ Examples:
533
546
534
547
### Registry classes
535
548
536
-
#### DfnRegistry (abstract base)
537
-
538
-
Similar to `ModelRegistry` and `ProgramRegistry`, defines the contract:
539
-
540
-
```python
541
-
class DfnRegistry(ABC):
542
-
@property
543
-
@abstractmethod
544
-
def spec(self) -> DfnSpec:
545
-
"""Get the full DFN specification."""
546
-
pass
547
-
548
-
@property
549
-
@abstractmethod
550
-
def ref(self) -> str:
551
-
"""Get the git ref for this registry."""
552
-
pass
549
+
The registry class hierarchy is based on a Pydantic `DfnRegistry` base class:
553
550
554
-
def get_dfn(self, component: str) -> Dfn:
555
-
"""
556
-
Get a parsed DFN for the specified component.
557
-
Convenience method for spec[component].
558
-
"""
559
-
return self.spec[component]
551
+
**`DfnRegistry` (base class)**:
552
+
- Pydantic model with optional `meta` field for registry metadata
553
+
- Provides access to a `DfnSpec` (the full parsed specification)
554
+
- Can be instantiated directly for data-only use (e.g., loading/parsing TOML files)
555
+
- Key properties:
556
+
- `spec` - The full DFN specification (lazy-loaded)
557
+
- `ref` - Git ref for this registry
558
+
- `get_dfn(component)` - Convenience for `spec[component]`
559
+
- `get_dfn_path(component)` - Get local path to DFN file
560
+
- `schema_version` - Convenience for `spec.schema_version`
561
+
- `components` - Convenience for `dict(spec.items())`
560
562
561
-
@abstractmethod
562
-
def get_dfn_path(self, component: str) -> Path:
563
-
"""Get the local path to a DFN file (fetching if needed)."""
564
-
pass
563
+
**`RemoteDfnRegistry(DfnRegistry)`**:
565
564
566
-
@property
567
-
def schema_version(self) -> str:
568
-
"""Get the schema version. Convenience for spec.schema_version."""
569
-
return self.spec.schema_version
570
-
571
-
@property
572
-
def components(self) -> dict[str, Dfn]:
573
-
"""Get all components. Convenience for dict(spec.items())."""
574
-
return dict(self.spec.items())
575
-
```
576
-
577
-
#### RemoteDfnRegistry
578
-
579
-
Handles remote registry discovery, caching, and DFN fetching:
565
+
Handles remote registry discovery, caching, and DFN fetching. Constructs DFN file URLs dynamically from bootstrap metadata:
580
566
581
567
```python
582
568
class RemoteDfnRegistry(DfnRegistry):
@@ -590,45 +576,13 @@ class RemoteDfnRegistry(DfnRegistry):
@@ -641,18 +595,18 @@ class RemoteDfnRegistry(DfnRegistry):
641
595
642
596
def get_dfn_path(self, component: str) -> Path:
643
597
# Use Pooch to fetch file (from cache or remote)
644
-
# Pooch constructs full URL from base_url + filename
598
+
# Pooch constructs full URL from base_url + filename at runtime
645
599
filename = self._get_filename(component)
646
600
return Path(self._pooch.fetch(filename))
647
601
```
648
602
649
603
**Benefits of dynamic URL construction**:
650
-
- Registry files are smaller and simpler
651
-
- Users can substitute personal forks by modifying bootstrap file
604
+
- Registry files are smaller and simpler (no URLs stored)
605
+
- Users can test against personal forks by modifying bootstrap file
652
606
- Single source of truth for repository location
653
607
- URLs adapt automatically when repo/path changes
654
608
655
-
#### LocalDfnRegistry
609
+
**`LocalDfnRegistry(DfnRegistry)`**:
656
610
657
611
For developers working with local DFN files:
658
612
@@ -680,6 +634,11 @@ class LocalDfnRegistry(DfnRegistry):
680
634
raise ValueError(f"Component {component} not found in {self.path}")
681
635
```
682
636
637
+
**Design decisions**:
638
+
- **Pydantic-based** (not ABC) - allows direct instantiation for data-only use cases
639
+
- **Dynamic URL construction** - DFN file URLs constructed at runtime, not stored in registry
640
+
- **No `MergedRegistry`** - users typically work with one MODFLOW 6 version at a time, so merging across versions doesn't make sense
641
+
683
642
### Module-level API
684
643
685
644
Convenient module-level functions:
@@ -1383,6 +1342,24 @@ The DFNs API deliberately mirrors the Models and Programs API architecture for c
1383
1342
1384
1343
This consistency benefits both developers and users with a familiar experience across all three APIs.
1385
1344
1345
+
## Cross-API Consistency
1346
+
1347
+
The DFNs API follows the same design patterns as the Models and Programs APIs for consistency. See the **Cross-API Consistency** section in `models.md` for full details.
1348
+
1349
+
**Key shared patterns**:
1350
+
- Pydantic-based registry classes (not ABCs)
1351
+
- Dynamic URL construction (URLs built at runtime, not stored in registries)
1352
+
- Separate bootstrap and user config files (`dfn-bootstrap.toml`)
0 commit comments