Skip to content

Commit 1a3a0e6

Browse files
docs: Add Phase 7 (AdaptedTypes → Codecs) to migration guides
- Add Phase 7 to how-to/migrate-from-0x.md: - AttributeAdapter to Codec conversion examples - Key differences table (put/get → encode/decode) - Migration steps and troubleshooting - Add Step 6 to reference/specs/migration-2.0.md: - Detailed spec for adapter-to-codec migration - Type mapping table for get_dtype() - New capabilities in Codec system - AI prompt for Phase 7: AdaptedTypes Migration - Rollback instructions for Step 6 - Updated post-migration checklist Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 36bea6e commit 1a3a0e6

2 files changed

Lines changed: 417 additions & 21 deletions

File tree

src/how-to/migrate-from-0x.md

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Upgrade existing pipelines from DataJoint 0.x to DataJoint 2.0.
1212
| 4. Blob/Attach (Internal) | Internal blob columns | Column comments | 100% |
1313
| 5. External Blob/Attach | External storage columns | FK → JSON | Yes |
1414
| 6. Filepath | Filepath columns | FK → JSON | Yes |
15+
| 7. AdaptedTypes | Custom AttributeAdapter classes | Code + column comments | 100% |
1516

1617
**Phases 1-4** are trivial. Phases 3-4 only modify column comments—the actual
1718
data and column types are unchanged. You can return to DataJoint 0.x at any
@@ -289,11 +290,112 @@ migrate_filepath(schema) # Apply
289290

290291
---
291292

293+
## Phase 7: AdaptedTypes to Codecs
294+
295+
Migrate custom `AttributeAdapter` classes to user-defined codecs.
296+
297+
**This phase requires updating Python code and column comments.**
298+
299+
### Background
300+
301+
DataJoint 0.x used `dj.AttributeAdapter` subclasses to define custom attribute
302+
types. In 2.0, this is replaced by the more powerful `dj.Codec` system.
303+
304+
### Definition Changes
305+
306+
```python
307+
# 0.x — AttributeAdapter
308+
@schema
309+
class MyAdapter(dj.AttributeAdapter):
310+
attribute_type = 'filepath@store' # underlying type
311+
312+
def put(self, filepath):
313+
# transform on insert
314+
return filepath
315+
316+
def get(self, filepath):
317+
# transform on fetch
318+
return pathlib.Path(filepath)
319+
320+
# Usage in 0.x
321+
my_adapter = MyAdapter()
322+
schema.spawn_missing_classes(context={..., 'adapted': my_adapter})
323+
324+
@schema
325+
class MyTable(dj.Manual):
326+
definition = '''
327+
id : int
328+
---
329+
path : <adapted>
330+
'''
331+
332+
# 2.0 — Codec
333+
class PathCodec(dj.Codec):
334+
name = "path"
335+
336+
def get_dtype(self, is_external: bool) -> str:
337+
return "<filepath>" # underlying storage
338+
339+
def encode(self, value, *, key=None, store_name=None):
340+
return str(value)
341+
342+
def decode(self, stored, *, key=None):
343+
return pathlib.Path(stored)
344+
345+
# Usage in 2.0 — codec auto-registers when class is defined
346+
@schema
347+
class MyTable(dj.Manual):
348+
definition = '''
349+
id : int32
350+
---
351+
path : <path@store>
352+
'''
353+
```
354+
355+
### Key Differences
356+
357+
| 0.x AttributeAdapter | 2.0 Codec |
358+
|---------------------|-----------|
359+
| `attribute_type` property | `get_dtype(is_external)` method |
360+
| `put()` method | `encode()` method |
361+
| `get()` method | `decode()` method |
362+
| Manual registration via context | Auto-registration on class definition |
363+
| Instance-based | Class-based with singleton instance |
364+
365+
### Migration Steps
366+
367+
1. **Identify all AttributeAdapter subclasses** in your codebase
368+
369+
2. **Convert each to a Codec class**:
370+
- Rename `put()``encode()`
371+
- Rename `get()``decode()`
372+
- Replace `attribute_type` with `get_dtype()` method
373+
- Add `name` class attribute
374+
375+
3. **Update table definitions**:
376+
- Replace adapter references with codec names
377+
- Update column comments if needed
378+
379+
4. **Remove adapter registration** from `spawn_missing_classes()` calls
380+
381+
### Apply
382+
383+
```python
384+
from datajoint.migrate import migrate_adapted_types
385+
386+
migrate_adapted_types(schema, dry_run=True) # Preview
387+
migrate_adapted_types(schema) # Apply
388+
```
389+
390+
**Safe:** Only modifies column comments. Data unchanged. Requires code changes.
391+
392+
---
393+
292394
## Quick Reference
293395

294-
### Safe Phases (1-4)
396+
### Safe Phases (1-4, 7)
295397

296-
Phases 3-4 only modify column comments. Return to 0.x anytime.
398+
Phases 3-4 and 7 only modify column comments. Return to 0.x anytime.
297399

298400
| 0.x | 2.0 |
299401
|-----|-----|
@@ -320,6 +422,15 @@ Convert FK references to JSON. Verify path compatibility first.
320422
| `.fetch('KEY')` | `.keys()` |
321423
| `.fetch(as_dict=True)` | `.to_dicts()` |
322424

425+
### AdaptedTypes (Phase 7)
426+
427+
| 0.x | 2.0 |
428+
|-----|-----|
429+
| `dj.AttributeAdapter` | `dj.Codec` |
430+
| `put()` method | `encode()` method |
431+
| `get()` method | `decode()` method |
432+
| `attribute_type` | `get_dtype()` method |
433+
323434
---
324435

325436
## Troubleshooting
@@ -337,10 +448,21 @@ Run Phase 4 (blob/attach).
337448
Phase 5/6: Store paths don't match legacy external table paths.
338449
Verify configuration with `verify_external_paths()`.
339450

451+
### "Unknown codec" after Phase 7
452+
453+
Ensure your new Codec class is imported before table definitions.
454+
Codecs auto-register when the class is defined.
455+
456+
### AttributeAdapter still referenced
457+
458+
Remove old adapter instances from `spawn_missing_classes()` context dicts.
459+
Update table definitions to use new codec names.
460+
340461
---
341462

342463
## See Also
343464

344465
- [What's New in 2.0](../explanation/whats-new-2.md)
345466
- [Type System](../explanation/type-system.md)
467+
- [Codec API](../reference/specs/codec-api.md)
346468
- [Configure Storage](configure-storage.md)

0 commit comments

Comments
 (0)