|
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 | | - - 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 | +``` |
26 | 16 |
|
27 | | -### Basic Usage |
| 17 | +## Quick start |
28 | 18 |
|
29 | 19 | ```python |
30 | | -from mdio.builder.template_registry import TemplateRegistry |
31 | | - |
32 | | -# Get the singleton instance |
33 | | -registry = TemplateRegistry() |
34 | | - |
35 | | -# Or use the class method |
36 | | -registry = TemplateRegistry.get_instance() |
37 | | - |
38 | | -# Register a template |
39 | | -template = MyDatasetTemplate() |
40 | | -template_name = registry.register(template) |
41 | | -print(f"Registered template named {template_name}") |
| 20 | +from mdio.builder.template_registry import get_template, list_templates |
42 | 21 |
|
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) |
| 22 | +# See what's available |
| 23 | +print(list_templates()) |
| 24 | +# e.g. ["Seismic2DPostStackTime", "Seismic3DPostStackDepth", ...] |
47 | 25 |
|
48 | | -# Check if template exists |
49 | | -if registry.is_registered("my_template"): |
50 | | - print("Template is registered") |
| 26 | +# Grab a template by name |
| 27 | +tpl = get_template("Seismic3DPostStackTime") |
51 | 28 |
|
52 | | -# List all templates |
53 | | -template_names = registry.list_all_templates() |
| 29 | +# Customize your copy (safe) |
| 30 | +tpl.add_units({"amplitude": "unitless"}) |
54 | 31 | ``` |
55 | 32 |
|
56 | | -### Global Functions |
| 33 | +## Common tasks |
57 | 34 |
|
58 | | -For convenience, you can use global functions that operate on the singleton instance: |
| 35 | +### Fetch a template you can edit |
59 | 36 |
|
60 | 37 | ```python |
61 | | -from mdio.builder.template_registry import ( |
62 | | - register_template, |
63 | | - get_template, |
64 | | - is_template_registered, |
65 | | - list_templates |
66 | | -) |
| 38 | +from mdio.builder.template_registry import get_template |
67 | 39 |
|
68 | | -# Register a template globally |
69 | | -register_template(Seismic3DTemplate()) |
70 | | - |
71 | | -# Get a template |
72 | | -template = get_template("seismic_3d") |
73 | | - |
74 | | -# Check registration |
75 | | -if is_template_registered("seismic_3d"): |
76 | | - print("Template available") |
77 | | - |
78 | | -# List all registered templates |
79 | | -templates = list_templates() |
| 40 | +tpl = get_template("Seismic2DPostStackDepth") |
| 41 | +# Use/modify tpl freely — it’s your copy |
80 | 42 | ``` |
81 | 43 |
|
82 | | -### Multiple Instantiation |
83 | | - |
84 | | -The singleton pattern ensures all instantiations return the same object: |
| 44 | +### List available templates |
85 | 45 |
|
86 | 46 | ```python |
87 | | -registry1 = TemplateRegistry() |
88 | | -registry2 = TemplateRegistry() |
89 | | -registry3 = TemplateRegistry.get_instance() |
| 47 | +from mdio.builder.template_registry import list_templates |
90 | 48 |
|
91 | | -# All variables point to the same instance |
92 | | -assert registry1 is registry2 is registry3 |
| 49 | +names = list_templates() |
| 50 | +for name in names: |
| 51 | + print(name) |
93 | 52 | ``` |
94 | 53 |
|
95 | | -## API Reference |
| 54 | +### Check if a template exists |
96 | 55 |
|
97 | | -```{eval-rst} |
98 | | -.. automodule:: mdio.builder.template_registry |
99 | | - :members: |
| 56 | +```python |
| 57 | +from mdio.builder.template_registry import is_template_registered |
| 58 | + |
| 59 | +if is_template_registered("Seismic3DPostStackTime"): |
| 60 | + ... # safe to fetch |
100 | 61 | ``` |
101 | 62 |
|
102 | | -## Thread Safety |
| 63 | +### Register your own template (optional) |
103 | 64 |
|
104 | | -All operations on the registry are thread-safe: |
| 65 | +If you have a custom template class, register an instance so others can fetch it by name: |
105 | 66 |
|
106 | 67 | ```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() |
| 68 | +from typing import Any |
| 69 | +from mdio.builder.template_registry import register_template |
| 70 | +from mdio.builder.templates.abstract_dataset_template import AbstractDatasetTemplate |
| 71 | +from mdio.builder.templates.types import SeismicDataDomain |
| 72 | + |
| 73 | +class MyTemplate(AbstractDatasetTemplate): |
| 74 | + def __init__(self, domain: SeismicDataDomain = "time"): |
| 75 | + super().__init__(domain) |
| 76 | + |
| 77 | + @property |
| 78 | + def _name(self) -> str: |
| 79 | + # The public name becomes something like "MyTemplateTime" |
| 80 | + return f"MyTemplate{self._data_domain.capitalize()}" |
| 81 | + |
| 82 | + def _load_dataset_attributes(self) -> dict[str, Any]: |
| 83 | + return {"surveyType": "2D", "gatherType": "custom"} |
| 84 | + |
| 85 | +# Make it available globally |
| 86 | +registered_name = register_template(MyTemplate("time")) |
| 87 | +print(registered_name) # "MyTemplateTime" |
121 | 88 | ``` |
122 | 89 |
|
123 | | -## Best Practices |
| 90 | +```{tip} |
| 91 | +Use `list_templates()` to discover the exact names to pass to `get_template()`. |
| 92 | +``` |
124 | 93 |
|
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 |
| 94 | +## Troubleshooting |
129 | 95 |
|
130 | | -## Example: Complete Template Management |
| 96 | +- KeyError: “Template 'XYZ' is not registered.” |
| 97 | + - The name is wrong or not registered yet. |
| 98 | + - Call `list_templates()` to see valid names, or `is_template_registered(name)` to check first. |
131 | 99 |
|
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 | | -``` |
| 100 | +## FAQ |
163 | 101 |
|
164 | | -## Error Handling |
| 102 | +- Do I need to create a TemplateRegistry instance? |
| 103 | + No. Use the global helpers: `get_template`, `list_templates`, `register_template`, and `is_template_registered`. |
| 104 | +- Are templates shared between callers or threads? |
| 105 | + No. Each `get_template()` call returns a deep-copied instance that is safe to modify independently. |
165 | 106 |
|
166 | | -The registry provides clear error messages: |
| 107 | +## API reference |
167 | 108 |
|
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." |
| 109 | +```{eval-rst} |
| 110 | +.. automodule:: mdio.builder.template_registry |
| 111 | + :members: |
181 | 112 | ``` |
0 commit comments