Skip to content

Commit 7a65c07

Browse files
committed
Merge remote-tracking branch 'upstream/main' into create_empty
2 parents 83b7717 + 8c40d61 commit 7a65c07

44 files changed

Lines changed: 2962 additions & 3495 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/constraints.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
bump-my-version==1.2.3
1+
bump-my-version==1.2.4
22
nox==2025.5.1

docs/requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
aiohttp==3.12.15
1+
aiohttp==3.13.0
22
autodoc-pydantic==2.2.0
33
furo==2025.9.25
44
linkify-it-py==2.0.3
@@ -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 & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,181 +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-
- PreStackCdpGathers3DTime
19-
- PreStackShotGathers3DTime
20-
- PostStack2DDepth
21-
- PostStack3DDepth
22-
- PreStackCdpGathers3DDepth
23-
- PreStackShotGathers3DDepth
24-
25-
## 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+
```
2616

27-
### Basic Usage
17+
## Quick start
2818

2919
```python
30-
from mdio.builder.template_registry import TemplateRegistry
20+
from mdio.builder.template_registry import get_template, list_templates
3121

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

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

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

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

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

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

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

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

6046
```python
61-
from mdio.builder.template_registry import (
62-
register_template,
63-
get_template,
64-
is_template_registered,
65-
list_templates
66-
)
47+
from mdio.builder.template_registry import list_templates
6748

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

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

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

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

82-
### Multiple Instantiation
63+
### Register your own template (optional)
8364

84-
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:
8566

8667
```python
87-
registry1 = TemplateRegistry()
88-
registry2 = TemplateRegistry()
89-
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
9072

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

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

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

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

104-
All operations on the registry are thread-safe:
10586

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

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

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

130-
## 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.
131101

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

164-
## 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.
165108

166-
The registry provides clear error messages:
109+
## API reference
167110

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

0 commit comments

Comments
 (0)