Skip to content

Commit f3e4489

Browse files
Remove backward compatibility aliases from Codec API
- Remove AttributeType alias (use Codec directly) - Remove register_type function (codecs auto-register) - Remove deprecated type_name property (use name) - Remove list_types, get_type, is_type_registered, unregister_type aliases - Update all internal usages from type_name to name - Update tests to use new API The previous implementation was experimental; no backward compatibility is needed for the v2.0 release. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 898d0ed commit f3e4489

File tree

11 files changed

+137
-237
lines changed

11 files changed

+137
-237
lines changed

src/datajoint/__init__.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,10 @@
4545
"kill",
4646
"MatCell",
4747
"MatStruct",
48-
# New codec API
48+
# Codec API
4949
"Codec",
5050
"list_codecs",
5151
"get_codec",
52-
# Backward compatibility aliases
53-
"AttributeType",
54-
"register_type",
55-
"list_types",
5652
"errors",
5753
"migrate",
5854
"DataJointError",
@@ -67,12 +63,9 @@
6763
from . import migrate
6864
from .admin import kill
6965
from .codecs import (
70-
AttributeType,
7166
Codec,
7267
get_codec,
7368
list_codecs,
74-
list_types,
75-
register_type,
7669
)
7770
from .blob import MatCell, MatStruct
7871
from .cli import cli

src/datajoint/codecs.py

Lines changed: 0 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ class MyTable(dj.Manual):
3636
from __future__ import annotations
3737

3838
import logging
39-
import warnings
4039
from abc import ABC, abstractmethod
4140
from typing import Any
4241

@@ -179,80 +178,10 @@ def validate(self, value: Any) -> None:
179178
"""
180179
pass
181180

182-
# =========================================================================
183-
# Backward compatibility properties
184-
# =========================================================================
185-
186-
@property
187-
def type_name(self) -> str | None:
188-
"""Backward compatibility alias for `name`."""
189-
return self.name
190-
191-
@property
192-
def dtype(self) -> str:
193-
"""
194-
Backward compatibility property.
195-
196-
Deprecated: Use get_dtype(is_external) instead.
197-
"""
198-
warnings.warn(
199-
"Codec.dtype property is deprecated. Use get_dtype(is_external) instead.",
200-
DeprecationWarning,
201-
stacklevel=2,
202-
)
203-
return self.get_dtype(is_external=False)
204-
205181
def __repr__(self) -> str:
206182
return f"<{self.__class__.__name__}(name={self.name!r})>"
207183

208184

209-
# Backward compatibility alias
210-
AttributeType = Codec
211-
212-
213-
def register_type(cls: type[Codec]) -> type[Codec]:
214-
"""
215-
Register a codec with DataJoint.
216-
217-
Deprecated: Codecs now auto-register when subclassed. This function
218-
is kept for backward compatibility but is no longer needed.
219-
220-
Args:
221-
cls: A Codec subclass to register.
222-
223-
Returns:
224-
The same class, unmodified.
225-
"""
226-
warnings.warn(
227-
"@dj.register_type is deprecated. Codecs auto-register when subclassed. "
228-
"Just inherit from dj.Codec and set the 'name' class attribute.",
229-
DeprecationWarning,
230-
stacklevel=2,
231-
)
232-
233-
if not isinstance(cls, type) or not issubclass(cls, Codec):
234-
raise TypeError(f"register_type requires a Codec subclass, got {cls!r}")
235-
236-
# Check if already registered
237-
if cls.name and cls.name in _codec_registry:
238-
existing = _codec_registry[cls.name]
239-
if type(existing) is not cls:
240-
raise DataJointError(
241-
f"Codec <{cls.name}> already registered by " f"{type(existing).__module__}.{type(existing).__name__}"
242-
)
243-
return cls # Same class, idempotent
244-
245-
# Manual registration for classes that didn't auto-register
246-
if cls.name:
247-
_codec_registry[cls.name] = cls()
248-
249-
return cls
250-
251-
252-
# Backward compatibility alias
253-
codec = register_type
254-
255-
256185
def parse_type_spec(spec: str) -> tuple[str, str | None]:
257186
"""
258187
Parse a type specification into type name and optional store parameter.
@@ -299,10 +228,6 @@ def unregister_codec(name: str) -> None:
299228
del _codec_registry[name]
300229

301230

302-
# Backward compatibility alias
303-
unregister_type = unregister_codec
304-
305-
306231
def get_codec(name: str) -> Codec:
307232
"""
308233
Retrieve a registered codec by name.
@@ -338,10 +263,6 @@ def get_codec(name: str) -> Codec:
338263
)
339264

340265

341-
# Backward compatibility alias
342-
get_type = get_codec
343-
344-
345266
def list_codecs() -> list[str]:
346267
"""
347268
List all registered codec names.
@@ -353,10 +274,6 @@ def list_codecs() -> list[str]:
353274
return sorted(_codec_registry.keys())
354275

355276

356-
# Backward compatibility alias
357-
list_types = list_codecs
358-
359-
360277
def is_codec_registered(name: str) -> bool:
361278
"""
362279
Check if a codec name is registered.
@@ -374,10 +291,6 @@ def is_codec_registered(name: str) -> bool:
374291
return type_name in _codec_registry
375292

376293

377-
# Backward compatibility alias
378-
is_type_registered = is_codec_registered
379-
380-
381294
def _load_entry_points() -> None:
382295
"""
383296
Load codecs from installed packages via entry points.

src/datajoint/fetch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ def _get(connection, attr, data, squeeze, download_path):
6464
# Include store if present to get correct chain for external storage
6565
store = getattr(attr, "store", None)
6666
if store is not None:
67-
dtype_spec = f"<{attr.codec.type_name}@{store}>"
67+
dtype_spec = f"<{attr.codec.name}@{store}>"
6868
else:
69-
dtype_spec = f"<{attr.codec.type_name}>"
69+
dtype_spec = f"<{attr.codec.name}>"
7070
final_dtype, type_chain, _ = resolve_dtype(dtype_spec)
7171

7272
# First, process the final dtype (what's stored in the database)

src/datajoint/gc.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,15 @@ def _uses_content_storage(attr) -> bool:
5656
return False
5757

5858
# Check if this type uses content storage
59-
type_name = getattr(attr.codec, "type_name", "")
59+
codec_name = getattr(attr.codec, "name", "")
6060
store = getattr(attr, "store", None)
6161

6262
# <hash> always uses content storage (external only)
63-
if type_name == "hash":
63+
if codec_name == "hash":
6464
return True
6565

6666
# <blob@> and <attach@> use content storage when external (has store)
67-
if type_name in ("blob", "attach") and store is not None:
67+
if codec_name in ("blob", "attach") and store is not None:
6868
return True
6969

7070
return False
@@ -83,8 +83,8 @@ def _uses_object_storage(attr) -> bool:
8383
if not attr.codec:
8484
return False
8585

86-
type_name = getattr(attr.codec, "type_name", "")
87-
return type_name == "object"
86+
codec_name = getattr(attr.codec, "name", "")
87+
return codec_name == "object"
8888

8989

9090
def _extract_content_refs(value: Any) -> list[tuple[str, str | None]]:

src/datajoint/heading.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,11 @@
1818
class _MissingType(Codec, register=False):
1919
"""Placeholder for missing/unregistered codecs. Raises error on use."""
2020

21-
name = None # Don't auto-register
22-
2321
def __init__(self, codec_name: str):
2422
self._codec_name = codec_name
2523

2624
@property
27-
def type_name(self) -> str:
25+
def name(self) -> str:
2826
return self._codec_name
2927

3028
def get_dtype(self, is_external: bool) -> str:

src/datajoint/staged_insert.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ def _get_storage_path(self, field: str, ext: str = "") -> str:
9898
raise DataJointError(f"Attribute '{field}' not found in table heading")
9999

100100
attr = self._table.heading[field]
101-
# Check if this is an object AttributeType (has adapter with "object" in type_name)
102-
if not (attr.codec and hasattr(attr.codec, "type_name") and "object" in attr.codec.type_name):
101+
# Check if this is an object Codec (has codec with "object" as name)
102+
if not (attr.codec and attr.codec.name == "object"):
103103
raise DataJointError(f"Attribute '{field}' is not an <object> type")
104104

105105
# Extract primary key from rec

src/datajoint/table.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ def __make_placeholder(self, name, value, ignore_extra_fields=False, row=None):
758758
attr.codec.validate(value)
759759

760760
# Resolve full type chain
761-
_, type_chain, resolved_store = resolve_dtype(f"<{attr.codec.type_name}>", store_name=attr.store)
761+
_, type_chain, resolved_store = resolve_dtype(f"<{attr.codec.name}>", store_name=attr.store)
762762

763763
# Apply encoders from outermost to innermost
764764
for attr_type in type_chain:

tests/integration/test_adapted_attributes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
22
Tests for adapted/custom attribute types.
33
4-
These tests verify the AttributeType system for custom data types.
4+
These tests verify the Codec system for custom data types.
55
"""
66

77
from itertools import zip_longest
@@ -29,7 +29,7 @@ def schema_ad(
2929
schema_name,
3030
):
3131
dj.config["stores"] = {"repo-s3": dict(s3_creds, protocol="s3", location="adapted/repo", stage=str(tmpdir))}
32-
# Types are registered globally via @dj.register_type decorator in schema_adapted
32+
# Codecs are auto-registered via __init_subclass__ in schema_adapted
3333
context = {**schema_adapted.LOCALS_ADAPTED}
3434
schema = dj.schema(schema_name, context=context, connection=connection_test)
3535
schema(schema_adapted.Connectivity)

tests/integration/test_gc.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def test_returns_true_for_hash_type(self):
2424
"""Test that True is returned for <hash@> type."""
2525
attr = MagicMock()
2626
attr.codec = MagicMock()
27-
attr.codec.type_name = "hash"
27+
attr.codec.name = "hash"
2828
attr.store = "mystore"
2929

3030
assert gc._uses_content_storage(attr) is True
@@ -33,7 +33,7 @@ def test_returns_true_for_blob_external(self):
3333
"""Test that True is returned for <blob@> type (external)."""
3434
attr = MagicMock()
3535
attr.codec = MagicMock()
36-
attr.codec.type_name = "blob"
36+
attr.codec.name = "blob"
3737
attr.store = "mystore"
3838

3939
assert gc._uses_content_storage(attr) is True
@@ -42,7 +42,7 @@ def test_returns_true_for_attach_external(self):
4242
"""Test that True is returned for <attach@> type (external)."""
4343
attr = MagicMock()
4444
attr.codec = MagicMock()
45-
attr.codec.type_name = "attach"
45+
attr.codec.name = "attach"
4646
attr.store = "mystore"
4747

4848
assert gc._uses_content_storage(attr) is True
@@ -51,7 +51,7 @@ def test_returns_false_for_blob_internal(self):
5151
"""Test that False is returned for <blob> internal storage."""
5252
attr = MagicMock()
5353
attr.codec = MagicMock()
54-
attr.codec.type_name = "blob"
54+
attr.codec.name = "blob"
5555
attr.store = None
5656

5757
assert gc._uses_content_storage(attr) is False
@@ -103,15 +103,15 @@ def test_returns_true_for_object_type(self):
103103
"""Test that True is returned for <object> type."""
104104
attr = MagicMock()
105105
attr.codec = MagicMock()
106-
attr.codec.type_name = "object"
106+
attr.codec.name = "object"
107107

108108
assert gc._uses_object_storage(attr) is True
109109

110110
def test_returns_false_for_other_types(self):
111111
"""Test that False is returned for non-object types."""
112112
attr = MagicMock()
113113
attr.codec = MagicMock()
114-
attr.codec.type_name = "blob"
114+
attr.codec.name = "blob"
115115

116116
assert gc._uses_object_storage(attr) is False
117117

0 commit comments

Comments
 (0)