or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdcore-io.mdformat-registration.mdformats.mdindex.mdmesh-data.md

format-registration.mddocs/

0

# Format Registration System

1

2

System for registering custom file formats and managing format detection based on file extensions, enabling extensibility of meshio with user-defined formats.

3

4

## Capabilities

5

6

### Format Registration Functions

7

8

Core functions for managing the format registry that controls which readers and writers are available for different file extensions.

9

10

```python { .api }

11

def register_format(format_name, extensions, reader, writer_map):

12

"""

13

Register a new file format with meshio's format detection system.

14

15

Parameters:

16

- format_name: str - Unique identifier for the format

17

Used internally to reference the format and in error messages

18

Should be descriptive and unique (e.g., "custom_fem", "my_format")

19

- extensions: List[str] - List of file extensions associated with this format

20

Extensions should include the dot (e.g., [".myfmt", ".dat"])

21

Multiple extensions can map to the same format

22

Extensions are case-insensitive during detection

23

- reader: Callable | None - Function to read files of this format

24

Signature: reader(filename) -> Mesh

25

Can be None if format is write-only

26

Function should handle both file paths and file-like objects

27

- writer_map: Dict[str, Callable] - Dictionary mapping format names to writer functions

28

Key: format name (usually same as format_name parameter)

29

Value: writer function with signature writer(filename, mesh, **kwargs)

30

Can be empty dict {} if format is read-only

31

32

Side Effects:

33

- Updates extension_to_filetypes mapping for auto-detection

34

- Registers reader function in global reader_map

35

- Registers writer functions in global writer_map

36

37

Examples:

38

>>> def my_reader(filename):

39

... # Custom reading logic

40

... return meshio.Mesh(points, cells)

41

>>>

42

>>> def my_writer(filename, mesh, **kwargs):

43

... # Custom writing logic

44

... pass

45

>>>

46

>>> meshio.register_format(

47

... "my_format",

48

... [".myfmt", ".dat"],

49

... my_reader,

50

... {"my_format": my_writer}

51

... )

52

"""

53

54

def deregister_format(format_name):

55

"""

56

Remove a previously registered file format from meshio.

57

58

Parameters:

59

- format_name: str - Name of format to remove

60

Must match the format_name used in register_format()

61

62

Side Effects:

63

- Removes format from extension_to_filetypes mapping

64

- Removes reader from reader_map if present

65

- Removes writer from writer_map if present

66

- After deregistration, files with associated extensions will no longer be auto-detected

67

68

Examples:

69

>>> meshio.deregister_format("my_format")

70

>>> # Now .myfmt files will not be recognized

71

"""

72

```

73

74

### Format Detection System

75

76

Internal mappings and utilities used by meshio's automatic format detection.

77

78

```python { .api }

79

extension_to_filetypes: Dict[str, List[str]]

80

"""

81

Dictionary mapping file extensions to lists of format names.

82

83

Structure:

84

- Keys: File extensions including dot (e.g., ".vtk", ".msh", ".stl")

85

- Values: List of format names that handle this extension

86

- Multiple formats can handle the same extension

87

- Extensions are stored in lowercase for case-insensitive matching

88

89

Examples:

90

>>> print(meshio.extension_to_filetypes[".vtk"])

91

['vtk']

92

>>> print(meshio.extension_to_filetypes[".msh"])

93

['gmsh']

94

95

Note: This is primarily for internal use and format introspection.

96

Direct modification is not recommended - use register_format() instead.

97

"""

98

99

# Internal mappings (not directly exposed but used by format system)

100

reader_map: Dict[str, Callable]

101

"""Internal mapping from format names to reader functions."""

102

103

_writer_map: Dict[str, Callable]

104

"""Internal mapping from format names to writer functions."""

105

```

106

107

## Usage Examples

108

109

### Registering a Custom Format

110

111

```python

112

import meshio

113

import numpy as np

114

115

def read_simple_format(filename):

116

"""

117

Reader for a hypothetical simple format.

118

119

File format:

120

Line 1: number_of_points number_of_triangles

121

Next lines: point coordinates (x, y, z)

122

Final lines: triangle indices (i, j, k)

123

"""

124

with open(filename, 'r') as f:

125

# Read header

126

n_points, n_triangles = map(int, f.readline().split())

127

128

# Read points

129

points = []

130

for _ in range(n_points):

131

x, y, z = map(float, f.readline().split())

132

points.append([x, y, z])

133

points = np.array(points)

134

135

# Read triangles

136

triangles = []

137

for _ in range(n_triangles):

138

i, j, k = map(int, f.readline().split())

139

triangles.append([i, j, k])

140

triangles = np.array(triangles)

141

142

# Create mesh

143

cells = [("triangle", triangles)]

144

return meshio.Mesh(points, cells)

145

146

def write_simple_format(filename, mesh, **kwargs):

147

"""

148

Writer for the simple format.

149

"""

150

# Extract triangles from mesh

151

triangles = mesh.get_cells_type("triangle")

152

153

with open(filename, 'w') as f:

154

# Write header

155

f.write(f"{len(mesh.points)} {len(triangles)}\n")

156

157

# Write points

158

for point in mesh.points:

159

f.write(f"{point[0]} {point[1]} {point[2]}\n")

160

161

# Write triangles

162

for triangle in triangles:

163

f.write(f"{triangle[0]} {triangle[1]} {triangle[2]}\n")

164

165

# Register the custom format

166

meshio.register_format(

167

"simple_triangle", # Format name

168

[".tri", ".simple"], # File extensions

169

read_simple_format, # Reader function

170

{"simple_triangle": write_simple_format} # Writer function

171

)

172

173

# Now can use the format automatically

174

mesh = meshio.read("model.tri") # Auto-detects simple_triangle format

175

meshio.write("output.simple", mesh) # Auto-detects and uses custom writer

176

```

177

178

### Read-Only Format Registration

179

180

```python

181

def read_special_format(filename):

182

"""Reader for a read-only format."""

183

# ... reading logic ...

184

return meshio.Mesh(points, cells)

185

186

# Register read-only format

187

meshio.register_format(

188

"read_only_format",

189

[".readonly", ".ro"],

190

read_special_format,

191

{} # Empty writer map - format is read-only

192

)

193

194

# Usage

195

mesh = meshio.read("data.readonly") # Works

196

# meshio.write("output.readonly", mesh) # Would raise WriteError

197

```

198

199

### Write-Only Format Registration

200

201

```python

202

def write_visualization_format(filename, mesh, **kwargs):

203

"""Writer for a visualization-only format."""

204

# ... writing logic for visualization ...

205

pass

206

207

# Register write-only format

208

meshio.register_format(

209

"viz_format",

210

[".viz", ".display"],

211

None, # No reader function

212

{"viz_format": write_visualization_format}

213

)

214

215

# Usage

216

# mesh = meshio.read("file.viz") # Would raise ReadError

217

meshio.write("visualization.viz", mesh) # Works

218

```

219

220

### Multiple Extension Handling

221

222

```python

223

def read_multi_ext_format(filename):

224

"""Reader that handles multiple extensions with slight variations."""

225

# Different behavior based on extension

226

if filename.endswith('.v1'):

227

# Handle version 1 format

228

pass

229

elif filename.endswith('.v2'):

230

# Handle version 2 format

231

pass

232

return meshio.Mesh(points, cells)

233

234

def write_multi_ext_format(filename, mesh, **kwargs):

235

"""Writer that adapts to extension."""

236

if filename.endswith('.v1'):

237

# Write version 1 format

238

pass

239

elif filename.endswith('.v2'):

240

# Write version 2 format

241

pass

242

243

# Register format with multiple extensions

244

meshio.register_format(

245

"versioned_format",

246

[".v1", ".v2", ".legacy"],

247

read_multi_ext_format,

248

{"versioned_format": write_multi_ext_format}

249

)

250

```

251

252

### Format Introspection

253

254

```python

255

# Check what formats are available

256

print("Registered formats:")

257

for ext, formats in meshio.extension_to_filetypes.items():

258

print(f" {ext}: {formats}")

259

260

# Check if specific format is registered

261

def is_format_registered(format_name):

262

"""Check if a format is currently registered."""

263

from meshio._helpers import reader_map, _writer_map

264

return (format_name in reader_map or

265

format_name in _writer_map)

266

267

print("Is 'vtk' registered?", is_format_registered("vtk"))

268

print("Is 'my_format' registered?", is_format_registered("my_format"))

269

270

# Find formats for extension

271

def get_formats_for_extension(extension):

272

"""Get all formats that handle a given extension."""

273

return meshio.extension_to_filetypes.get(extension.lower(), [])

274

275

print("Formats for .msh:", get_formats_for_extension(".msh"))

276

print("Formats for .vtk:", get_formats_for_extension(".vtk"))

277

```

278

279

### Dynamic Format Loading

280

281

```python

282

import importlib

283

284

def register_plugin_format(plugin_module_name):

285

"""

286

Dynamically load and register a format from a plugin module.

287

288

The plugin module should define:

289

- FORMAT_NAME: str

290

- EXTENSIONS: List[str]

291

- read_function: Callable

292

- write_function: Callable (optional)

293

"""

294

try:

295

plugin = importlib.import_module(plugin_module_name)

296

297

# Check required attributes

298

if not hasattr(plugin, 'FORMAT_NAME'):

299

raise ValueError("Plugin must define FORMAT_NAME")

300

if not hasattr(plugin, 'EXTENSIONS'):

301

raise ValueError("Plugin must define EXTENSIONS")

302

if not hasattr(plugin, 'read_function'):

303

print(f"Warning: {plugin_module_name} has no read_function")

304

reader = None

305

else:

306

reader = plugin.read_function

307

308

# Optional writer

309

writer_map = {}

310

if hasattr(plugin, 'write_function'):

311

writer_map[plugin.FORMAT_NAME] = plugin.write_function

312

313

# Register the format

314

meshio.register_format(

315

plugin.FORMAT_NAME,

316

plugin.EXTENSIONS,

317

reader,

318

writer_map

319

)

320

print(f"Successfully registered format '{plugin.FORMAT_NAME}'")

321

322

except ImportError:

323

print(f"Could not import plugin module '{plugin_module_name}'")

324

except Exception as e:

325

print(f"Error registering plugin: {e}")

326

327

# Usage

328

# register_plugin_format("my_mesh_plugin")

329

```

330

331

### Temporary Format Registration

332

333

```python

334

from contextlib import contextmanager

335

336

@contextmanager

337

def temporary_format(format_name, extensions, reader, writer_map):

338

"""

339

Context manager for temporary format registration.

340

341

Useful for testing or temporary format overrides.

342

"""

343

# Store original state

344

original_extensions = {}

345

for ext in extensions:

346

if ext in meshio.extension_to_filetypes:

347

original_extensions[ext] = meshio.extension_to_filetypes[ext].copy()

348

349

try:

350

# Register temporary format

351

meshio.register_format(format_name, extensions, reader, writer_map)

352

yield

353

finally:

354

# Restore original state

355

meshio.deregister_format(format_name)

356

357

# Restore original extension mappings

358

for ext, original_formats in original_extensions.items():

359

meshio.extension_to_filetypes[ext] = original_formats

360

361

# Usage

362

def temp_reader(filename):

363

return meshio.Mesh(np.array([[0, 0, 0]]), [])

364

365

with temporary_format("temp_fmt", [".tmp"], temp_reader, {}):

366

# Format is available only within this block

367

mesh = meshio.read("test.tmp") # Uses temporary reader

368

369

# Outside the block, .tmp files are no longer recognized

370

```

371

372

### Format Validation

373

374

```python

375

def validate_custom_format(reader_func, writer_func=None):

376

"""

377

Validate that custom format functions have correct signatures.

378

"""

379

import inspect

380

381

# Validate reader signature

382

if reader_func is not None:

383

sig = inspect.signature(reader_func)

384

if len(sig.parameters) < 1:

385

raise ValueError("Reader function must accept at least one parameter (filename)")

386

387

# Validate writer signature

388

if writer_func is not None:

389

sig = inspect.signature(writer_func)

390

if len(sig.parameters) < 2:

391

raise ValueError("Writer function must accept at least two parameters (filename, mesh)")

392

393

return True

394

395

# Example validation before registration

396

def my_reader(filename):

397

return meshio.Mesh(np.array([[0, 0, 0]]), [])

398

399

def my_writer(filename, mesh, **kwargs):

400

pass

401

402

# Validate before registering

403

if validate_custom_format(my_reader, my_writer):

404

meshio.register_format("validated_format", [".val"], my_reader, {"validated_format": my_writer})

405

```

406

407

## Error Handling

408

409

### Common Registration Errors

410

411

```python

412

# Handle registration errors gracefully

413

try:

414

meshio.register_format(

415

"problematic_format",

416

[".bad"],

417

lambda x: None, # Bad reader - doesn't return Mesh

418

{"problematic_format": lambda x, y: None}

419

)

420

except Exception as e:

421

print(f"Registration failed: {e}")

422

423

# Check for conflicts

424

def register_format_safely(format_name, extensions, reader, writer_map):

425

"""Register format with conflict detection."""

426

# Check for extension conflicts

427

conflicts = []

428

for ext in extensions:

429

if ext in meshio.extension_to_filetypes:

430

existing = meshio.extension_to_filetypes[ext]

431

conflicts.extend(existing)

432

433

if conflicts:

434

print(f"Warning: Extensions {extensions} conflict with formats: {conflicts}")

435

response = input("Continue? (y/n): ")

436

if response.lower() != 'y':

437

return False

438

439

# Register format

440

meshio.register_format(format_name, extensions, reader, writer_map)

441

return True

442

```

443

444

## Best Practices

445

446

### Format Design Guidelines

447

448

1. **Reader Functions**: Should be robust and handle various edge cases

449

2. **Writer Functions**: Should preserve as much mesh data as possible

450

3. **Extension Choice**: Use descriptive, unique extensions

451

4. **Error Messages**: Provide clear error messages for invalid files

452

5. **Documentation**: Document format specifications and limitations

453

454

### Performance Considerations

455

456

```python

457

# Efficient readers for large files

458

def efficient_reader(filename):

459

"""Reader optimized for large files."""

460

# Use memory mapping for large files

461

if os.path.getsize(filename) > 100_000_000: # 100MB

462

# Use memory-mapped reading

463

pass

464

else:

465

# Standard reading

466

pass

467

return mesh

468

469

# Lazy loading for complex formats

470

def lazy_reader(filename):

471

"""Reader that supports lazy loading of data."""

472

# Read only metadata first, load data on demand

473

return mesh

474

```

475

476

The format registration system provides a flexible way to extend meshio with custom file formats while maintaining compatibility with the existing I/O system and automatic format detection.