Skip to content

Commit 84cafea

Browse files
authored
Merge branch 'main' into 624_prestack_schema
2 parents 5bc972c + 693bf0b commit 84cafea

35 files changed

+1547
-2431
lines changed

docs/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ sphinx==8.2.3
88
sphinx-click==6.1.0
99
sphinx-copybutton==0.5.2
1010
sphinx-design==0.6.1
11+
ipywidgets==8.1.7

docs/template_registry.md

Lines changed: 72 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,182 +1,114 @@
11
# Template Registry
22

3-
A thread-safe singleton registry for managing dataset templates in MDIO applications.
3+
A simple, thread-safe place to discover and fetch dataset templates for MDIO.
44

5-
## Overview
5+
## Why use it
66

7-
The `TemplateRegistry` implements the singleton pattern to ensure there's only one instance managing all dataset templates throughout the application lifecycle. This provides a centralized registry for template management with thread-safe operations.
7+
- One place to find all available templates
8+
- Safe to use across threads and the whole app (singleton)
9+
- Every fetch gives you your own editable copy (no side effects)
10+
- Comes preloaded with common seismic templates
811

9-
## Features
10-
11-
- **Singleton Pattern**: Ensures only one registry instance exists
12-
- **Thread Safety**: All operations are thread-safe using locks
13-
- **Global Access**: Convenient global functions for common operations
14-
- **Advanced Support**: Reset functionality for environment re-usability.
15-
- **Default Templates**: The registry is instantiated with the default set of templates:
16-
- PostStack2DTime
17-
- PostStack3DTime
18-
- SeismicPreStack
19-
- PreStackCdpGathers3DTime
20-
- PreStackShotGathers3DTime
21-
- PostStack2DDepth
22-
- PostStack3DDepth
23-
- PreStackCdpGathers3DDepth
24-
- PreStackShotGathers3DDepth
25-
26-
## Usage
12+
```{note}
13+
Fetching a template with `get_template()` returns a deep copy. Editing it will not change the
14+
registry or anyone else’s copy.
15+
```
2716

28-
### Basic Usage
17+
## Quick start
2918

3019
```python
31-
from mdio.builder.template_registry import TemplateRegistry
20+
from mdio.builder.template_registry import get_template, list_templates
3221

33-
# Get the singleton instance
34-
registry = TemplateRegistry()
22+
# See what's available
23+
print(list_templates())
24+
# e.g. ["Seismic2DPostStackTime", "Seismic3DPostStackDepth", ...]
3525

36-
# Or use the class method
37-
registry = TemplateRegistry.get_instance()
26+
# Grab a template by name
27+
template = get_template("Seismic3DPostStackTime")
3828

39-
# Register a template
40-
template = MyDatasetTemplate()
41-
template_name = registry.register(template)
42-
print(f"Registered template named {template_name}")
29+
# Customize your copy (safe)
30+
template.add_units({"amplitude": "unitless"})
31+
```
4332

44-
# Retrieve a template using a well-known name
45-
template = registry.get("my_template")
46-
# Retrieve a template using the name returned when the template was registered
47-
template = registry.get(template_name)
33+
## Common tasks
4834

49-
# Check if template exists
50-
if registry.is_registered("my_template"):
51-
print("Template is registered")
35+
### Fetch a template you can edit
5236

53-
# List all templates
54-
template_names = registry.list_all_templates()
55-
```
37+
```python
38+
from mdio.builder.template_registry import get_template
5639

57-
### Global Functions
40+
template = get_template("Seismic2DPostStackDepth")
41+
# Use/modify template freely — it’s your copy
42+
```
5843

59-
For convenience, you can use global functions that operate on the singleton instance:
44+
### List available templates
6045

6146
```python
62-
from mdio.builder.template_registry import (
63-
register_template,
64-
get_template,
65-
is_template_registered,
66-
list_templates
67-
)
47+
from mdio.builder.template_registry import list_templates
6848

69-
# Register a template globally
70-
register_template(Seismic3DTemplate())
49+
names = list_templates()
50+
for name in names:
51+
print(name)
52+
```
7153

72-
# Get a template
73-
template = get_template("seismic_3d")
54+
### Check if a template exists
7455

75-
# Check registration
76-
if is_template_registered("seismic_3d"):
77-
print("Template available")
56+
```python
57+
from mdio.builder.template_registry import is_template_registered
7858

79-
# List all registered templates
80-
templates = list_templates()
59+
if is_template_registered("Seismic3DPostStackTime"):
60+
... # safe to fetch
8161
```
8262

83-
### Multiple Instantiation
63+
### Register your own template (optional)
8464

85-
The singleton pattern ensures all instantiations return the same object:
65+
If you have a custom template class, register an instance so others can fetch it by name:
8666

8767
```python
88-
registry1 = TemplateRegistry()
89-
registry2 = TemplateRegistry()
90-
registry3 = TemplateRegistry.get_instance()
68+
from typing import Any
69+
from mdio.builder.template_registry import register_template
70+
from mdio.builder.templates.base import AbstractDatasetTemplate
71+
from mdio.builder.templates.types import SeismicDataDomain
9172

92-
# All variables point to the same instance
93-
assert registry1 is registry2 is registry3
94-
```
9573

96-
## API Reference
74+
class MyTemplate(AbstractDatasetTemplate):
75+
def __init__(self, domain: SeismicDataDomain = "time"):
76+
super().__init__(domain)
9777

98-
```{eval-rst}
99-
.. automodule:: mdio.builder.template_registry
100-
:members:
101-
```
78+
@property
79+
def _name(self) -> str:
80+
# The public name becomes something like "MyTemplateTime"
81+
return f"MyTemplate{self._data_domain.capitalize()}"
10282

103-
## Thread Safety
83+
def _load_dataset_attributes(self) -> dict[str, Any]:
84+
return {"surveyType": "2D", "gatherType": "custom"}
10485

105-
All operations on the registry are thread-safe:
10686

107-
```python
108-
import threading
109-
110-
def register_templates():
111-
registry = TemplateRegistry()
112-
for i in range(10):
113-
template = MyTemplate(f"template_{i}")
114-
registry.register(template)
115-
116-
# Multiple threads can safely access the registry
117-
threads = [threading.Thread(target=register_templates) for _ in range(5)]
118-
for thread in threads:
119-
thread.start()
120-
for thread in threads:
121-
thread.join()
87+
# Make it available globally
88+
registered_name = register_template(MyTemplate("time"))
89+
print(registered_name) # "MyTemplateTime"
12290
```
12391

124-
## Best Practices
92+
```{tip}
93+
Use `list_templates()` to discover the exact names to pass to `get_template()`.
94+
```
12595

126-
1. **Use Global Functions**: For simple operations, prefer the global convenience functions
127-
2. **Register Early**: Register all templates during application startup
128-
3. **Thread Safety**: The registry is thread-safe, but individual templates may not be
129-
4. **Testing Isolation**: Always reset the singleton in test setup/teardown
96+
## Troubleshooting
13097

131-
## Example: Complete Template Management
98+
- KeyError: “Template 'XYZ' is not registered.”
99+
- The name is wrong or not registered yet.
100+
- Call `list_templates()` to see valid names, or `is_template_registered(name)` to check first.
132101

133-
```python
134-
from mdio.builder.template_registry import TemplateRegistry
135-
from mdio.builder.templates.seismic_3d_poststack import Seismic3DPostStackTemplate
136-
from mdio.builder.schemas.v1 import Seismic3DPostStackTimeTemplate
137-
from mdio.builder.schemas.v1 import Seismic3DPreStackTemplate
138-
139-
140-
def setup_templates():
141-
"""Register MDIO templates runtime.
142-
Custom templates can be created in external projects and added without modifying the MDIO library code
143-
"""
144-
# Use strongly-typed template
145-
template_name = TemplateRegistry.register(Seismic3DPostStackTimeTemplate())
146-
print(f"Registered template named {template_name}")
147-
# Use parametrized template
148-
template_name = TemplateRegistry.register(Seismic3DPostStackTemplate("Depth"))
149-
print(f"Registered template named {template_name}")
150-
template_name = TemplateRegistry.register(Seismic3DPreStackTemplate())
151-
print(f"Registered template named {template_name}")
152-
153-
print(f"Registered templates: {list_templates()}")
154-
155-
156-
# Application startup
157-
setup_standard_templates()
158-
159-
# Later in the application
160-
template = TemplateRegistry().get_template("PostStack3DDepth")
161-
dataset = template.create_dataset(name="Seismic 3d m/m/ft",
162-
sizes=[256, 512, 384])
163-
```
102+
## FAQ
164103

165-
## Error Handling
104+
- Do I need to create a TemplateRegistry instance?
105+
No. Use the global helpers: `get_template`, `list_templates`, `register_template`, and `is_template_registered`.
106+
- Are templates shared between callers or threads?
107+
No. Each `get_template()` call returns a deep-copied instance that is safe to modify independently.
166108

167-
The registry provides clear error messages:
109+
## API reference
168110

169-
```python
170-
# Template not registered
171-
try:
172-
template = get_template("nonexistent")
173-
except KeyError as e:
174-
print(f"Error: {e}") # "Template 'nonexistent' is not registered."
175-
176-
# Duplicate registration
177-
try:
178-
register_template("duplicate", template1)
179-
register_template("duplicate", template2)
180-
except ValueError as e:
181-
print(f"Error: {e}") # "Template 'duplicate' is already registered."
111+
```{eval-rst}
112+
.. automodule:: mdio.builder.template_registry
113+
:members:
182114
```

0 commit comments

Comments
 (0)