Skip to content

Commit bd54d7f

Browse files
committed
✨ feat(converters): make dataclass and field public
1 parent 7fb9f2f commit bd54d7f

File tree

4 files changed

+45
-15
lines changed

4 files changed

+45
-15
lines changed

src/dataclassish/_src/converters.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def __call__(self, value: ArgT | PassThroughTs, /) -> RetT | PassThroughTs:
164164
#####################################################################
165165
# Minimal implementation of a dataclass supporting converters.
166166

167-
_CT = TypeVar("_CT")
167+
_CT = TypeVar("_CT") # class type
168168

169169

170170
# TODO: how to express default_factory is mutually exclusive with default?
@@ -228,7 +228,25 @@ class DataclassInstance(Protocol):
228228
__dataclass_fields__: ClassVar[dict[str, dataclasses.Field[Any]]]
229229

230230

231-
def _process_dataclass(cls: type[_CT], **kwargs: Any) -> type[_CT]:
231+
def process_dataclass(cls: type[_CT], **kwargs: Any) -> type[_CT]:
232+
"""Process a class into a dataclass with converters.
233+
234+
Parameters
235+
----------
236+
cls : type
237+
The class to transform into a dataclass.
238+
**kwargs : Any
239+
Additional keyword arguments to pass to `dataclasses.dataclass`.
240+
241+
Returns
242+
-------
243+
type[DataclassInstance]
244+
The dataclass, it's a transformed version of the input class `cls`. This
245+
also adds the argument ``_skip_convert`` to the `__init__` method, which
246+
allows for skipping the conversion of fields. This provides a fast path
247+
for when the input values are already converted.
248+
249+
"""
232250
# Make the dataclass from the class.
233251
# This does all the usual dataclass stuff.
234252
dcls: type[_CT] = dataclasses.dataclass(cls, **kwargs)
@@ -292,8 +310,8 @@ def dataclass(
292310
Parameters
293311
----------
294312
cls : type | None, optional
295-
The class to transform into a dataclass. If `None`, returns a partial
296-
function that can be used as a decorator.
313+
The class to transform into a dataclass. If `None`, `dataclass` returns
314+
a partial function that can be used as a decorator.
297315
**kwargs : Any
298316
Additional keyword arguments to pass to `dataclasses.dataclass`.
299317
@@ -327,5 +345,5 @@ def dataclass(
327345
328346
"""
329347
if cls is None:
330-
return functools.partial(_process_dataclass, **kwargs)
331-
return _process_dataclass(cls, **kwargs)
348+
return functools.partial(process_dataclass, **kwargs)
349+
return process_dataclass(cls, **kwargs)

src/dataclassish/converters.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,26 @@
55
includes: ``attrs`` and ``equinox``. This module provides a few useful converter
66
functions. If you need more, check out ``attrs``!
77
8+
We also provide a lightweight dataclass-like decorator and field function that
9+
supports these converters and converters in general.
10+
11+
>>> from dataclassish.converters import field, dataclass, Optional
12+
13+
>>> @dataclass
14+
... class MyClass:
15+
... a: int | None = field(converter=Optional(int))
16+
... b: str = field(converter=str.upper)
17+
18+
>>> obj = MyClass(a="1", b="hello")
19+
>>> obj
20+
MyClass(a=1, b='HELLO')
21+
22+
>>> obj = MyClass(a=None, b="there")
23+
>>> obj
24+
MyClass(a=None, b='THERE')
25+
826
"""
927

10-
__all__ = ["AbstractConverter", "Optional", "Unless"]
28+
__all__ = ["AbstractConverter", "Optional", "Unless", "field", "dataclass"]
1129

12-
from ._src.converters import AbstractConverter, Optional, Unless
13-
# TODO: make dataclass & field public
30+
from ._src.converters import AbstractConverter, Optional, Unless, dataclass, field

tests/test_converters.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,6 @@ def test_unless_object():
3737
assert converter("1.0") == 1.0
3838

3939

40-
def test_field_not_public():
41-
"""Test `field` is not public."""
42-
assert not hasattr(dataclassish.converters, "field")
43-
44-
4540
def test_field():
4641
"""Test `field`."""
4742
converter = dataclassish.converters.Optional(int)

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)