|
1 | 1 | # Template Registry |
2 | 2 |
|
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. |
4 | 4 |
|
5 | | -## Overview |
| 5 | +## Why use it |
6 | 6 |
|
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 |
8 | 11 |
|
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 | +``` |
27 | 16 |
|
28 | | -### Basic Usage |
| 17 | +## Quick start |
29 | 18 |
|
30 | 19 | ```python |
31 | | -from mdio.builder.template_registry import TemplateRegistry |
| 20 | +from mdio.builder.template_registry import get_template, list_templates |
32 | 21 |
|
33 | | -# Get the singleton instance |
34 | | -registry = TemplateRegistry() |
| 22 | +# See what's available |
| 23 | +print(list_templates()) |
| 24 | +# e.g. ["Seismic2DPostStackTime", "Seismic3DPostStackDepth", ...] |
35 | 25 |
|
36 | | -# Or use the class method |
37 | | -registry = TemplateRegistry.get_instance() |
| 26 | +# Grab a template by name |
| 27 | +template = get_template("Seismic3DPostStackTime") |
38 | 28 |
|
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 | +``` |
43 | 32 |
|
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 |
48 | 34 |
|
49 | | -# Check if template exists |
50 | | -if registry.is_registered("my_template"): |
51 | | - print("Template is registered") |
| 35 | +### Fetch a template you can edit |
52 | 36 |
|
53 | | -# List all templates |
54 | | -template_names = registry.list_all_templates() |
55 | | -``` |
| 37 | +```python |
| 38 | +from mdio.builder.template_registry import get_template |
56 | 39 |
|
57 | | -### Global Functions |
| 40 | +template = get_template("Seismic2DPostStackDepth") |
| 41 | +# Use/modify template freely — it’s your copy |
| 42 | +``` |
58 | 43 |
|
59 | | -For convenience, you can use global functions that operate on the singleton instance: |
| 44 | +### List available templates |
60 | 45 |
|
61 | 46 | ```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 |
68 | 48 |
|
69 | | -# Register a template globally |
70 | | -register_template(Seismic3DTemplate()) |
| 49 | +names = list_templates() |
| 50 | +for name in names: |
| 51 | + print(name) |
| 52 | +``` |
71 | 53 |
|
72 | | -# Get a template |
73 | | -template = get_template("seismic_3d") |
| 54 | +### Check if a template exists |
74 | 55 |
|
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 |
78 | 58 |
|
79 | | -# List all registered templates |
80 | | -templates = list_templates() |
| 59 | +if is_template_registered("Seismic3DPostStackTime"): |
| 60 | + ... # safe to fetch |
81 | 61 | ``` |
82 | 62 |
|
83 | | -### Multiple Instantiation |
| 63 | +### Register your own template (optional) |
84 | 64 |
|
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: |
86 | 66 |
|
87 | 67 | ```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 |
91 | 72 |
|
92 | | -# All variables point to the same instance |
93 | | -assert registry1 is registry2 is registry3 |
94 | | -``` |
95 | 73 |
|
96 | | -## API Reference |
| 74 | +class MyTemplate(AbstractDatasetTemplate): |
| 75 | + def __init__(self, domain: SeismicDataDomain = "time"): |
| 76 | + super().__init__(domain) |
97 | 77 |
|
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()}" |
102 | 82 |
|
103 | | -## Thread Safety |
| 83 | + def _load_dataset_attributes(self) -> dict[str, Any]: |
| 84 | + return {"surveyType": "2D", "gatherType": "custom"} |
104 | 85 |
|
105 | | -All operations on the registry are thread-safe: |
106 | 86 |
|
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" |
122 | 90 | ``` |
123 | 91 |
|
124 | | -## Best Practices |
| 92 | +```{tip} |
| 93 | +Use `list_templates()` to discover the exact names to pass to `get_template()`. |
| 94 | +``` |
125 | 95 |
|
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 |
130 | 97 |
|
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. |
132 | 101 |
|
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 |
164 | 103 |
|
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. |
166 | 108 |
|
167 | | -The registry provides clear error messages: |
| 109 | +## API reference |
168 | 110 |
|
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: |
182 | 114 | ``` |
0 commit comments