@@ -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
1718data 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).
337448Phase 5/6: Store paths don't match legacy external table paths.
338449Verify 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